二つの設計、一つの HTTPS アプリケーション、そしてパケットはそれぞれ別の経路を通ります。ポート転送はパケットの届け先を変え、それ以外はそのままにします。VPN はまずそのパケットを別のパケットの中に入れて運ぶので、アプリケーションのリスナーは別の送信元とより小さい最大ペイロードを見ます。人が議論する暗号化はどちらの場合にも存在します。アプリケーションは依然として HTTPS だからです。違うのは、誰が接続を開けるか、そして途中のネットワークが何を観測できるかです。この区別が実務的な疑問のほとんどを決着させます。

DNAT ルールは宛先を書き換えてそこで止まる

Linux ゲートウェイでサービスを公開するとは、nat テーブルの PREROUTING チェーンにルールを置くこと、または nftables での同等物を置くことです。ルールは公開アドレスとポートに一致し、宛先をアプリケーションのプライベートアドレスに書き換えます。送信元アドレス、送信元ポート、ペイロードはそのままで、conntrack が対応を記録するので戻りの応答は出るときに書き換えられます。この動作は RFC 3022 に書かれた従来のアドレス変換モデルです。

sudo iptables -t nat -A PREROUTING -d 203.0.113.10 -p tcp --dport 443 \
  -j DNAT --to-destination 10.20.30.40:443
sudo iptables -t nat -L PREROUTING -n -v
sudo conntrack -L -p tcp --dport 443

アプリケーションのリスナーは、接続が変換を通って来たことを知らず、クライアントの本当の送信元アドレスが見えるのでアクセスログやレート制限に役立ちます。conntrack が対応を反転させるため、プライベートアドレスに応答します。その経路上で復号や再暗号化は起きません。TLS はクライアントとアプリケーション自身の証明書の間で動き続けます。

このルールは後で出会う失敗の形も決めます。ゲートウェイが転送しても、アプリケーションのホストに クライアントへの戻り経路がない 場合、応答は誤った送信元で出てハンドシェイクが止まります。二番目のルールが先に一致すれば順序が結果を決め、iptables -t nat -L -n -v がどのルールがパケットを取ったかを示すカウンタを表示します。

トンネルはリスナーが見る前にパケットを包む

VPN はアプリケーションを公開しません。クライアントはゲートウェイの公開アドレス宛の外側パケットを作り、その中に内側パケットを暗号化して入れ、ゲートウェイは復号して内側パケットをプライベートな宛先へルーティングします。WireGuard では外側の転送は UDP で、通常は高いポートです。OpenVPN を TCP 443 で使うと、経路を見ているものには外側パケットが TLS のように見えます。

トンネルの中では内側パケットがプライベートアドレスを保ちます。クライアントのトンネルアドレス、たとえば 10.8.0.6 と、10.20.30.40 のアプリケーションです。そのためリスナーが見る送信元はトンネルのプールからになり、すべてのクライアントがそのゲートウェイを次のホップとして共有します。VPN の後ろのアクセスログがユーザーではなくゲートウェイを示すことが多いのはまさにこの理由で、ゲートウェイが元の送信元を保持しない限りそうです。

包むにはヘッダーの場所が必要で、これが測定できる結果を伴う唯一の仕組み上の違いです。外側の IP ヘッダーに UDP、さらに WireGuard 自身のヘッダーが経路の MTU を削るので、大きなパケットは分割するか、内側の TCP スタックが MSS を絞る必要があります。転送経路で動く転送が、中間装置が小さい MTU を知らせる ICMP を落とすと、トンネル上で止まることがあります。

ip route get 10.20.30.40
ping -M do -s 1400 10.20.30.40
sudo iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN \
  -j TCPMSS --clamp-mss-to-pmtu

露出は入口で決まり、暗号では決まらない

どちらの設計も同じ TLS リスナーで終わるので、同じ証明書、同じプロトコルバージョン、同じアプリケーションのログインを引き継ぎます。変わるのは、誰がハンドシェイクを始められるかです。公開転送では、203.0.113.10:443 に到達できるホストならどれでも、アプリケーションの認可が検討される前に TCP ハンドシェイクと TLS ClientHello を得ます。トンネル経由のアクセスだけなら、リスナーに届くのはゲートウェイがトンネルへルーティングするアドレスだけで、見知らぬ者の SYN はゲートウェイのポリシーで死にます。

この違いは到達可能性の話で、機密性の話ではありません。転送された HTTPS サービスは平文ではなく、VPN はアプリケーション認証の必要性をなくしません。トンネルへの受け入れは、ある機器がこのネットワークにパケットを送れるかを答え、ファイルアプリケーションは、あるユーザーが文書を読めるかを答えます。この二つを混同すると、LAN 全体を渡す VPN と、一つの共有パスワードのアプリケーションに落ち着きます。

リスナーとポリシーを別々に調べてください。どちらも想定より広い可能性があります。

sudo ss -ltnp 'sport = :443'
sudo nft list ruleset
openssl s_client -connect 203.0.113.10:443 -servername files.example.com </dev/null

ss がリスナーのバインド先を 0.0.0.0 と示すなら、アプリケーションはルーティングとファイアウォールのポリシーが許すどこからでも到達でき、転送は入口の一つにすぎません。プライベートアドレスにバインドするか、ファイアウォールで送信元の範囲を絞るかは、VPN の選択とは別の決定であり、露出を実際に狭める決定です。

ラベルではなく経路を測る

転送のほうが速いという主張に対して、公正な比較は同じクライアント、同じアクセス網、同じファイル、同じ TLS 設定、同じアプリケーションホストと、ほかを一定に保ちます。経路ごとに転送を 二回実行し、合計時間、失敗回数、応答性を記録します。無関係な速度テストの出力ではありません。

curl -sS -o /dev/null -w '%{time_connect} %{time_appconnect} %{time_total}\n' \
  https://files.example.com/report.pdf
mtr -rwc 20 203.0.113.10
mtr -rwc 20 10.20.30.40

これらの数値は接続の確立と転送時間を分けます。二つの経路はふつう暗号のコストではなく、往復遅延と MTU で違うからです。TLS の処理はどちらの設計でも端点で行われ、トンネルはカプセル化、別の経路、場合によってはより混雑したゲートウェイを加えます。トンネルの経路が長い、またはゲートウェイが混んでいるなら、違いは経路に属し、暗号という言葉には属しません。

サービスが本当に必要とする入口ポリシーを選び、測定した差がそれを変えるに値するかを決めます。公開転送は、送信元の制限、更新された TLS、前面の監視を備えた、開かれたインターネット向けのサービスに合います。トンネル経由のアクセスだけなら、利用者がすでに登録済みの内部ツールに合います。ただしゲートウェイのルーティングとアプリケーションの権限の両方が LAN 全体より狭いことが条件です。

設計を完成と呼ぶ前に 四つを確認します。リスナーがどのアドレスにバインドされているか、どのルールや経路がパケットを受け入れるか、クライアントの実際のアドレスから戻り経路が機能するか、大きなペイロードが MTU を越えられるかです。どれにも上のコマンドがあり、「安全」という言葉や帯域のグラフでは答えられません。

関連記事