要約

  • 設定の受理、使用中の設定、プロキシによる認証と転送許可、遠隔アプリケーションの利用成功は、異なる判断である。変更を完了とするには、適用状態と通信結果を同じ試行に結び付けなければならない。設定の意図と適用の区別はRFC 8342、プロキシ接続の段階的な手順はRFC 1928に根拠がある。
  • TCPのkeepaliveが確認する対象は、そのTCP接続の相手である。通常のSOCKS中継でクライアントがプロキシから応答を得ても、その先のアプリケーション処理は確認できない。接続の生存と要求の完了を分け、結果を観測できなかった試行を「成功」にも「未実行」にも置き換えないことが重要になる。RFC 9293

受理されたのは、まず管理操作である

ietf-tcp-clientを利用した設定の書き込みが成功しても、その応答は、遠隔アプリケーションに要求を届けたという報告ではない。最初に確かめるべきなのは、何を対象に、どの操作が成功したかである。

例えばNETCONFでは、<edit-config>は指定された設定データストアを編集する操作であり、その要求を満たせた場合に<ok>を返す。編集対象が<candidate>なら、そこへの変更と、<commit>によって<running>に反映することは別の操作になる。成功応答を読むときは、その意味を実行した操作の範囲にとどめなければならない。RFC 6241

さらに、稼働用の設定を更新したことと、その値が実際に使われていることも区別する必要がある。NMDAでは、<running>に変換前の設定が含まれる場合があり、<intended>は変換後にシステムが適用しようとする設定を表す。<operational>が扱うのは、適用済みの設定とシステム状態である。適用済みの値には、意図した設定以外に、システムが生成した値や既定値なども関係する。RFC 8342

したがって、単純に二つのデータストア全体が同一かを比較するのではなく、対象となる設定が、どの由来の値として使用中なのかを照合する方が適切である。観測可能な適用状態を確認できたとしても、それで分かるのは装置内の設定についての事実までだ。外部サービスの応答は、別の観測を必要とする。

三つのグルーピングが提供するもの、提供しないもの

RFC 9643は、TCPの設定を三つのモジュールに分けている。ietf-tcp-commonのtcp-common-groupingは共通のkeepalive設定、ietf-tcp-clientのtcp-client-groupingは接続先やローカルバインド、プロキシ設定、ietf-tcp-serverのtcp-server-groupingは待ち受け側のバインドと共通設定を扱う。同RFC自体は、接続試験結果を返す操作や、アプリケーションの正常性を報告する状態項目を定義していない。

ここでいうグルーピングは、設定項目を再利用するための定義である。YANGでは、groupingを定義しただけではスキーマツリーにノードは作られず、利用側がusesで取り込む。従って、モジュールを認識できること、利用側のモデルに設定を組み込めること、実際のサービスが動作していることは、それぞれ別の確認事項になる。RFC 7950

この境界は、標準化の不足を意味しない。接続設定の共通化と、サービス結果の検証は目的が異なる。共通の設定形式があれば、運用者は異なる実装に対して同じ意図を記述しやすくなる。しかし、その意図が実現されたという判断まで、設定形式に肩代わりさせることはできない。

また、RFC 9643が独自の状態項目を定義しないことと、適用済みの設定をNMDAで観測できないことは同義ではない。問題は「状態が一切ない」ことではなく、設定の使用状況だけではアプリケーションの利用結果を埋められないことである。

同じ名前のアドレスが、別の相手を指す

クライアント設定の外側にあるremote-addressと、proxy-server内のremote-addressは、同じ対象を指さない。前者は目的の接続先、後者はプロキシのアドレスである。プロキシ利用自体が任意で、SOCKS4、SOCKS4a、SOCKS5は、それぞれ実装の対応機能に依存する選択肢になっている。RFC 9643

運用画面でこれらを単に「接続先」と表示すると、プロキシに届いた記録が、その先のサービスに届いた記録に見えてしまう。記録上は、選択したプロキシ、要求した宛先、対応するポートを分ける必要がある。方式名だけを残し、どの代理サーバーに何を要求したかを失う設計では、後から経路の妥当性を評価できない。

宛先の表現も重要である。SOCKS5の要求では、ATYPによってIPv4アドレス、ドメイン名、IPv6アドレスを区別する。設定にサービス名が書かれていることと、その試行でプロキシにドメイン名を渡したことは、同じ記録ではない。RFC 1928

