【実務・中級編】 Proxy Protocol v2(プロキシプロトコルv2)のバイナリヘッダー構造とNLBでの活用 – クラウド&コンテナネットワーク実践ガイド

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)」も大きく改善されます。

ぜひ、次回のインフラ設計やトラブルシューティングの現場で、この「バイナリの呪文」を思い出してください。健闘を祈ります。

コメント

タイトルとURLをコピーしました