NGINX の stream コンテキストで TLS パススルー接続を許可する
NGINX は TLS を終端せずに TCP TLS リレーを拒否できます。許可ルールは HTTP の location ではなく stream に置き、どのピアアドレスが届くかを確認してください。
証明書を一切保持せずに暗号化されたバイトを転送するのが TLS パススルーリレーであり、この構成は便利であると同時に少し分かりにくいものです。何も復号されないため、フィルタ対象になる HTTP 形式のものは存在せず、通常の location ブロックとそのアクセスルールはここでは役に立ちません。NGINX にできる判断は接続そのものについてです。どのネットワークピアが接続してきたのか、そもそもそのピアを転送すべきかどうかです。
判断は HTTP ではなく stream にある
stream コンテキストで NGINX は TCP セッションを扱います。接続のピアアドレスを見て、どのバイトもバックエンドに届く前に、順序付けされた allow と deny のルールを適用できます。これは完全な受け入れ判断であり、秘密鍵も証明書も HTTP 解析も必要ありません。
| Mechanism | What it decides | Where it lives |
|---|---|---|
| stream allow/deny | Whether this TCP peer is relayed | stream server block |
| ssl_preread map | Which backend a named connection goes to | stream, with the preread module |
| HTTP location rule | Whether an HTTP request is served | http server block |
この三行は決して互いの代わりにはなりません。443 番ポートに言及したファイルに HTTP のアクセスディレクティブをコピーしても何も変わりません。stream サーバーは http コンテキストを決して読まないからです。
転送する前に接続を受け入れる
stream モジュールと stream-access モジュールが利用可能な既存のインストールがあり、VPN クライアントが送信元アドレスを 10.90.0.0/24 に保ち、192.168.50.20:443 のバックエンドがすでに目的の HTTPS アイデンティティを提供していると仮定します。
stream {
server {
listen 443;
allow 10.90.0.0/24;
deny all;
proxy_pass 192.168.50.20:443;
}
}
これは動作中の設定への直接の置き換えではなく、新しい listener の断片として読んでください。既存の listener と include を先に確認してください。すでに使用中のポートに二つ目の listener を置くと、リクエスト時ではなく reload 時に失敗します。
欠けているものに注目してください。listen ... ssl はなく、証明書ディレクティブもありません。NGINX は暗号化されたストリームを転送し、バックエンドが TLS を終端してクライアントが検証する証明書を提示します。allowlist を通らないクライアントの TCP セッションは拒否され、HTTP 403 のページは返らず、ステータスコードを期待するツールは役に立たない結果を報告します。
allowlist が対象とする範囲とそうでない範囲
リレーがすでにサーバー名でバックエンドを選んでいるなら、モジュールが利用可能であれば ssl_preread と map がその仕事を続けられます。名前は依然としてクライアントが提示するものであり、名前を提示してもクライアントが VPN に参加したことの証明にはなりません。
例のルールは stream listener 全体を対象にします。そのため、公開サイトと VPN 専用サイトが混在する単一の入口には不向きで、名前ごとの例外が必要になります。名前依存の読めないポリシーより、listener を分けるほうが通常は明確です。
さらに二つの隙間を挙げておきます。プレフィックスの一致は、パケットがどのインターフェースから来たかを何も語りません。また、別の場所の HTTP ルールでこの listener を制約することはできません。どちらも、一行の allow を境界全体とみなすのではなく、ホストレベルの ingress ポリシーを視野に入れておく理由です。境界は一致すべき二つの制御として書き留め、どちらかを変更したらレビューされるようにしてください。
NGINX が実際に見るのは誰のアドレスか
ロードバランサー、別のプロキシ、あるいは source NAT が NGINX の前に中間装置を置くことがあるため、観測されるピアは VPN クライアントの内部アドレスではありません。プレフィックスを選ぶ前に実際の経路を調べてください。誤ったアドレス向けに書かれた allowlist は、変換装置の背後の全員を通すか、誰も通さないかのどちらかになります。
PROXY プロトコルと実 IP の扱い は正当な答えであり、互換性があり明示的に信頼された送信者に対してのみ設定する必要があります。どちらの仕組みも送信者の言うことを信じるため、送信者リストは短く保たなければなりません。任意のインターネットクライアントからの識別ヘッダーを信頼しても、送信元情報が再び信頼できるようになるわけではありません。正しい拒否が偽造された受け入れに変わるだけです。
reload の前に両方の結果をテストする
設定を検証して reload し、その後二回テストします。許可された新しいセッションが動作すること、拒否されたセッションが動作しないことです。許可されたテストでは通常のバックエンド証明書検証を残してください。接続はできるがバックエンドを検証できないリレーは、一つの問題を直して別の問題を生んでいるからです。
nginx -t
ss -tnp | grep ':443'
バックエンドへの経路と応答も別々に確認してください。allowlist を通過したことは NGINX がセッションを受け入れたことしか証明しません。到達できないバックエンドに応答させることはできず、開始前に欠けていた戻り経路を修復することもできません。