一台のゲートウェイが自分の端末のために WireGuard を動かし、他人のネットワークへ OpenVPN クライアントを張っている。二つの内部インターフェース間の転送は機能するので、下流のサブネットはもう上流サービスの一部だと結論づけたくなる。そうではない。クライアントが取得したルートは、要求をどこへ送るかをゲートウェイに伝えるだけで、リモートネットワークが聞いたこともない端末へどうやってトラフィックを返すかは何も語らない。一本のルールを足す前に、上流が実際に支える戻り経路のモデルを選ぶこと。

ルーティングに触れる前に戻り経路のモデルを決める

この解説では、下流クライアントは 10.90.0.0/24 を使い、ゲートウェイに割り当てられた上流トンネルのアドレスは 10.80.0.6、承認済みのリモート資源は 172.20.0.30 だ。この形に合うモデルは 二つある。下流の送信元を保持して遠端側にルートしてもらうか、送信元をゲートウェイ自身のトンネルアドレスへ変換するかだ。この判断より後はすべて機械的で、判断そのものにはサービスの所有者が要る。上の 一行は遠端側とのルーティング合意であり、もう 一行は自分だけでできるローカルなポリシー変更だ。この 二つを混同することが、十分間の変更を交渉に変えてしまう。

preserved:  10.90.0.23 -> 172.20.0.30
translated: 10.80.0.6  -> 172.20.0.30

一行を選び、それに従う。行は手順ではなく選択肢であり、混ぜるとレビューで誰も説明できない設計になる。

ルートによる送信元の保持

遠端側は下流アドレスからの要求を受け取るので、そのサブネットに対するサポート済みのルートと peer の所有権、さらにそれを受け入れる許可が要る。これらはリモート側の設定であり、ローカルの Linux ルートでは作れない。プレフィックスと、それを運ぶトンネル peer を添えて、明示的に書面で求めよ。答えはサービスが拠点間接続をそもそも支えるかどうかにかかっていると想定しておく。

答えが Yes なら、ローカル設定は小さい。転送を有効にし、下流の範囲を覆う WireGuard peer の allowed-ips を設定し、双方向の通過を許すファイアウォールポリシーを置く。

意図的な送信元変換

サービスが接続中のクライアントアドレスにしかトラフィックを返さないなら、出ていく際に送信元をそのアドレスへ変換し、応答のために反転させる conntrack 状態を保つ。ルールは想定した下流の送信元、想定したリモートの宛先、上流インターフェースに限定する。すべてのインターフェースから出るすべてを変換するルールは、この要件よりはるかに大きいポリシーであり、後で驚かされる。

IPv6 には独自の設計が要る。IPv4 の masquerade 行を写すのはアーキテクチャではない。変換後の経路は、キャッシュされた接続ではなく新しい接続で試すこと。

ローカルのデータ経路も依然として機能する必要がある

変換してもローカルの作業は消えない。ゲートウェイには下流の宛先へのルート、正しい WireGuard peer の送信元所有権、有効な転送、インターフェース間の狭いファイアウォールポリシーが依然として要る。ゲートウェイ自身で作った要求はこれらの許可をどれも試さないので、ゲートウェイ上のローカル試験は通り、下流の端末は依然として失敗する。

ゲートウェイからではなく、実際の下流端末から試すこと。送信元アドレスこそがこの演習の要点だ。

一つの送信元は 一つのセッション ID を意味する

リモートサービスが見るのはゲートウェイの認証済みセッションとその変換後アドレスであり、下流端末ごとの独立した認証ではない。端末ごとの権限とアプリケーションの ID を明示し、複数の端末の代理を務めるゲートウェイがそもそも許されるのかをサービスの所有者に確認する。変換は端末ごとの登録要件を回避する手段ではない。サービスが各端末の登録を求めるなら、そのモデルを使うか、拠点間接続を交渉すること。

その確認をルールの隣に runbook として書き残す。次のレビュー担当者は、その設計が承認されたのか、単に都合がよかったのかを問うからだ。

切断時の状態を定義し、そのうえで 三つの要求を試す

上流トンネルが落ちたときに何が起きるかを決める。許可されたリモートトラフィックが、禁じられている場所で通常の WAN フォールバックへ黙って流れてはならないので、通過を許すファイアウォールポリシーも閉じる側に失敗するようにする。そのうえで実際の下流端末から 三つの場合を試す。通るべき要求が通り、通すべきでない要求が落ち、上流の障害で許可済みの要求が止まること。

ロールバックはルールごとに 一行で記録し、意図を再構築せずに変更を取り消せるようにする。

関連記事