マルチホームの迷宮:AWS EC2における複数ENIのルーティングと「非対称パケット」の深淵
クラウドインフラの設計において、冗長化やセキュリティ分離の観点から「1台のインスタンスに複数のENI(Elastic Network Interface)をぶら下げる」というアーキテクチャに遭遇することは珍しくありません。しかし、この設計は往々にして、パケットの往来に関する「ネットワークの迷宮」を招きます。
特に、デフォルトゲートウェイが設定されたプライマリENI以外のセカンダリENIに対して外部からパケットが到達した際、Linuxカーネルが「返信をどこに送るべきか」を見失い、パケットがブラックホールに消える現象は、多くのエンジニアが一度は通る洗練の壁です。今回は、この泥臭いルーティングの挙動を、カーネルの視点から紐解いていきます。
—
なぜパケットは「迷子」になるのか?
Linuxのネットワークスタックは、デフォルトで「宛先ベースのルーティング」を行います。
1. パケットが eth1(セカンダリENI)に届く。
2. カーネルは応答パケットを作成する。
3. カーネルはルーティングテーブルを参照する。
4. 通常、ルーティングテーブルにはデフォルトゲートウェイとして eth0(プライマリENI)が指定されている。
5. 結果、応答パケットは eth0 から出ていく。
これをAWSのインフラ層が検知するとどうなるか。AWSのソース/デスティネーションチェックは、「パケットの送信元IPが、そのインターフェースに割り当てられたIPと一致しない」場合、即座にパケットを破棄します。つまり、eth1 に届いたリクエストの応答が eth0 から出ていこうとすると、AWSのネットワークフィルタによって遮断されるのです。これが「通信が確立しない」という事象の正体です。
—
Policy Based Routing(PBR)による解決:ip ruleの真価
この問題を解決するには、カーネルに対して「どのインターフェースから入ってきたパケットか」を識別させ、それに応じた「専用のルーティングテーブル」を適用させる必要があります。これを実現するのが ip rule です。
まずは、カスタムルーティングテーブルを定義します。
# テーブル番号200に「secondary_net」という名前を付与
echo "200 secondary_net" >> /etc/iproute2/rt_tables
# eth1のサブネットからの通信は、このテーブルを参照するようにルールを追加
# 10.0.1.0/24 は eth1 が属するサブネットの CIDR
ip rule add from 10.0.1.5 table secondary_net
# デフォルトゲートウェイをテーブル200に定義
# 10.0.1.1 は eth1 のサブネットのゲートウェイIP
ip route add default via 10.0.1.1 dev eth1 table secondary_net
この設定により、10.0.1.5 のIPを持つパケットに対する応答は、必ず eth1 のゲートウェイを経由して戻るようになります。これで「非対称ルーティング」という呪縛からは解放されます。
—
パフォーマンスとセキュリティの極致:TCPスタックの最適化
マルチホーム構成において、ルーティングが解決した後に待ち受けているのは「パフォーマンスの最適化」です。特にレイテンシにシビアなマイクロサービス環境では、以下のチューニングが決定打となります。
TCPバッファとウィンドウサイズ
デフォルトのTCPバッファサイズは、現代の高速なクラウドネットワーク環境では小さすぎることがあります。帯域幅遅延積(BDP)を考慮した調整が必要です。
# /etc/sysctl.conf に追記し、カーネルパラメータを最適化
# 大容量通信時のスループット向上
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
# TCPウィンドウのスケーリングを有効化(必須)
net.ipv4.tcp_window_scaling = 1
RTT削減とTLSハンドシェイク
ネットワークの物理的な制約(光の速さ)を超えられない以上、RTT(Round Trip Time)の削減はアプリケーション層の手腕にかかっています。
- TLS 1.3の強制: TLS 1.3はハンドシェイクを1回(1-RTT)で完了させます。従来のTLS 1.2の2-RTTと比較して、ハンドシェイク自体のレイテンシを確実に半減させます。
- TCP Fast Open (TFO): 2回目の接続以降、ハンドシェイク中にデータを送りつける技術ですが、AWSのロードバランサ等で終端する場合は注意が必要です。アプリケーションのエンドツーエンドで有効化することで、体感速度は劇的に向上します。
—
セキュリティの「見えない穴」を塞ぐ
複数ENI構成において、最も恐ろしいのは「誤ったインターフェースからパケットが漏洩すること」です。これを防ぐために、rp_filter(Reverse Path Filtering)の設定を慎重に行う必要があります。
# /etc/sysctl.conf
# 厳密なリバースパスフィルタリング(2は緩い設定、1が推奨)
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.eth0.rp_filter = 1
net.ipv4.conf.eth1.rp_filter = 1
rp_filter を 1 に設定することで、カーネルは「ソースIPアドレスに対して、パケットが到着したインターフェースが最適ルートであるか」をチェックします。これはセキュリティの最後の砦です。IPスプーフィング攻撃への耐性を高め、予期せぬルーティングミスによるパケット漏洩を未然に防ぎます。
結びに代えて:SREとしての矜持
複数ENIを扱うということは、OSレベルのネットワークスタックの深淵を覗き込むことに他なりません。単にクラウドのGUIでボタンをポチポチ押すだけでは、真の可用性は得られないのです。
パケットは嘘をつきません。tcpdump でキャプチャしたパケットが、期待したインターフェースから出ていっているか。あるいは、TCPフラグが正常なシーケンスを描いているか。その一瞬の挙動にこそ、我々エンジニアが追求すべき「信頼性」の真髄が宿っています。
この記事が、あなたの構築するアーキテクチャの堅牢性を、ほんの少しでも高める一助となれば幸いです。
コメント