要求はトンネルのIPアドレス宛に届き、同じコンテナから隣接サービスのアドレス宛に出ていきます。その二つの瞬間の間にDNATが宛先を書き換えたため、パケットはVPNコンテナにとっての入力ではなくなりました。いまやこれは転送トラフィックであり、別のルールで判定されます。この変化が、トンネルアドレスに対して正しく見えるファイアウォールルールが、変換された接続に効かない理由です。

変換後のパケットを追う

クライアントプール10.90.0.0/24とトンネルアドレス10.90.0.1を考えます。二つのコンテナが一つのブリッジ上にあり、192.0.2.2がVPNを、192.0.2.3がアプリケーションを動かしています。クライアントは10.90.0.1:8080に接続し、VPNコンテナの名前空間のDNATルールがそれをアプリケーションの実際のアドレスとポートに書き換えます。その後、ルートがパケットをブリッジ越しに送ります。これらのアドレスは例示であり、配備の手順書ではありません。

アプリケーションが実際に待ち受けるポートは、ホストで公開されているどのポートとも異なる場合があります。二つの数字が一致すると仮定せず、コンテナ内のリスナーを読んでください。

許可は転送経路に属する

VPNコンテナにはIP転送と、クライアントプール・アプリケーションのアドレス・目的のポートに限定した転送の判断が必要です。確立済みの応答には独自の許可が要ります。元のトンネルアドレスに一致するルールはDNATの後では一致しません。宛先がすでに変わっているからです。INPUTの許可は、もはやこのホスト宛ではないトラフィックには誤ったフックです。

範囲は狭く保ちます。送信元範囲を一つ、宛先を一つ、サービスを一つ。緩い転送ルールは書きやすく、後から守るのははるかに難しくなります。

docker exec vpn-container ip route get 192.0.2.3
docker exec vpn-container iptables -t nat -S
docker exec vpn-container iptables -S FORWARD

Dockerのチェーンは自分のコンテナのチェーンではない

コンテナの名前空間内のルールはDockerホストのルールではありません。トラフィックがトンネルのインターフェースからブリッジへ渡るとき、ホストのブリッジ側ファイアウォールが別の判断を下すことがあります。Dockerのiptablesバックエンドでは、文書化されている転送チェーンとDNAT後の照合点が、その判断の現れる場所です。

Dockerのファイアウォール解説は、これらのチェーンとDNAT後の照合を説明しています。受け入れがないのを、Dockerのファイアウォール管理を無効にしたり、すべてのチェーンを緩くしたりして直さないでください。使おうとしている境界がなくなります。

戻り経路を意識的な選択にする

送信元アドレスを保持すると、アプリケーションには10.90.0.xが見え、応答をVPNコンテナ経由で戻す必要があります。そうしなければ通常のDockerゲートウェイが応答をホストへ送りますが、ホストはトンネルを所有していません。別の方法は、VPNコンテナで送信元を狭く変換することで、応答は単純になりますが、アプリケーションからクライアントが見えなくなります。意識して選び、どちらを選んだかを書き留めてください。

通常のクライアントから新たに許可された接続を試し、無関係なポートが閉じたままであることを確認します。パケットが消えるときは、VPNの名前空間、アプリケーションの名前空間、アプリケーション自身のログを調べます。ブリッジのゲートウェイへのpingは、サービスの受け入れテストではありません。

ルールはコンテナの対応する起動設定に置いてください。対話的な編集は、コンテナが再作成されると消えます。ホストのポート公開は別の露出経路であり、サービスがトンネル経由で届くという理由だけで必要なわけではありません。

関連記事