同じホストでNGINXとOpenVPNを動かすと、クライアントのアドレスは三通りに現れ、それぞれがリクエストの取りうる経路の一つに対応します。トンネルアドレスに届くブラウザ、公開アドレスに届くブラウザ、ゲートウェイのインターネット経路から出ていくプログラムは、待ち受けソケットではすべて違って見えます。ログ行を解釈する前に、どの経路を見ているのかを決めてください。判断はクライアントが使った宛先、外側のVPNエンドポイントに対する例外、そして途中でパケットが変換されるかどうかにかかっています。

誰が利用者かではなく、宛先で決める

リクエストが送られた宛先アドレスから始めるのは、そのアドレスが経路を選ぶからです。ホストのトンネルアドレス宛てのリクエストは、クライアントの内向きアドレスを送信元としてトンネルインターフェースに届きます。ホストの公開アドレス宛てのリクエストは通常、インターネット側のインターフェースにクライアントの公開アドレスで届き、同じノートPCがその瞬間にトンネルを張っていても変わりません。つまりVPNプールの所属はパケットの経路の性質であり、利用者について回る性質ではありません。

Path the request tookSource the site normally records
Client reaches the site at its tunnel address, 10.24.0.1Client inner address, 10.24.0.20
Client reaches another internet site through the gatewayGateway public egress address, 192.0.2.44
Client reaches the gateway's public address through the endpoint exceptionClient's own public access address

トンネルと無関係なアドレスでVPN利用者がログに現れたとき、最初に確認する価値があるのはこの三行目です。同じプロファイルの二人が違う記録を残せる理由も、それぞれの接続元ネットワークが違い、トンネルの中の何もそれを上書きしないことから説明できます。

外側のエンドポイントが二つ目の公開経路を作る理由

クライアントはトンネルを張るためにゲートウェイの公開アドレスへ到達する必要があるので、そのアドレスへの経路はトンネルの外に存在しなければなりません。クライアントが全通信を内側へ向けるとき、まともな実装は自分自身に依存するトンネルを避けるため、サーバーの公開アドレスへの明示的なホスト経路を保持します。この例外はサービスを選ばないので、同じ公開アドレスへのあらゆるリクエストがそれに従い、ゲートウェイ上に置かれたサイトへのブラウザのリクエストも含まれます。

これがこの分野の混乱の多くを生む仕組みで、サーバー側ではなくクライアント実装に依存します。したがって同じプロファイルの二つのクライアントが違う振る舞いをすることがあります。ログを直そうとして例外を外すとトンネルも一緒に落ちるので、例外は残したまま、その周りで設計してください。

ソケット、経路表、ログ形式を合わせて読む

どの経路を見ているかは三つの観察、つまりソケットがどこで待ち受けているか、宛先に応答するのはどのインターフェースか、そしてログ形式が実際に何を記録しているかで決まります。待ち受けがトンネルアドレスだけに束縛されていれば、公開宛てのリクエストはそこへ全く届かず、これだけで二行が消えます。クライアントの経路検索がトンネルデバイスを返すなら、リクエストは内向きの送信元で届いており、ログにもそう出るはずです。

ss -lntp 'sport = :443'
ip route get 10.24.0.20
ip route get 192.0.2.44

次に、行ではなく形式を読みます。転送ヘッダーで埋まる項目は、ソケットの相手ではなく主張を記録し、その主張が意味を持つのは直接の相手が信頼できるプロキシであるときだけです。両方の値をログに書いておけば後日の議論が片付きます、直接の相手と置き換えられたアドレスは別の事実であり、ネットワークから来たのは片方だけだからです。

log_format tunneled '$remote_addr $realip_remote_addr $request $status';
grep -n 'log_format' /etc/nginx/nginx.conf

望む入口を選び、DNSを合わせる

サイトをトンネル専用にするなら、VPNクライアントに対してはトンネルアドレスに解決される名前を与え、待ち受けソケットでポリシーを適用します。内部名に対して10.24.0.1を返す分割DNSの応答は、名前解決の細部という装いをした経路の決定です。サイトを公開もするなら、名前を二つ、またはポートを二つ保ち、どちらがリクエストを処理したのかをログに語らせてください。

許可の規則も同じ論理に従います。トンネルプールを許可しても公開宛てのリクエストは認可されず、インターネット経由で届いた接続に内向きアドレスを埋めることもしません。二つの入口を一つの名前の下で混ぜると、記録される送信元は設計上の選択ではなくクライアント経路の副作用になります。

経路を確かめ、次にポリシーを確かめる

ゲートウェイでのキャプチャと自分で制御できるリクエストで経路を確認します。トンネルデバイスと公開インターフェースでのキャプチャはどちらがバイトを運んだかを示し、パケットの順序を見ればその間に変換が起きたかどうかも分かります。

tcpdump -ni tun0 port 443 -c 5
tcpdump -ni eth0 port 443 -c 5

次にアクセスを両方向で、つまり意図した名前の入口が意図したクライアントで機能し、承認していない公開経路は単に遅いのではなく拒否されることを確認します。一般的なIPエコーサイトはゲートウェイのインターネット出口について何かを示すだけで、同じホスト上のこのサイトについては何も示しません。ページとWebSocketが食い違うときは、サーバー設定に触れる前にURL、アドレスファミリー、DNSの応答を比較してください。

関連記事