クラウドの世界へようこそ。AWSのVCPやGCPのVPC、そしてKubernetesのポッドネットワークを横断しながら、「パケットの気持ち」になってインフラの挙動を追うのが我々SREの醍醐味だ。
今日は、クラウドネットワークの基本中の基本でありながら、いまだに「なぜこのルートテーブルが必要なのか」「パケットは境界線でどう化けるのか」という本質を見落としがちなテーマを取り上げる。
「パブリックサブネットの定義とインターネットゲートウェイ(IGW)の接続」だ。
教科書通りの「パブリック=外からアクセスできる場所」というフワッとした理解を捨て、ルーティングの数学的必然性と、NATゲートウェイやIGWが裏で行っている泥臭いパケット書き換え(SNAT/DNAT)のリアルな挙動を、現場の視点から徹底的に解き明かしていこう。
—
1. パブリックサブネットとは何か?「パブリック」の正体を暴く
まず大前提として、クラウドのVPC内において、サブネット自体に「パブリック」「プライベート」という魔法のフラグが最初から焼き付けられているわけではない。
AWSのVPCやGCPのVPCを思い出してほしい。サブネットを作成するときに指定するのは、単にCIDRブロック(例: 10.0.1.0/24)だけだ。では、何がそのサブネットを「パブリック」たらしめているのか?
答えはシンプル。「インターネットゲートウェイ(IGW)へのルート(経路)を持つルートテーブルが関連付けられているかどうか」、これだけだ。
プライベートサブネットとの決定的な違い
- プライベートサブネット: トラフィックの宛先がVPC内(
local)か、せいぜい同一リージョン内のVPCピアリングやTGW(Transit Gateway)に限られており、デフォルトルート(0.0.0.0/0)の向け先がNATゲートウェイや仮想プライベートゲートウェイを向いている。 - パブリックサブネット: ルートテーブルに
0.0.0.0/0のターゲットとして IGW が明示的に設定されている。
つまり、「パブリックサブネット」とは、外の世界(インターネット)へ直接パスポートなしで飛び出せる片道切符、あるいは世界中から直接キャッチボールができるグラウンドのようなものだ。
—
2. パケットの往復運動:IGWの接続とルーティングの裏側
パブリックサブネットにあるリソース(例えば、Nginxを動かしているEC2インスタンス)に、インターネット上のユーザーがアクセスするシーンを想像してほしい。ここで不可欠なのが、ルーティングとアドレス変換(NAT)のコンビネーションだ。
シーケンス:パケットがIGWを通過する瞬間
1. クライアントからのリクエスト(外 → 中)
- ユーザーのブラウザから、パブリックIPアドレス(Elastic IP等)を持つEC2のプライベートIP宛てにTCP SYNパケットが飛ぶ。
- パケットは世界中のルーターをホップし、クラウドプロバイダーのEdgeルーターに到達。そこでIGWを通過する。
- この時、IGWは宛先IPアドレスをパブリックIPから、EC2が持つVPC内のプライベートIPアドレス(例:
10.0.1.100)に書き換える(DNAT: Destination NAT)。
2. EC2での処理とレスポンス(中 → 外)
- EC2は自身のIPが
10.0.1.100であると認識してリクエストを受け取り、Nginxがレスポンスを返す。 - 送信元IP
10.0.1.100、宛先IPはクライアントのパブリックIPとなる。 - パケットがパブリックサブネットのルートテーブルに従ってIGWに向かう。
3. IGWでのSNAT(Source NAT)
10.0.1.100というプライベートIPアドレスのままでは、グローバルインターネットの世界ではルーティングできない(RFC 1918で定められたプライベートIPはインターネット上にルーティングされないため)。- そこでIGWは、パケットの送信元IPを再びアタッチされているパブリックIP(Elastic IP等)に書き換える(SNAT)。
- これにより、クライアント側には「正しいサーバーから返事が返ってきた」ように見える。
—
3. 実務で直面する設定とインフラコード(Terraformの例)
言葉だけでは味気ないので、実際にIaC(Infrastructure as Code)でこの「パブリックサブネットとIGWの結びつき」をどう表現するのかを見ておこう。Terraformを使った標準的な構築コードだ。
# 1. VPCの作成
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "production-vpc"
}
}
# 2. インターネットゲートウェイ(IGW)の作成とVPCへのアタッチ
resource "aws_internet_gateway" "gw" {
vpc_id = aws_vpc.main.id
tags = {
Name = "production-igw"
}
}
# 3. パブリックサブネットの作成
resource "aws_subnet" "public" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.1.0/24"
availability_zone = "ap-northeast-1a"
# これをtrueにすることで、このサブネットで起動したインスタンスに自動でパブリックIPが付与される
map_public_ip_on_launch = true
tags = {
Name = "production-public-subnet-1a"
}
}
# 4. パブリック用ルートテーブルの作成
resource "aws_route_table" "public" {
vpc_id = aws_vpc.main.id
# デフォルトルート(0.0.0.0/0)の向け先をIGWに指定
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.gw.id
}
tags = {
Name = "production-public-rt"
}
}
# 5. ルートテーブルとパブリックサブネットの関連付け(Association)
resource "aws_route_table_association" "public" {
subnet_id = aws_subnet.public.id
route_table_id = aws_route_table.public.id
}
このコードの肝は、aws_route_table 内の route ブロックだ。ここに 0.0.0.0/0 と gateway_id を記述した瞬間から、このサブネットに紐づくすべてのリソースは、世界中と繋がるパブリックな存在へと生まれ変わる。
—
4. 現場のSREが教える「よくあるハマりポイント」とデバッグ手法
「コードを書いてIGWも紐付けたのに、外からつながらない!」
これは、夜間対応でSREが最も冷や汗をかく瞬間のひとつだ。だいたい犯人は以下のどれかに絞られる。
ハマりポイント1: セキュリティグループ(SG)とネットワークACL(NACL)の勘違い
パブリックサブネットにあるからといって、無防備に全開放されているわけではない。
- セキュリティグループ(ステートフル): インバウンドで許可した通信に対するアウトバウンドは、自動的に許可される(戻りのパケットを気にしなくてよい)。
- ネットワークACL(ステートレス): サブネット境界にある門番。インバウンドだけでなく、アウトバウンド(戻り通信のポート範囲:通常はエフェメラルポート
1024-65535)も明示的に許可しないと、パケットが外に出ていけない。 「外から来れるのに返事ができない」という現象の大半はNACLのエフェメラルポート抜けが原因だ。
ハマりポイント2: アプリケーション側のバインド設定
インフラ側でパケットがEC2まで届いていても、アプリが 127.0.0.1 (localhost) にしかリスンしていなかったら、外からのパケットは門前払いされる。
例えば、Node.jsやPythonのWeb APIサーバーを立ち上げるとき、次のように 0.0.0.0 (すべてのインターフェース)にバインドさせなければならない。
# Python (Flask) の正しいバインド例
from flask import Flask
app = Flask(__name__)
@app.route("/")
def health_check():
return {"status": "ok"}, 200
if __name__ == "__main__":
# 127.0.0.1 ではなく 0.0.0.0 を指定して外部からのアクセスを受け付ける
app.run(host="0.0.0.0", port=80)
デバッグ時の鉄板コマンド
もし疎通に悩んだら、感情的に設定をいじる前に、現場のエンジニアらしく論理的にパケットを追おう。パブリックサブネット内のインスタンスにSSH/SSMで入り、次のようなコマンドで現状をあぶり出す。
# 1. ちゃんと外(インターネット)にパケットが出ていけるか確認
curl -I https://api.ipify.org
# 2. どのポートで何が待ち受けているか(プロセスとバインドIPの確認)
sudo ss -tulpn | grep LISTEN
# 3. インターフェース単位でパケットのドロップやエラーが起きていないか確認
ip -s link
—
まとめ
パブリックサブネットとインターネットゲートウェイ(IGW)の関係は、一見するとただの「外への出口」に見える。だがその実態は、緻密なルーティングルールと、L3/L4レイヤーでのアドレス変換(SNAT/DNAT)が高速に、かつ透明に行われている巨大なルーター群の表れに他ならない。
インフラストラクチャを設計・運用する我々は、ただ動くものを作るのではなく、「今、パケットがどこを通り、どのゲートウェイでどう変換されているか」を脳内でビジュアライズできなければならない。
この基本原則さえ押さえておけば、どれほど複雑なマルチVPC環境やKubernetesのIngress制御が絡んできたとしても、迷うことなくトラブルシューティングの糸口が見つかるはずだ。さあ、今日も安全で堅牢なネットワークをデプロイしよう。
コメント