L4ロードバランサーの「見えない壁」を突破せよ:Proxy Protocol v2でクライアントIPを正しく射抜く技術
クラウドアーキテクトとして現場を渡り歩いていると、避けては通れない「IPアドレスの消失問題」というものがあります。
AWSのNLB(Network Load Balancer)のようなL4ロードバランサーは、その超高速なパケット転送能力と引き換えに、HTTPレイヤーのヘッダーを書き換えることができません。そのため、バックエンドのコンテナやサーバーに届く頃には、接続元IPアドレスは「NLBのIP」にすり替わっています。
「ログにはNLBのIPしか残らない。クライアントの真のIPを知りたい」。そんな時、安易にHTTPヘッダーに頼るのではなく、ネットワーク層で解決するスマートな解が Proxy Protocol v2 です。今日は、現場の泥臭いトラブルシューティングにも耐えうる、このバイナリプロトコルの深淵を解説します。
—
1. なぜ「Proxy Protocol v2」なのか
HTTP/HTTPSであれば X-Forwarded-For を使えば済みますが、TCP/UDPベースのDBアクセスや独自プロトコルの通信では、アプリケーション層でヘッダーを挿入することすらままなりません。
Proxy Protocol v2(以降PPv2)は、HAProxyが策定したプロトコルで、通信の先頭にバイナリ形式のヘッダーを1行挿入します。NLBはクライアントからの接続を受け取った際、ターゲットサーバーとの間に新しいTCPコネクションを張りますが、その「一番最初」にクライアントのIPとポート情報を詰め込んだバイナリデータを送り込みます。
アプリケーションはこれを解釈して真のIPを取り出すのですが、重要なのは「バイナリである」という点です。人間がパケットキャプチャして tcpdump を眺めても、ただのゴミデータにしか見えません。だからこそ、仕組みを理解していないとデバッグで死ぬことになります。
—
2. Proxy Protocol v2のバイナリ構造を紐解く
PPv2のヘッダーは非常にシンプルですが、厳格です。16バイトのシグネチャ(マジックナンバー)から始まり、バージョン情報やプロトコルファミリーが続きます。
バイナリヘッダーの主要パーツ
- Signature:
0D 0A 0D 0A 00 0D 0A 51 55 49 54 0A(固定の12バイト) - Ver & Command: バージョン(2)とコマンド(PROXY/LOCAL)
- Family: TCPv4, TCPv6, Unixドメインソケットなどの識別
- Length: 後続データの長さ
このヘッダーを読み解く際、最も注意すべきは「後続データ」のパースです。もしアプリケーション側で read() した際にヘッダーの途中で切れていたり、逆にアプリケーションデータをヘッダーの一部と誤認したりすると、接続は即座に切断されます。
—
3. NLBで有効化する際の実務的な設定
AWS NLBでPPv2を有効にするのは、ターゲットグループの設定で「Proxy Protocol v2」を「オン」にするだけです。しかし、これが有効になった瞬間、バックエンドのアプリケーションは、先頭のバイナリデータを受け取る準備ができていなければなりません。
準備なしにオンにすると、アプリケーションは「不正なパケットが送られてきた」と判断し、コネクションを閉じてしまいます。
NginxでPPv2を受け入れる設定例
Nginxをリバースプロキシとして配置する場合、listen ディレクティブに proxy_protocol を追記します。
http {
server {
# 80番ポートでProxy Protocolを受け入れる設定
listen 80 proxy_protocol;
# 信頼できるNLBのIP範囲を定義(セキュリティの基本)
set_real_ip_from 10.0.0.0/16;
# Proxy Protocolから取得したIPを$remote_addrに反映
real_ip_header proxy_protocol;
location / {
# これでログにもバックエンドへの転送にも正しいIPが引き継がれる
proxy_set_header X-Forwarded-For $proxy_protocol_addr;
}
}
}
—
4. 現場のデバッグTips:パケットをどう見るか
「接続が拒否される」「通信がタイムアウトする」といったトラブル時、tcpdump で何が起きているかを確認する方法は必須のスキルです。
まず、NLB経由の通信でヘッダーが正しく付与されているかを確認するには、以下のコマンドが有用です。
# 特定のポートでヘッダーの中身をバイナリとして確認
sudo tcpdump -i any port 80 -X -n -v
ただし、-X だけではバイナリが読みづらいため、Wireshark に取り込んで解析するのがベストです。Wiresharkであれば、Protocolを proxy でフィルタリングするだけで、バイナリヘッダー内の Source IP と Destination IP を可視化してくれます。
—
5. まとめ:シニアエンジニアからの教訓
最後に一つだけ、現場でよくある失敗談を共有します。
「ロードバランサーとサーバーの間に、別のネットワーク機器(WAFや別のLB)が挟まっている場合」 は特に注意が必要です。途中の機器がProxy Protocolを解釈できずにパケットをドロップしたり、ヘッダーを破壊したりすることがあります。
1. トポロジーの確認: 途中に透過的ではないデバイスはないか。
2. ログの二重チェック: NLBのアクセスログと、アプリケーションのログ(Proxy Protocol解析後)を突き合わせる。
3. ヘルスチェックの罠: NLBのヘルスチェック自体はProxy Protocolなしで行われることが多いですが、アプリケーション側で「すべての接続がPPv2であること」を強制すると、ヘルスチェックが通らなくなります。listenポートを分けるか、条件分岐を適切に記述してください。
Proxy Protocol v2は、現代の疎結合なマイクロサービス環境において、ネットワークとアプリケーションの架け橋となる非常に強力な武器です。これを使いこなせるようになれば、ログの精度は劇的に向上し、障害時の「追跡可能性(Observability)」も大きく改善されます。
ぜひ、次回のインフラ設計やトラブルシューティングの現場で、この「バイナリの呪文」を思い出してください。健闘を祈ります。
コメント