ここから導かれる運用上の要件は、設定文字列を実測値の代わりにしないことである。名前をどこで解決し、どのアドレスを要求に使用し、代理側がどこへ接続したかは、取得可能な記録の範囲で照合する。代理側でしか確認できない値があるなら、クライアントの設定から補完せず、未確認の部分として残すべきだ。

SOCKS4、SOCKS4a、SOCKS5を選択できるという設定上の共通性も、三方式の通信手順や認証が同一であることを意味しない。以下の方式交渉と転送応答の検討は、SOCKS5を対象とする。

認証方式の設定は、認証の実行ではない

SOCKS5用のauthentication-parametersは任意のコンテナで、設定する場合は対応する認証方式を選ぶ。RFC 9643が示す選択肢はGSS-APIとユーザー名・パスワードであり、GSS-APIのコンテナは具体的な設定を追加できる空の拡張点になっている。RFC 9643

つまり、方式の名前を保存できても、必要な資格情報が実行時に利用できるとは限らない。逆に、認証設定のコンテナがないことだけから、実際の通信で「認証不要」が合意されたと読み替えることもできない。設定の有無と、通信上の選択結果は分けて扱う必要がある。

SOCKS5では、クライアントがプロキシへのTCP接続を開いた後に方式候補を提示し、プロキシが方式を選ぶ。必要な副交渉を終えてから転送要求へ進む。受け入れ可能な方式がないことを示す選択結果なら、クライアントは接続を閉じなければならない。RFC 1928

ユーザー名・パスワード方式では、資格情報の検証に対して独立した成功・失敗の応答がある。この副交渉自体はパスワードを平文で運ぶため、設定を安全に保管したことと、プロキシへの認証通信を保護したことは別の問題になる。RFC 1929

設定側では、SOCKS用のパスワードに使われるpassword-groupingが、遠隔システムへの認証に必要な値を平文または暗号化された形で表現する。この区別を定義しているのがRFC 9640である。暗号化された設定値が存在するだけでは、必要な時点にその値を利用できることも、送信時の機密性も確定しない。

従って、保管時の保護、管理接続の保護、プロキシへの認証通信、宛先との暗号化通信を、一つの「暗号化済み」という評価にまとめてはいけない。宛先とのTLS接続が後から成立しても、それ以前に別の相手へ送った資格情報を遡って保護することはできない。

GSS-API方式にも別の確認がある。セキュリティコンテキストの確立に加え、メッセージの完全性や機密性に関する保護水準を交渉する手順があるため、方式名だけでは実際に得られた保護を説明できない。RFC 1961 運用記録で必要なのは、秘密そのものではなく、交渉の結果と、採用された保護が組織の方針を満たしたかという判定である。

転送の許可とTCPの確立にも境界がある

認証を終えても、要求した宛先への接続が許可されるとは限らない。SOCKS5のCONNECT応答は、成功、規則による拒否、接続拒否などを区別する。成功応答は、プロキシが要求された接続の成功を報告した証拠になるが、遠隔アプリケーションの処理結果ではない。RFC 1928

この違いは、責任の所在を変える。資格情報の検証で止まった場合と、その後の転送規則で拒否された場合では、確認すべき管理者も方針も異なる。「プロキシ認証成功」という一項目にまとめれば、後者の拒否が見えなくなる。

応答内のアドレスにも注意がいる。CONNECTに対するBND.ADDRとBND.PORTは、プロキシが宛先への接続に使用する側のアドレスとポートを示す。宛先サーバー自身のアドレスを返したものではないため、これを名前解決後の宛先として保存してはいけない。RFC 1928

通常のSOCKS中継では、クライアントからプロキシまでのTCP接続と、プロキシから宛先までのTCP接続を区別する必要がある。TCPが提供するのは、接続相手との信頼性のある順序付きバイト列の転送であって、業務操作が確定したという応答ではない。RFC 9293

そのため、クライアント側から見えた事実と、プロキシから報告された事実を区別して記録することが望ましい。報告された成功を無意味と扱う必要はないが、その報告に含まれないサービスの状態まで推定してはならない。

暗号化された接続でも、誰と通信したかを問う

