【実務・中級編】 セキュリティグループのコネクションステートトラッキングと非対称ルーティング問題 – クラウドインフラと仮想化ネットワーク実践ガイド

セキュリティグループが「隠された非対称ルート」で牙を剥く日:AWSにおけるステートフル・トラッキングの罠と現場の処方箋

こんにちは。クラウドインフラの底が抜けるような夜も、泥臭いパケット解析で朝を迎えてきたシニアSREの私です。

Web APIの設計やインフラのサイジングをどれほど美しく仕上げても、ひとたびネットワークの「裏の顔」であるルーティングとファイアウォールの挙動に嫌われると、システムは音もなく沈黙します。特に、AWSの仮想化ネットワークにおいて、パブリックサブネットやプライベートサブネット、そしてインターネットゲートウェイ(IGW)の境界線を縦横無尽に行き交うパケットたちが、どのようなルールで裁かれているか意識したことはあるでしょうか。

今回は、AWSのセキュリティグループ(以下、SG)が持つ「ステートフル・コネクションステートトラッキング」という強烈な機能が、非対称ルーティング(Asymmetric Routing)という魔物と出会ったときに、いかにして正常な通信を木端微塵に粉砕するか、そのメカニズムと現場でのリアルな回避策を徹底的に解説します。

教科書通りの設定をしたはずなのに、なぜかAPIレスポンスが返ってこない――そんな悪夢に立ち向かうための知見を紐解いていきましょう。

—

1. そもそもAWSのセキュリティグループとは何者か?

AWSを触るエンジニアであれば、SGを触ったことがない人はいないでしょう。インスタンスやENI(Elastic Network Interface)単位でアタッチされる仮想ファイアウォールです。

ここで重要なのは、SGがステートフル(Stateful)なファイアウォールであるという事実です。
ステートフルとは、パケットの往来における「文脈(状態)」をハイパーバイザー層で記憶していることを意味します。

  • インバウンド(Inbound)のルール設定: 外部から入ってくるパケットを許可します。この時、SGの内部ステートテーブルに「この通信は許可された」というエントリが刻まれます。
  • アウトバウンド(Outbound)の自動許可: ステートフルであるため、インバウンドで許可されて確立された通信に対する戻りのパケット(レスポンス)は、アウトバウンドルールに関わらず自動的に許可されます。

しかし、この「賢すぎるステート管理」こそが、ルーティングの意図せぬ歪み(非対称ルーティング)と組み合わさったとき、致命的なパケットドロップを引き起こす引き金になるのです。

—

2. 非対称ルーティングが引き起こす「片道切符」の悲劇

非対称ルーティングとは、通信の「往路(Request)」と「復路(Response)」で、異なるネットワーク経路を通る現象を指します。

一般的なWeb API通信の往復路を考えてみましょう。

1. 往路: クライアント(インターネット) $\to$ IGW $\to$ EC2インスタンス(プライベートサブネット上のAPIサーバー)
2. 復路: EC2インスタンス $\to$ IGW $\to$ クライアント

これが正常な「対称ルーティング」です。しかし、次のような構成やトラブルシューティングの最中に、非対称ルーティングが顔を出します。

  • 複雑なマルチENI構成で、プライマリNICとセカンダリNICの間でルーティングテーブルが混線している場合
  • サードパーティ製のセキュリティアプライアンス(ファイアウォール/NATインスタンス)を経由させるため、カスタムルートテーブルで強引にパケットを曲げた場合
  • AWS Transit Gateway(TGW)やVPN接続を絡めた複雑なオンプレミスとのハイブリッド環境

パケットがドロップするメカニズムのシーケンス

ここで、SGのステートトラッキングと非対称ルーティングが衝突する瞬間の挙動を追ってみましょう。

[クライアント] 
      │
      ▼ (1. 往路パケット送信: Src=Client, Dst=ENI_A)
[AWS ハイパーバイザー (ENI_A)] 
      │ ──> [SGステートテーブルに「通信確立」を記録]
      ▼
[APIサーバー (ENI_A)]
      │ (2. 処理完了・復路パケット生成: Src=ENI_B, Dst=Client)
      ▼
[AWS ハイパーバイザー (ENI_B)] 
      │ ──> ★ここで悲劇が発生!
      │       復路パケットが往路とは別のENI_Bから送出されたため、
      │       ENI_B側のSGステートテーブルには対応する「確立済みセッション」が存在しない。
      ▼
[SGの判定: 「見覚えのない戻りパケットだ!不正な通信に違いない」]
      │
      ❌ (3. パケット即座にサイレントドロップ)

AWSのハイパーバイザー層において、SGのステートテーブルはENI(ネットワークインターフェイス)単位、あるいは流れるフロー単位で管理されています。往路のパケットが通過したENIと、復路のパケットが通過するENI(または同じENIであっても、ルーティングの不整合でステートと一致しないパケット)が食い違うと、SGは「往路を通っていないのに、急に戻りパケットが来たぞ」と判断し、容赦なくパケットを闇に葬り去ります。

これが、非対称ルーティング起因のパケットドロップの正体です。

—

3. 実務で遭遇するデバッグと再現検証

では、この現象に現場で直面したとき、私たちはどうやってそれを突き止め、検証すればよいのでしょうか。

