VPN サイドカーのためのキルスイッチ: 終了時にトラフィックを遮断する
VPN コンテナの名前空間を共有しても、トンネルが落ちたときにアプリは止まりません。明示的な出力ポリシーを追加し、切断だけでなく再起動も試してください。
VPN コンテナのネットワーク名前空間を共有するアプリケーションコンテナには独自のインターフェースがないため、トンネルが落ちたときには何も送れないと考えるのは自然です。その前提は、本当に重要な障害モードでは誤りです。VPN プロセスが死んでも名前空間が残っていれば、アプリはソケットを保持し、名前空間はルートを保持したまま、まだインストールされている経路で通信が続きます。本物のキルスイッチは明示的なフィルタリングポリシーとランタイムのライフサイクルのテストであり、起動時の依存関係ではありません。
名前空間の共有がキルスイッチではない理由
名前空間を共有するとは、アプリが VPN コンテナのインターフェース、アドレス、ルーティングテーブルを使うということです。共有された名前空間が無傷である限りアプリの独立したネットワーク経路を取り除きますが、トンネルが消えたときにその名前空間が何をするかについては何も語りません。
Compose の依存条件は、依存先が正常になるまでアプリの起動を遅らせることができますが、それは一瞬の時点を覆うだけで、その後の障害は覆いません。したがってこれは 起動順序のための道具であり、継続的な出力ファイアウォールではありません。
コンテナが終了したときに実際に何が起きるか
三つの出来事を区別してください。コンテナ内の VPN プロセスは、コンテナが動き続けたまま死ぬことがあります。コンテナが停止または削除されれば、名前空間は破棄されます。コンテナが作り直されれば、新しい名前空間と新しいルールが構築されます。
一つ目の場合、名前空間は残り、デフォルトルートは物理インターフェースを指したままかもしれず、アプリは直接送信を続けます。二つ目の場合、依存するアプリは通常、名前空間が消えたために接続を完全に失います。三つ目の場合、アプリはトンネルの準備ができる前に新しい名前空間へ再接続するかもしれません。どの場合も別のテストが必要であり、整った切断だけを覆う設計は最も面白くない場合を覆っています。
明示的な出力ポリシーを組み立てる
ポリシーは共有名前空間の内側に書き、アプリのパケットに適用させます。形は既定の破棄に狭い例外を添えたもので、例外は loopback、トンネルのインターフェース、そしてトンネルの転送が必要とする特定のエンドポイントのアドレスとポートです。
エンドポイントの例外はトンネルが上がる前に用意しなければならず、さもないと VPN クライアントは自分のサーバーに届きません。ルール集合が物理インターフェースを一般的に許可するのではなく、外側の転送を明示的に許可しているのはそのためです。名前空間に IPv6 の接続性があるなら、IPv4 だけのポリシーがもう一方のアドレス体系を開いたままにするため、IPv6 のルールも加えてください。
DNS もポリシーの一部です。アプリがトンネルの内側でしか到達できないリゾルバで名前を解決するなら、トンネルが落ちているとき破棄ルールは解決を壊しますが、それがキルスイッチとして正しい挙動です。それが望みどおりなのか意識して決めてください。
ライフサイクルを試す。切断だけではない
トンネルが健全なうちに新しい無害なリクエストを送り、そのあと VPN プロセスを殺して、もう一度送ります。コンテナの停止後、再起動後、作り直しの後にも繰り返します。新しいリクエストが重要なのは、既存の接続が新しい接続を止めるルール変更を生き延びることがあるからです。
ブロックの仕組みとしてヘルスチェックや出口 IP の照会に頼ってはいけません。チェックは状態を観測して報告し、ポリシーは通信を制御します。両者は同じ配備に属し、互いの代わりにはなりません。
更新のあともテストが使えるようにルールを記録する
故障の各ケースについて期待される結果を、それを実装するルールとともに配備の文書に書きます。その記録があれば、名前空間の振る舞いやデフォルトルートが誰かが compose ファイルを編集しなくても変わりうるため、イメージ更新やランタイム更新のあとにも同じテストを実行できます。
VPN エンドポイントに必要な外側の経路を、制限のないアプリの出力から切り離して保ち、DNS と IPv6 を想定した範囲の内側に保ってください。ポリシーが便宜のために物理インターフェース全体を許すなら、キルスイッチはありません。Docker のネットワーク文書は、ポリシーが依拠する共有名前空間の取り決めを説明しており、ランタイムの振る舞いに疑いがあるときはそれが参照すべき資料です。