NATゲートウェイとNACLの「ステートレス」という罠:現場でハマるパケットドロップの正体
クラウドインフラの設計において、プライベートサブネットからインターネットへ抜ける通信の要となるのが「NATゲートウェイ」です。しかし、このNATゲートウェイと、サブネットの門番である「ネットワークACL(NACL)」を組み合わせたとき、多くのエンジニアが「なぜか通信が疎通しない」という不可解な事象に頭を抱えます。
今回は、セキュリティグループ(SG)のような「ステートフル」な感覚でNACLを扱っていると確実に足元をすくわれる、NACLのステートレスな動作仕様と、実務で必須となるEphemeral Ports(一時ポート)設定の落とし穴について、現場視点で深く掘り下げます。
—
1. 「ステートフル」と「ステートレス」の決定的な違い
まず、心に刻んでおくべき大原則があります。セキュリティグループはステートフルですが、NACLはステートレスです。
- セキュリティグループ: 「行き」の通信を許可すれば、戻りのパケットは自動的に許可されます。コネクションの状態を追跡しているからです。
- ネットワークACL: パケットを「行き」と「帰り」の個別の通信として処理します。行きを許可しても、帰りのパケットがNACLのルールに合致しなければ、無慈悲にパケットは破棄(ドロップ)されます。
この「ステートレス」という仕様を理解していないと、NATゲートウェイ経由の通信で、なぜか外部APIへのリクエストは飛ぶのに、レスポンスが一切返ってこないという現象に遭遇することになります。
—
2. 戻りパケットの通り道:Ephemeral Portsの罠
プライベートサブネット内のリソース(EC2やFargateなど)から curl や Fetch API で外部Web APIを叩くとき、クライアント側(ソース側)はOSが自動的に割り当てた「一時ポート(Ephemeral Ports)」を使用します。
この戻りの通信を許可するには、NACLのインバウンドルールに「戻り先となる広範囲なポート番号」を明記しなければなりません。
具体的な設定例(AWSの例)
多くのLinux OS(Amazon Linux 2023やUbuntuなど)では、一時ポートの範囲として 1024-65535 を使用します。NACLのインバウンドルールには、以下のように設定する必要があります。
| ルール番号 | タイプ | プロトコル | ポート範囲 | 送信元 | アクション |
| :— | :— | :— | :— | :— | :— |
| 100 | カスタムTCP | TCP | 1024-65535 | 0.0.0.0/0 | 許可 |
なぜこの範囲が必要なのか?
NATゲートウェイから戻ってきたパケットは、送り先がプライベートサブネット内のインスタンスの「ランダムなポート番号」であるため、特定のポート(80や443など)に限定した許可では届かないからです。
—
3. 実践:Pythonで通信をテストする
実際にコードを書く際、疎通確認を兼ねて以下のようなスクリプトを動かしてみましょう。もしNACLの設定が不完全なら、タイムアウトが待っています。
import requests
# 外部のAPIを叩くテストコード
def test_outbound_connectivity():
url = "https://api.github.com"
try:
# このリクエストが出ると、OSは適当なポート(例: 49152)を割り当てる
response = requests.get(url, timeout=5)
print(f"Status Code: {response.status_code}")
except Exception as e:
# 通信がNACLで弾かれると、ここがタイムアウトになる
print(f"接続失敗: {e}")
if __name__ == "__main__":
test_outbound_connectivity()
このコードを実行して requests.exceptions.ConnectTimeout が発生する場合、ほぼ間違いなくNACLのインバウンド設定で戻りパケットがブロックされています。
—
4. 現場のシニアエンジニアからのTips
実務において、NACLの設定で混乱を避けるための「鉄則」を3つ共有します。
1. VPCフローログを活用する:
どうしても原因が不明な場合、VPCフローログを確認してください。REJECT されているパケットがあれば、それがどのIP、どのポートに向かおうとして拒否されたのかが明確になります。
2. NACLは「最後の砦」として扱う:
NACLはサブネット単位の強力な制御ですが、細かな制御はセキュリティグループに任せるのがクラウド設計の定石です。NACLは「許可の全開放」または「特定の不要なIPの拒否」といった、境界防御的な使い方に留めるのが、運用の複雑性を下げるコツです。
3. 一時ポートの範囲を確認する:
OSによっては一時ポートの範囲が異なる場合があります。念のため、以下のコマンドでカーネルパラメータを確認しておくと安心です。
# Linuxでの確認コマンド
sysctl net.ipv4.ip_local_port_range
出力が 32768 60999 であれば、NACLのインバウンドルールはこの範囲をカバーすれば十分です。
—
まとめ
NATゲートウェイ経由の通信において、NACLのステートレスな仕様は、慣れるまでは厄介な敵に見えます。しかし、パケットが「行き」と「帰り」で独立しているという事実に立ち返れば、なぜインバウンドルールに一時ポートの範囲が必要なのか、その論理的な必然性が見えてくるはずです。
「通信が繋がらない」と焦った時こそ、OSが動的に割り当てるポート番号に意識を向け、NACLのルール表を冷静に見直してみてください。その一歩が、トラブルシューティングの時間を劇的に短縮してくれます。
コメント