現場でよくあるケースとして、Pythonの requests や curl を使ってAPIを叩いた際に、connection timeoutや connection reset by peer が発生する状況を想定してみましょう。

検証用Pythonスクリプト(タイムアウトと例外のキャッチ)

import requests
from requests.exceptions import RequestException

# 非対称ルーティングやSGのドロップが発生している環境へのリクエスト
API_ENDPOINT = "https://api.internal.example.com/v1/data"

def test_api_connection():
    try:
        print(f"Connecting to {API_ENDPOINT} ...")
        # 接続タイムアウトを短めに設定して挙動を確認
        response = requests.get(API_ENDPOINT, timeout=3.0)
        
        print(f"Status Code: {response.status_code}")
        print(f"Response Body: {response.text}")
        
    except RequestException as e:
        # SGによるサイレントドロップ(Blackhole)の場合、SYNパケットに対するACKが返らず
        # TCPコネクション確立の段階でタイムアウト(ConnectTimeoutError)が発生する。
        print(f"[ERROR] 通信に失敗しました。詳細: {e}")
        print("💡 ヒント: ファイアウォールのステート不整合やルーティングの非対称性を疑ってください。")

if __name__ == "__main__":
    test_api_connection()

デバッグの鉄則:パケットキャプチャ(tcpdump)の活用

OS内部に入り込んで tcpdump を仕掛けても、AWSのハイパーバイザー層(SG)でドロップされたパケットは、OSのネットワークスタックまで到達しないことがあります(往路のSYNがドロップされた場合など)。

しかし、復路が別のENIに逃げているケースや、パケットがどこまで飛んでいるかを追うためには、インスタンス内部でのキャプチャが第一歩になります。

# 特定のインターフェイス(例: eth0)でSYNパケットやRSTパケットの往来をキャプチャする
sudo tcpdump -nnvv -i eth0 host <クライアントのIPアドレス> and port 443

もし、OS側からは復路のパケット(ACKやSYN-ACK)を送出しているログが出ているにもかかわらず、クライアント側に一向に届いていない場合、AWSの仮想ルーターやSGのステート、あるいはルートテーブルのミスマッチを強く疑うべきサインです。

—

4. 回避策とアーキテクチャ上のベストプラクティス

この非対称ルーティングとSGの衝突問題を回避するためには、AWSのネットワーク設計における原則に立ち返る必要があります。

1. マルチENI構成の原則を見直す(Single ENIの推奨)

近代的なクラウドネイティブアーキテクチャにおいて、ひとつのEC2インスタンスに複数のENIをぶら下げ、それぞれに異なるルートテーブルを割り当てる設計は、百害あって一利なしであることが多いです。
特別な理由(管理用ネットワークの完全分離など)がない限り、「1インスタンス = 1ENI(メインのプライマリIPのみ)」を基本原則とし、複数のIPアドレスが必要な場合は、単一のENIに複数のセカンダリプライベートIPアドレス(Secondary IP Addresses)を割り当てるアプローチをとりましょう。これにより、ルーティングとSGのステートが単一のインターフェイスに集約され、非対称ルーティングの発生確率を劇的に下げることができます。

2. AWS Network Firewall や Transit Gateway への移行

もし、高度なパケットインスペクションやルーティング制御のために非対称なパスを意図的に作ざるを得ない場合(例:サードパーティ製ファイアウォールアプライアンスを挟む場合など)は、個々のEC2インスタンスのSGに頼るのではなく、AWSが提供するマネージドサービスを活用します。

  • AWS Network Firewall: ステートフル/ステートレスのルールを柔軟に定義でき、複雑なルーティング環境でもAWSの基盤側で適切にトラッキングされます。
  • AWS Transit Gateway のルートテーブル分離: ネットワークアプライアンスを正しくルーティングのパスに組み込み、パケットの往復経路を強制的に一致させます。

3. ステートレスな設計(可能な場合)へのシフト

Web APIのバックエンドサーバー群がロードバランサー(ALB)配下にある場合、ALBはステートフルにトラフィックを分散し、ターゲットグループへの通信はクリーンな対称ルーティングが維持されるようAWSが裏側でルーティングを担保しています。独自にEC2へ直接グローバルIPを付与したり、複雑なカスタムルートテーブルをプライベートサブネットに手動で流し込むような「アクロバティックなネットワーク設計」は避け、AWSのマネージドな抽象化層(ALB, NATゲートウェイ等)の裏側にリソースを配置することが、最大の防御策となります。

—

まとめ

パケットは嘘をつきません。しかし、私たちが組んだネットワークの「意図」と、AWSのハイパーバイザー層が持つ「ステートの記憶」に食い違いが生じた瞬間、ネットワークは冷酷に通信を遮断します。

セキュリティグループのステートフルな挙動と非対称ルーティングの相性の悪さは、多くのインフラエンジニアが一度はハマる深い罠です。もしあなたが今、原因不明のパケットドロップやAPIの接続タイムアウトに悩まされているなら、コードのバグを疑う前に、「往路と復路で、パケットが同じ門(ENI・ルート)を通っているか?」を今一度、パケットの目線に立って見つめ直してみてください。

現場からは以上です。それでは、また次回のトラブルシューティングの現場でお会いしましょう。

コメント

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