パブリックサブネットの正体:AWS VPCにおけるインターネット接続の「条件」とパケットの真実
こんにちは、SREチームのシニアエンジニアです。
クラウドインフラの設計をしていると、若手エンジニアから「パブリックサブネットに配置したはずのEC2インスタンスから外に出ていけない」「NATゲートウェイを置いたのにHTTPリクエストがタイムアウトする」といった相談を本当によく受けます。
AWSのマネジメントコンソールで「サブネットの作成」ボタンをポチポチ押しているだけだと、裏側でパケットがどうルーティングされ、IPアドレスがどう変換されているのかという本質が見えなくなりがちです。しかし、いざ本番環境で障害が起きたとき、あるいは高度なAPI連携やセキュリティ要件の監査に対応するときに頼りになるのは、パケットの挙動に対する解像度の高さです。
今回は、AWS VPCにおける「パブリックサブネット」の定義と、インターネット接続を成立させるための絶対不可欠な要件について、実務の現場で使える泥臭い知識とともにお話ししていきます。
—
1. パブリックサブネットとは何か?設計図の裏側にある「真の条件」
まず大前提として、AWSのVPC内部において、「サブネット自体が生まれながらにしてパブリックである」という仕様はありません。
コンソール上で「パブリックサブネット」というチェックボックスや選択肢があったとしても、それは単なるAWS側の親切なウィザード補助に過ぎません。AWSのネットワークレイヤーにおいて、あるサブネットが「パブリックサブネット」として機能するための条件は、以下の2つが厳密に満たされていることです。
1. インターネットゲートウェイ(IGW)がVPCにアタッチされていること
2. そのサブネットのルートテーブルに、IGW宛てのデフォルトルート(0.0.0.0/0)が存在すること
この2点のうち、どちらか片方でも欠けていれば、そのサブネットはただの「プライベートサブネット」です。いくらリソースにパブリックIPアドレスを割り当てようとも、外の世界へパケットを送り出すことはできません。
パケットの往復を支えるルートテーブルの現実
実務でよくあるミスが、「インターネットゲートウェイを作ったのに通信できない」というものです。ルートテーブルのルーティングエントリを思い出してください。
| 送信先 (Destination) | ターゲット (Target) |
| :— | :— |
| 10.0.0.0/16 | local |
| 0.0.0.0/0 | igw-xxxxxxxxxxxxxxxxx |
この 0.0.0.0/0(すべてのIPv4アドレス)に対するターゲットが、ローカルVPCではなく確実にインターネットゲートウェイ(igw-...)を向いていること。これがパブリックサブネットの生命線です。
—
2. IPアドレスの要件:パブリックIPとプライベートIPの二人三脚
パブリックサブネットに配置されるリソース(EC2やNATゲートウェイなど)には、ネットワーク通信を行うためにいくつかのIPアドレス要件が絡んできます。ここでRFCの仕様やAWS特有の挙動で混乱しがちなポイントを整理しておきましょう。
プライベートIPアドレス(RFC 1918)の必須性
パブリックサブネットに置かれるリソースであっても、VPC内の通信(ENI間通信)やAWS内部のサービス連携を行うためには、必ずRFC 1918に準拠したプライベートIPv4アドレス(例: 10.0.x.x や 172.16.x.x など)がアサインされています。
パブリックIP / Elastic IP (EIP) の要件
インターネット(VPCの外側)と直接通信を行う場合、宛先または送信元にグローバルIPアドレスが必要です。
- アウトバウンド(外向き)通信: パブリックサブネット内のリソースがインターネット上のWeb API等にアクセスする場合、そのリソースにパブリックIPv4アドレスまたはElastic IPが割り当てられているか、あるいは同じサブネット経由でNATゲートウェイ等を通る必要があります。
- インバウンド(外から入ってくる)通信: インターネット側から直接リソースにアクセスを叩き込む場合(パブリックなWebサーバーなど)、そのリソースのENI(Elastic Network Interface)にグローバルなパブリックIPアドレス(またはEIP)が紐づいている必要があります。
ここで重要なのは、「AWSのパブリックIPは、AWSのバーチャルルーターによってプライベートIPに1:1でNAT(ネットワークアドレス変換)されている」という点です。OS(Linux等)のネットワークインターフェース(eth0など)を ip a コマンドなどで確認すると、そこにバインドされているのはあくまでVPCのプライベートIPアドレスであり、パブリックIPはOSの知らないところでAWS基盤側(Hypervisor)によってマッピングされています。
—
3. 通信フローの全貌:パブリックサブネットから外の世界へ
実際にパブリックサブネットに配置されたアプリケーションから、インターネット上のWeb APIを叩くときの通信フロー(シーケンス)を追ってみましょう。
ここでは、Pythonスクリプトやcurlを使って外部APIを叩くシーンを想定します。
[EC2 (プライベートIP: 10.0.1.50)]
│
▼ (1. パケット送信: src=10.0.1.50, dst=93.184.216.34)
[VPC ルートテーブル参照] -> 0.0.0.0/0 は IGW へ
│
▼ (2. インターネットゲートウェイ (IGW))
[AWS ネットワーク基盤 (SNAT処理)]
-> プライベートIP (10.0.1.50) を パブリックIP (203.0.113.5) に変換
│
▼ (3. パブリックインターネット空間)
[外部 Web API サーバー]
現場で役立つデバッグTips
もしこの通信がタイムアウトする場合、以下のチェックリストを上から順に潰していくのがプロの現場の作法です。
1. セキュリティグループ (SG): アウトバウンドルール(Egress)で 0.0.0.0/0 の TCPポート 443 や 80 がブロックされていないか?(デフォルトでは全許可ですが、ガチガチに絞っている環境では要注意です)
2. ネットワークACL (NACL): ステートレスであるNACLの性質を忘れていませんか?インバウンドだけでなく、アウトバウンドのレスポンスパケット用のエフェメラルポート(TCP 1024-65535)が双方向で許可されているかを確認します。
3. ルートテーブル: サブネットに関連付けられているルートテーブルに 0.0.0.0/0 -> igw-xxxx が本当にあるか。
—
4. 実践:コードと設定ファイルからのアプローチ
では、実際にパブリックサブネット上で稼働するアプリケーションが、どのようにネットワークを意識して実装されるべきか、いくつかのコード例を見ていきましょう。
① Python (requests) による外部API呼び出し
パブリックサブネット上のEC2から外部APIを叩く最も一般的なコードです。タイムアウト設定を適切に入れることが、ネットワークトラブル時の連鎖障害(カスケード障害)を防ぐためのSREとしての鉄則です。
import requests
from requests.exceptions import RequestException
def call_external_api():
# 接続先外部APIのエンドポイント
api_url = "https://api.example.com/v1/data"
try:
# タイムアウト(接続に3秒、読み込みに5秒)を明示的に指定する
# これにより、IGWやネットワーク経路の障害時にスレッドが枯渇するのを防ぎます
response = requests.get(api_url, timeout=(3.0, 5.0))
# ステータスコードのチェック
response.raise_for_status()
print("API呼び出し成功:", response.json())
except RequestException as e:
# ネットワークレベルのエラーやタイムアウトをキャッチ
print(f"ネットワークエラーまたはタイムアウトが発生しました: {e}", file=sys.stderr)
if __name__ == "__main__":
call_external_api()
② curlによる接続テストとルーティング・パブリックIPの確認
インフラのデバッグ時、SSHやAWS Systems Manager (SSM) Session Managerでパブリックサブネット上のインスタンスにログインし、外向きの通信や自身のパブリックIPを直接確認するためのスニペットです。
# 1. 自身のインスタンスから外向きのグローバルIPが正しくNATされているか確認する
# (AWS基盤を抜けた先でどのように見えているかをチェック)
curl -s https://checkip.amazonaws.com
# 2. 任意の外部APIへHTTPSリクエストを送り、レスポンスヘッダーとHTTPステータスを確認する
# -I オプションでヘッダーのみを取得し、通信経路が正常か素早くテスト
curl -Iv https://postman-echo.com/get
③ Terraformによるパブリックサブネットの宣言的定義
最後に、インフラストラクチャ・アズ・コード(IaC)として、パブリックサブネットとインターネットゲートウェイ、ルートテーブルがどのように結びついているかをTerraformのコードで確認します。
# 1. インターネットゲートウェイの作成とVPCへのアタッチ
resource "aws_internet_gateway" "main" {
vpc_id = aws_vpc.main.id
tags = {
Name = "production-igw"
}
}
# 2. パブリックサブネットの作成
resource "aws_subnet" "public" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.1.0/24"
availability_zone = "ap-northeast-1a"
# これにより、このサブネット内で起動したインスタンスにデフォルトでパブリックIPが割り当てられます
map_public_ip_on_launch = true
tags = {
Name = "production-public-subnet-1a"
}
}
# 3. パブリックサブネット用のルートテーブルの作成
resource "aws_route_table" "public" {
vpc_id = aws_vpc.main.id
# すべてのトラフィック(0.0.0.0/0)をインターネットゲートウェイに向ける
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.main.id
}
tags = {
Name = "production-public-rt"
}
}
# 4. ルートテーブルとパブリックサブネットの関連付け(Association)
resource "aws_route_table_association" "public" {
subnet_id = aws_subnet.public.id
route_table_id = aws_route_table.public.id
}
このTerraformコードの構成こそが、AWSにおけるパブリックサブネットの定義そのものです。サブネット単体ではなく、「IGWの存在」「ルートテーブルでの 0.0.0.0/0 のルーティング」「アソシエーション」の3要素が揃って初めてパブリックサブネットが爆誕するということが、このコードからも美しく読み取れるはずです。
—
おわりに
パブリックサブネットの設計と運用は、クラウドネットワークの基本中の基本ですが、同時にセキュリティインシデント(不要な公開リソースの放置など)の温床になりやすいデリケートな領域でもあります。
「どこからパケットが来て、どこへ抜けていくのか」
「OSが認識しているIPと、AWS基盤がマッピングしているIPの違いは何か」
こうした裏側のメカニズムを頭に入れた上で設計・運用を行えば、トラブルシューティングのスピードは劇的に向上します。皆さんのインフラストラクチャが、今日も安全でスムーズなパケットの往復に満ちていることを願っています。
コメント