【実務・中級編】 CNIプラグインにおけるマスカレード(Masquerade)機能とポッドCIDRの隠蔽 – クラウド&コンテナネットワーク実践ガイド

Kubernetesの「見えない壁」:CNIマスカレードが隠蔽するPod IPの真実

「なぜ、Podから外部のAPIを叩くと、送信元IPがノードのIPに化けているのか?」

インフラエンジニアとして現場に立っていると、一度は必ずこの疑問に突き当たります。KubernetesのPodは、クラスタ内で一意なIPアドレス(Pod CIDR)を持っています。しかし、そのパケットがAWSのVPCの外、あるいはNATゲートウェイを越えてインターネットへ飛び出すとき、PodのIPはそのままでは通用しません。

ここで暗躍するのが、CNI(Container Network Interface)プラグインによる「マスカレード(IP Masquerade)」です。今回は、この「パケットの変身」の裏側を、泥臭いトラブルシューティングの視点から紐解いていきます。

なぜマスカレードが必要なのか?

結論から言えば、「ルーティングの不整合を回避するため」です。

Pod CIDRは、多くの場合、クラスタ内でのみ有効な「プライベートな空間」です。これをそのままVPC外やインターネットへ流すと、戻りのパケットがどこへ向かえばいいのか(どのノードのどのPodへ届けばいいのか)、ルーターは理解できません。

そこで、CNIはパケットがノードの境界を出る瞬間に、送信元IPアドレスを「ノード自身のIPアドレス」に書き換えます。これが iptables や ebpf を用いたSNAT(Source NAT)の正体です。

通信のシーケンス:パケットの「変身」

Podから外部API(例: https://api.example.com)を叩く際の通信フローは、以下のようになります。

1. Pod内: curl がパケットを生成。送信元は 10.244.x.x (Pod IP)。
2. veth pair: パケットは仮想NICを通り、ホストOS(ノード)のネットワーク名前空間へ到着。
3. iptables (POSTROUTING): ここが運命の分かれ道。CNIの設定により、送信元IPをホストのNIC IP(例: 192.168.1.10)へ書き換えるルールが適用される。
4. VPCルーター/NAT Gateway: 送信元がノードIPになったパケットを受け取り、インターネットへ転送。
5. 返信: 応答はノードIPへ戻り、ホストは conntrack テーブルを使って、どのPodへの戻りかを判断し、再度Pod IPへ変換してPodへ渡す。

CNIの設定と実務的なパラメーター

多くのCNI(CalicoやFlannelなど)では、このマスカレードを有効にするかどうかのフラグがあります。

例えば、Calicoの IPPool 設定ファイルを見てみましょう。

apiVersion: projectcalico.org/v3
kind: IPPool
metadata:
  name: default-ipv4-ippool
spec:
  cidr: 10.244.0.0/16
  # ここが重要!NATOutgoingを有効にすると、
  # このプール内のPodから外部への通信がマスカレードされる
  natOutgoing: true
  # もしVPC内で直接Pod IPと通信したい場合はfalseにするが、
  # その場合はVPCルートテーブルの更新が必要
  nodeSelector: all()

なぜ natOutgoing: false にするのか?

VPC内の他のサーバー(RDSやオンプレミスへのVPN接続先など)とPodが直接通信したい場合、マスカレードは邪魔になります。送信元が「ノードのIP」になってしまうと、受取側はどのPodからのアクセスか判別できないからです。

現場で遭遇する「マスカレードの罠」

トラブルシューティングで最も多いのが、「外部APIからアクセス制限を受けている」というケースです。

例えば、相手先のAPIが「ホワイトリスト方式」でIP制限をかけている場合、PodごとのIPを登録しても無意味です。ノードがオートスケーリングで増減するたびに送信元IPが変わるため、API担当者にノードのサブネット範囲をすべて伝え、NAT Gatewayの「固定IP(EIP)」を経由させる構成を組むのが、クラウド運用の定石です。

デバッグコマンド:今、何が起きているか?

パケットが変換されているか確認したいときは、ノード上で iptables を覗くのが最も確実です。

# マスカレードのルールが適用されているか確認
sudo iptables -t nat -L POSTROUTING -n --line-numbers

# 特定のPod通信をトレースする場合(要tcpdump)
# ノード上でPodからのパケットをキャプチャし、IPの変化を確認する
sudo tcpdump -ni eth0 host 192.168.1.10 and port 443

Pythonで疎通確認用コード

単純な curl だけでなく、送信元IPがどう見えているかを確認するための簡単なスクリプトをPod内で走らせると、検証が捗ります。

import requests

# 外部のグローバルIP確認サービスを叩く
# マスカレードが効いていれば、PodのIPではなく「NAT GatewayやノードのIP」が表示されるはず
try:
    response = requests.get("https://ifconfig.me/ip", timeout=5)
    print(f"現在の送信元グローバルIP: {response.text}")
except Exception as e:
    print(f"通信エラー: {e}")

まとめ:ネットワークの透明性は諸刃の剣

CNIのマスカレード機能は、Kubernetesを既存のネットワーク環境に「無理やり」馴染ませるための便利な糊です。しかし、この「隠蔽」があるからこそ、アプリケーション開発者はネットワークの複雑さを意識せずに開発ができます。

一方で、いざ大規模なシステムを構築する際は、「どのIPで外部と通信しているか」を把握しておくことが、セキュリティ要件を満たすための唯一の道です。

「Pod IPが見えない」と嘆く前に、まずはそのノードが背負っているNATのルールを確認してみてください。ネットワークエンジニアとしての視点を持てば、Kubernetesのトラブルシューティングは、パズルのように面白くなってくるはずです。

コメント

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