「なぜか通信が返ってこない…」を解決!ネットワークACL(NACL)の「ステートレス」な罠とエフェメラルポートの秘密
みなさん、こんにちは!メガクラウドやKubernetesのネットワークを日々いじり倒しているSREの技術ライターです。
クラウドインフラの構築を学び始めて、最初に誰もが「おや?」と首を傾げる瞬間があります。
それは、「セキュリティグループ(SG)とネットワークACL(NACL)って、何が違うの?」という疑問です。
「どちらも通信を許可したり拒否したりするファイアウォールでしょ?」と思うかもしれません。確かにその通りなのですが、この2つには「パケットの通し方」に決定的な違いがあります。
特に、パブリックサブネット(インターネットと直接やり取りする場所)でNACLを設定するとき、この違いを理解していないと、「外への通信は許可したはずなのに、なぜかアップデート(yum や apt)が途中でフリーズして進まない!」という、ネットワークの迷宮に迷い込んでしまうのです。
今回は、そんなインフラ初学者のみなさんに向けて、小難しいネットワークの専門用語を「郵便配達」や「マンションのセキュリティ」に例えながら、一歩ずつ丁寧に紐解いていきます。最後まで読めば、パケットがネットワークを往復する姿が手に取るようにイメージできるようになりますよ!
—
1. そもそも「セキュリティグループ」と「ネットワークACL」は何が違う?
まずは、この2つの防衛ラインを、現実世界の「マンションのセキュリティ」に例えてみましょう。
| サービス名 | 役割 | 例え話 | 特徴 |
| :— | :— | :— | :— |
| セキュリティグループ (SG) | インスタンス(サーバー)ごとの盾 | 各部屋のドアホンと鍵 | 部屋の住人が「入っていいよ」と言えば、帰りも自動で通れる(ステートフル) |
| ネットワークACL (NACL) | サブネット(エリア全体)の関所 | マンションの「エントランスの自動ドア」 | 行きも帰りも、毎回きっちり通行証をチェックされる(ステートレス) |
AWSなどのVPC(バーチャルなネットワーク空間)では、この2つが二重のセキュリティとして働いています。
そして、今回の主役である NACL(ネットワークACL) は、「ステートレス(状態を記憶しない)」という、ちょっと頑固で融通の利かない性質を持っています。これが、今回のトラブルの引き金になるのです。
—
2. 「ステートレス」ってどういうこと?
「ステート(State)」とは、通信の「状態」や「文脈」のことです。
セキュリティグループ(ステートフル)の場合
セキュリティグループはとても気が利きます。
あなたが部屋の中から「ピザを注文(外へのリクエスト)」したら、セキュリティグループは「あ、この部屋の人がピザを頼んだんだな」と記憶してくれます。
そのため、ピザ配達員(外からの返事)がやってきたときは、特に許可ルールを書いていなくても、自動的に部屋の中へ通してくれます。
ネットワークACL(ステートレス)の場合
一方で、NACLは超がつくほど頑固な門番です。
あなたが「ピザを注文(外へのリクエスト)」して門を出て行っても、NACLはその事実を一切記憶しません。
ピザ配達員が戻ってきたとき、NACLはこう言います。
> 「ん? お前は誰だ? 『外からマンション内に入るルール』に書いていない奴は、たとえ注文されたピザだろうが絶対に中には入れん!」
そう、ステートレスなNACLでは、「行き(アウトバウンド)」の通信を許可したら、必ず「帰り(インバウンド)」の通信もセットで明示的に許可ルールを書いてあげなければならないのです。
—
3. 「エフェメラルポート」という名の、帰り道専用ポスト
ここで、一つの疑問が浮かびます。
「Webサイトを見たいとき(HTTP通信)は、宛先ポート 80 や 443 を使いますよね。じゃあ、帰りの通信も 80 や 443 で返ってくるから、それを許可すればいいんですか?」
実は、ここが一番の落とし穴です!
郵便を出すときのことを想像してみてください。
- 宛先: 相手の住所(例:千代田区1-1)
- 差出人(あなた): 自分の住所(例:新宿区2-2)
相手が返事を書くときは、当然「あなたの住所」に向けて手紙を送り返しますよね。
ネットワークの世界でも全く同じです。サーバー(あなた)が外部のWebサイト(相手)にアクセスするとき、相手のポート(宛先)は 80 や 443 と決まっていますが、あなた自身の受け取り窓口(送信元ポート)は、その都度ランダムに用意された臨時のポートになります。
この、一時的に割り当てられる使い捨てのポート番号のことを、ネットワーク用語で「エフェメラルポート(Ephemeral Port)」と呼びます。
- エフェメラル(Ephemeral): 「はかない」「一時的な」という意味。
- ポートの範囲: 一般的に
1024から65535までの高位ポートが使われます。
つまり、パケットの往復はこうなっている!
あなたがパブリックサブネット内のサーバーから、外部のWebサイト(192.0.2.1)にお買い物リクエストを送るとします。
1. 行き(アウトバウンド):
- あなたのIPから、相手の
192.0.2.1の443ポート(HTTPS)へ出発。 - このとき、あなたのサーバーは「帰りの返事は、一時的に用意した
49152ポート で待ってるよ!」と手紙に書いておきます。
2. 帰り(インバウンド):
- 相手のサーバーから、あなたの
49152ポート 宛てに返事が届きます。
このとき、もしNACLの「インバウンド(帰り道)」の設定で、1024-65535(エフェメラルポート)からの通信を許可していなかったらどうなるでしょうか?
頑固な門番(NACL)に「そんなポート宛ての通信は通さん!」とパケットをゴミ箱に捨てられてしまい、あなたのサーバーにはいつまで経っても返事が届きません。これが「通信が繋がらない!」というトラブルの正体です。
—
4. 実践!パブリックサブネットのNACL設定レシピ
では、この仕組みを踏まえて、AWSなどのインフラをコードで管理するツール「Terraform(テラフォーム)」を使い、パブリックサブネット用の安全かつ正しいNACLの設定例を見てみましょう。
今回は、パブリックサブネット内のサーバーが「インターネット上のWebサイトにアクセスしたり、システムのアップデート(yumやapt)を安全に行えるようにする」ための、必要最低限かつ王道のNACL設定をご紹介します。
# ==============================================================================
# パブリックサブネット用のネットワークACL(NACL)定義
# ==============================================================================
resource "aws_network_acl" "public_nacl" {
vpc_id = aws_vpc.main.id
tags = {
Name = "my-public-nacl"
}
}
# ------------------------------------------------------------------------------
# インバウンドルール(入ってくる通信の制御)
# ------------------------------------------------------------------------------
# ルール 100: インターネットからのWebアクセス(HTTP)を許可
resource "aws_network_acl_rule" "inbound_http" {
network_acl_id = aws_network_acl.public_nacl.id
rule_number = 100
egress = false # false = インバウンド(受信)
protocol = "tcp"
rule_action = "allow"
cidr_block = "0.0.0.0/0" # すべてのIPからの通信を許可
from_port = 80
to_port = 80
}
# ルール 110: インターネットからの安全なWebアクセス(HTTPS)を許可
resource "aws_network_acl_rule" "inbound_https" {
network_acl_id = aws_network_acl.public_nacl.id
rule_number = 110
egress = false
protocol = "tcp"
rule_action = "allow"
cidr_block = "0.0.0.0/0"
from_port = 443
to_port = 443
}
# ★超重要★ ルール 120: 外部に出て行った通信の「帰り道(返事)」を許可
# これがないと、サーバーが外にリクエストを送っても、返事を受け取れません!
resource "aws_network_acl_rule" "inbound_ephemeral" {
network_acl_id = aws_network_acl.public_nacl.id
rule_number = 120
egress = false
protocol = "tcp"
rule_action = "allow"
cidr_block = "0.0.0.0/0"
from_port = 1024 # エフェメラルポートの開始番号
to_port = 65535 # エフェメラルポートの終了番号
}
# ------------------------------------------------------------------------------
# アウトバウンドルール(出ていく通信の制御)
# ------------------------------------------------------------------------------
# ルール 100: 外部のWebサイトやアップデートサーバーへのアクセス(HTTP)を許可
resource "aws_network_acl_rule" "outbound_http" {
network_acl_id = aws_network_acl.public_nacl.id
rule_number = 100
egress = true # true = アウトバウンド(送信)
protocol = "tcp"
rule_action = "allow"
cidr_block = "0.0.0.0/0"
from_port = 80
to_port = 80
}
# ルール 110: 外部のWebサイトやアップデートサーバーへの安全なアクセス(HTTPS)を許可
resource "aws_network_acl_rule" "outbound_https" {
network_acl_id = aws_network_acl.public_nacl.id
rule_number = 110
egress = true
protocol = "tcp"
rule_action = "allow"
cidr_block = "0.0.0.0/0"
from_port = 443
to_port = 443
}
# ★超重要★ ルール 120: 外部からWebアクセス(80/443)された際の「返事の帰り道」を許可
# 外部のブラウザ(クライアント)が持つエフェメラルポートに向けて返事を送ります。
resource "aws_network_acl_rule" "outbound_ephemeral" {
network_acl_id = aws_network_acl.public_nacl.id
rule_number = 120
egress = true
protocol = "tcp"
rule_action = "allow"
cidr_block = "0.0.0.0/0"
from_port = 1024
to_port = 65535
}
この設定のポイント
- 双方向のペア設計:
「行き(アウトバウンド)」で 80 や 443 を開けたら、必ず「帰り(インバウンド)」で 1024-65535 のエフェメラルポートを開けています。
- 逆パターンも同様:
「外部からWebアクセスが来る(インバウンド 80 / 443)」なら、その返事を返すために「アウトバウンド 1024-65535」を開けています。
これが、ステートレスなNACLを正しく動かすための、美しい黄金律(ゴールデンルール)なのです。
—
5. まとめ:パケットの「帰り道」に想いを馳せよう
最後に、今回の重要な学びを3つのポイントでおさらいしましょう!
1. NACLは「ステートレス」:
行きと帰りの通信を、どちらも手動で許可する必要がある、融通の利かない「関所」です。
2. エフェメラルポートは「仮のポスト」:
通信を始めた側が、返事を受け取るために一時的に使う 1024-65535 のポート番号のこと。
3. 迷ったら「双方向」を確認:
「通信が通らない!」と思ったら、リクエストの宛先だけでなく、「その返事はどのポートを通って帰ってくるのか?」をイメージしてみましょう。
インフラの世界は一見すると複雑な記号や数字ばかりに見えますが、その本質は「手紙のやり取り(郵便配達)」と全く同じ、とてもシンプルで人間味あふれる仕組みでできています。
「パケットが迷子にならずに、無事に帰ってこられるかな?」
そんな風にパケットの帰り道に少しだけ想いを馳せてあげるだけで、あなたのネットワーク構築スキルは劇的に向上しますよ。
これからも、一歩ずつ一緒にインフラの楽しさを学んでいきましょう!応援しています!
コメント