OpenConnect はログインクッキーをどうトンネルに変えるのか
OpenConnect は Web ログインのクッキーを VPN トンネルと引き換えます。クッキーはセッションの持ち運び手なので、受け渡し自体を守ってください。
OpenConnect は Web ログインと VPN トンネルという二つの別々のやり取りを、一つの短命な値でつなぎます。最初のやり取りは普通の HTTPS で、資格情報、SAML の往復、またはトークンがゲートウェイへ送られ、応答が認証クッキーを運びます。二つ目のやり取りはそのクッキーを同じゲートウェイに提示して Web 側の段階がすでに済んだ証拠とし、そのとき初めてトンネルが立ち上がります。
ログインのあいだにトンネルについて交渉されることは何もなく、ここが理解すべき点です。ほとんどのスクリプトの誤りはクッキーを保存すべきパスワードや通信を守る鍵だと決めつけますが、実際には特定のゲートウェイセッションのための持ち運び式の切符にすぎません。
クライアントとゲートウェイが順に交わすもの
認証の段階は普通の保護された Web サイトのように見えます。OpenConnect は利用者の資格情報を送るか、ゲートウェイのリダイレクトに従って ID プロバイダーへ向かい、ゲートウェイは認証クッキーを埋め込んだ文書で応答します。AnyConnect プロトコルでは、その値は続く要求のクッキーヘッダーで、たいてい webvpn のような名前で運ばれ、手引きはそれをセッションを先へ運ぶ資格情報として扱います。
二つ目の段階は、そのクッキーを添えたゲートウェイの VPN エンドポイントへの CONNECT 要求で、ゲートウェイはそれを検査してアドレスを割り当て、クライアントは TLS 上で CSTP を開始します。セッションができてからは DTLS が任意のより速いデータ経路になります。トンネルのパラメーター、経路、DNS 設定、セッションの通信鍵が確定するのはこの時点だけです。クッキーはクライアントを戸口から通しただけで、何も暗号化していません。
この順序が、openconnect --authenticate の存在理由を説明します。実行すると Web 側の段階を行い、COOKIE、HOST、CONNECT_URL、FINGERPRINT のようなシェル変数の小さなブロックを出力し、トンネルを作る前に終了します。その後ラッパースクリプトがその値で実際の接続を始められ、これがヘッドレスや二コンテナーの配備に必要な分割そのものです。
クッキーはセッションの持ち運び手であり、鍵ではない
その値を Web アプリケーションのセッション ID と同じように扱ってください。存続期間中にそれを持つ者は、そのセッションに与えられたトンネルをゲートウェイに要求できるので、秘匿性が重要です。しかし複製しても通信が明らかになるわけではなく、トンネルの機密性は TLS ハンドシェイクとそこから導かれた鍵から来ており、クッキーの文字列から来るのではありません。
これは恒久的な許可でもありません。セッションがどれだけ生きるかはゲートウェイと ID プロバイダーが決め、ログイン済みのページを表示しているブラウザーはトンネルセッションがまだ有効かどうかを何も語りません。期限切れ後の再接続は Web 側の段階を繰り返して新しいクッキーを作ることを意味し、それこそが再認証の狙いであって、工学で避けるべき面倒ではありません。
クッキーを他の資格情報の万能の代わりにせず、SAML アサーション、ブラウザーのパスワード、別のサービスが発行したクッキーは、それぞれ異なる対象を持つ別のものだと考えてください。一方を他方の欄に貼り付けると、たいていゲートウェイで失敗するか、さらに悪いことに誤った信頼境界に対して成功します。
複製を残さずにクッキーを渡す
Linux で最も安全な機械的な受け渡しは標準入力で、--cookie-on-stdin は値を stdin から読むので、クッキーがプロセスの引数一覧に現れることはありません。そこではどのローカル利用者でも ps で読めてしまいます。一つのプロセスで認証し、別のプロセスでトンネルに与えるパイプラインは、値をファイルや環境変数ではなくパイプに保ちます。
引数と環境変数はそれぞれ別の理由で弱い手段です。引数はクライアントの存続期間中ずっとプロセステーブルに見え、しばしばシェルの履歴に残ります。環境変数は子プロセスへ継承され、ユニットファイルで設定する systemd ユニットは秘密を読める設定として保存します。どうしてもファイルが必要なら、サービスアカウントに限定し、セッションの終了時に削除してください。
特権の境界も意図して保ってください。ID プロバイダーと話し、場合によってはブラウザーを開くプロセスは、そのログインを所有する利用者として動くべきです。経路、DNS、トンネルデバイスを設定するプロセスは、より多くの特権を必要とするかもしれません。root 所有のトンネルにクッキーを届けるためにブラウザー全体を root で動かすのは誤った取引で、現代の OpenConnect の設定はその境界を越えて明示的に値を渡せます。
ログも同じ疑いを向ける価値があります。詳細なクライアント出力、補助スクリプト、ゲートウェイの診断はどれも要求の材料を繰り返すことがあり、すべてのログ水準がクッキーを伏せているわけではありません。必要最小限のエラー記録だけを取り、共有の経路から遠ざけ、チケットに添える前に伏せ字にした見本を確認してください。
第二段階での検証と期限切れ
第二段階でもサーバーを検証しなければなりません。--authenticate が出力する FINGERPRINT は pin-sha256: 形式の証明書ピンで、それを --servercert でトンネルの呼び出しに渡せば、検証は認証したゲートウェイに固定されたままになります。スクリプトを簡単にするために証明書の検証を切ることは、クッキーが意図したホストへ渡っているという唯一の証拠を捨てることです。
ゲートウェイがクッキーを拒否したときの解決は、長いキャッシュではなく新しい認証の一巡です。クッキーは接続の存続期間だけ保存し、終了時に一時ファイルを削除し、セッションが露出したり端末を失ったりしたときは ID プロバイダーやゲートウェイのセッション削除の手順を使ってください。キャッシュしたクッキーは MFA の免除にはなりません。
これを自動化する前に、トンネルが正しいアカウントで動くこと、クッキーが stdin で届くこと、証明書の指紋がピン留めされていること、トンネルが閉じたらセッションを捨てることを確かめてください。どれかが欠けていれば、その自動化は手作業の流れを再現したのではなく、クッキーへの信頼を広げてしまっています。