プロキシを通過した先でSSHやTLSを使うなら、次の課題は目的の相手を認証することである。プロキシへのログインと、遠隔サーバーの識別は別の関係だ。設定モデルでも、SSH側のserver-authenticationはRFC 9644、TLS側のserver-authenticationはRFC 9645で扱われ、TCPの接続設定とは分離されている。

SSHでは、相手からバージョン文字列を受け取ることと、期待したホスト鍵に基づいて相手を検証することを分けなければならない。RFC 4253の鍵交換手順は、ホスト鍵の確認と署名の検証を含む。ホスト鍵を確認せずに受け入れれば、能動的な攻撃に対する安全性を失うことも明記されている。RFC 4253

証明書を用いるTLS 1.3でも、証明書を受け取っただけでは足りない。CertificateVerifyは対応する秘密鍵の所持を示し、Finishedはハンドシェイクと計算された鍵に関する検証を担う。これらに加えて、証明書の検証と、その証明書が利用しようとするサービスに対応するかという判断が必要になる。RFC 8446

サービスの識別では、クライアントは相手が提示した識別子とは独立に、受け入れる識別子を構成しなければならない。接続できた相手の証明書を見てから、その名前を「期待していた名前」に採用するのでは、検証の方向が逆になる。RFC 9525

ここから得られる運用上の結論は、接続に使用したIPアドレス、認証されたサービスの識別子、実際に処理を担う構成要素を一つにまとめないことである。例えば、承認されたTLS終端を設ける構成を考えるなら、その終端の認証成功だけで、背後の全処理が正常だとは判断できない。どこまでを通信相手として検証し、どこから先をアプリケーションの結果で確かめるのかを明示する必要がある。

到達性を、具体的な操作の結果に結び付ける

相手を正しく識別できても、利用者に必要な操作が許可され、期待した結果を返すとは限らない。「何か応答した」を成功条件にすると、この最後の違いが消える。

具体例として、遠隔アプリケーションがNETCONFサーバーである場合を考えられる。<get-config>による読み出しでは、要求したデータストアとフィルターに対し、対応する<rpc-reply>の内容を確認することになる。要求と応答の対応付けにはmessage-idが使われる。この読み出し結果は、単なるTCP確立よりも具体的なアプリケーション操作の証拠になる。RFC 6241

ただし、成功の範囲はその要求に限られる。NACMでは、読み取り権限のないデータが応答から通知なく省かれる場合があるため、応答に項目がないことを、対象の設定が存在しないことと同一視してはいけない。RFC 8341

この例から導ける受け入れ条件は、操作、実行主体、対象、期待する内容、許容する応答時間を先に定義することである。読み出しができたという結果を、変更操作も実行できるという評価に広げない。監視用の主体が成功したという結果を、権限の異なる利用者にも広げない。

逆方向の取り違えもある。アプリケーション要求が成功したとしても、その成功だけでは、指定したプロキシ経路を使用した証明にはならない。経路の遵守が要件なら、同じ試行について経路の記録も照合する必要がある。「利用できた」と「認められた経路で利用できた」は、異なる受け入れ条件である。

一回の確認が示せるのは、その時点、その設定、その経路、その主体、その操作についての結果までだ。後から取得した設定と以前の通信結果を組み合わせるだけでは、当時の適用状態を確認したことにならない。サービス到達性は、設定オブジェクトに付ける恒久的な印ではなく、条件を明示した試行の結果として報告すべきである。

keepaliveが答えるのは、どの区間の質問か

TCPのkeepaliveは、アイドル状態の接続相手から応答を引き出す仕組みである。実装する場合でも既定では無効でなければならず、特定の一回のプローブに応答がなかったという理由だけで、接続が死んだと解釈してはならない。RFC 9293

通常のSOCKS接続で、クライアント側のkeepaliveに答えるTCP相手はプロキシである。その応答から、プロキシより先の接続や、宛先アプリケーションの処理結果までは確認できない。代理側が外向き接続でもkeepaliveを実行していたとしても、それは別のTCP接続についての観測であり、業務操作の完了通知ではない。

RFC 9643は、アプリケーションに生存確認が必要なら、そのアプリケーションに意味のあるプロトコル層で行うことを推奨している。RFC 9643 ここから導かれる判断は、keepaliveを不要とすることではなく、目的を限定することである。接続資源の整理に使う検出と、必要な要求が期限内に完了するかという監視を、同じ指標にしてはいけない。