Proxy Protocolを中継するサイドカー

TCP通信(非HTTP)のアクセス元IPの伝播には、Proxy Protocolが必要です。

コンテナイメージ

Proxy ProtocolのCODECツールとして、 go-mmproxyが手軽です。
バイナリと以下のスタートアップスクリプトを同梱したコンテナイメージを作成しておきます。

#!/bin/bash

ip rule add from 127.0.0.1/8 iif lo table 123
ip route add local 0.0.0.0/0 dev lo table 123

go-mmproxy -l 0.0.0.0:25577 -4 127.0.0.1:<target_port> -allowed-subnets </path/to/subnet.txt>

<target_port>は実アプリのポートで、たとえばsshdのウェルノウンポートは22番です。
<subnet.txt>はアクセス許可するIP範囲を記載したテキストで、制限なしの設定例は以下のような一行です。

0.0.0.0/0

サイドカーのマニフェスト

sshdのサイドカー構成のコンテナスペックの抜粋は以下のようになります。

    spec:
      containers:
      - name: mmproxy
        # image: required
        ports:
        - containerPort: 25577
          name: mmproxy
        securityContext:
          capabilities:
            add: ["NET_ADMIN"]
      - name: sshd
        # image: required
        ports:
        - containerPort: 22
          name: sshd

NET_ADMIN特権はスタートアップスクリプトのipコマンドに必要です。
TCPサービスからの戻りのパケットをキャプチャして書き換えます。

実サービスのコンテナポート(上の例の22)は公開しなくても動作するでしょう。
外部との通信は25577番に集約します。

ヘルスチェックに注意

Proxy Protocolを使用する場合、フロントにプロキシがある想定ですが、ヘルスチェックには注意が必要です。

go-mmproxyは互換性のないパケットを受信すると通信をドロップします。Google Cloudの構成では、ヘルスチェックは通過するものの、実通信の90%程度が失敗する挙動になりました。

ヘルスチェック対象をgo-mmproxyではなく実サービスに代えることで通信が安定しました。上の例ではヘルスチェック用に22番を定義しています。 TCPプロキシはログ出力も乏しく、非常に分かりにくい挙動となるため注意が必要です。

中馬崇尋
Chuma Takahiro