カスタムVPCのEC2インターネット接続不可を解決する — Internet GatewayとRoute Tableの設定手順

カスタムVPCを作成してパブリックサブネットにEC2インスタンスを起動したのに、ping google.comが通らない。この問題はVPC構築時に最もよく遭遇するトラブルで、原因はほぼ必ずInternet GatewayのアタッチかRoute Tableのルート設定の抜け漏れにある。デフォルトVPCと違い、カスタムVPCはこれらのリソースを明示的に構成しなければインターネット疎通は一切得られない。

TL;DR — EC2インターネット接続不可の原因と対処

確認レイヤーよくある原因対処
Internet Gateway作成済みだがVPCにアタッチされていないIGWをVPCにアタッチ
Route Table0.0.0.0/0のルートが存在しないIGWへのデフォルトルートを追加
サブネット関連付けパブリックサブネットがカスタムRoute Tableに関連付けられていないサブネットをRoute Tableに明示的に関連付け
パブリックIPアドレスインスタンスにパブリックIPが割り当てられていないサブネットの自動割り当て設定を有効化、またはElastic IPを割り当て
Security Groupアウトバウンドルールが制限されているアウトバウンド0.0.0.0/0を許可
Network ACLサブネットレベルのACLがトラフィックを拒否しているインバウンド/アウトバウンドルールを確認

カスタムVPCのインターネット接続がどのように機能するか

デフォルトVPCはAWSが自動的にIGWのアタッチとRoute Tableの設定を済ませた状態で提供される。カスタムVPCにはそれがない。EC2インスタンスがインターネットに到達するには、パケットが通過しなければならないレイヤーが複数存在する。

graph LR EC2["EC2インスタンス
パブリックIP必須"] --> SG["Security Group
ステートフル"] SG --> NACL["Network ACL
ステートレス"] NACL --> RT["Route Table
0.0.0.0/0 → IGW"] RT --> IGW["Internet Gateway
VPCにアタッチ済み"] IGW --> NET["インターネット"] style EC2 fill:#FF9900,color:#fff style IGW fill:#232F3E,color:#fff style RT fill:#1A73E8,color:#fff style NET fill:#34A853,color:#fff
  1. EC2インスタンス — パブリックIPが割り当てられていることが前提。なければパケットは返ってこない。
  2. Security Group (インスタンスレベル) — ステートフルなファイアウォール。アウトバウンドが許可されていればレスポンスは自動的に許可される。
  3. Route Table (サブネットレベル) — 0.0.0.0/0のルートがIGWを指していなければ、パケットはVPC内で行き場を失う。
  4. Network ACL (サブネットレベル) — ステートレスなフィルター。アウトバウンドとインバウンド両方のルールが必要。
  5. Internet Gateway — VPCにアタッチされていなければ、ルートが存在しても通信できない。
IGWはVPCの玄関ドアに相当する。Route Tableはその玄関への道順だ。どちらか一方が欠けていれば、もう一方が存在しても外には出られない。

EC2インターネット接続不可を診断する — 確認順序

問題を最短で特定するには、パケットが通過するレイヤーを外側から内側へ順番に確認する。IGWとRoute Tableから始めるのが効率的で、この2つで大半のケースが解決する。

graph TD START(["EC2 pingが通らない"]) --> CHK1{"IGWはVPCに
アタッチされているか?"} CHK1 -- No --> FIX1["IGWを作成/アタッチする"] CHK1 -- Yes --> CHK2{"Route Tableに
0.0.0.0/0ルートがあるか?"} FIX1 --> CHK2 CHK2 -- No --> FIX2["デフォルトルートを追加する"] CHK2 -- Yes --> CHK3{"サブネットは正しい
Route Tableに関連付けられているか?"} FIX2 --> CHK3 CHK3 -- No --> FIX3["サブネットをRoute Tableに関連付ける"] CHK3 -- Yes --> CHK4{"インスタンスに
パブリックIPがあるか?"} FIX3 --> CHK4 CHK4 -- No --> FIX4["EIPを割り当てる"] CHK4 -- Yes --> CHK5{"SGアウトバウンドは
許可されているか?"} FIX4 --> CHK5 CHK5 -- No --> FIX5["SGアウトバウンドルールを追加"] CHK5 -- Yes --> CHK6{"Network ACLは
通過を許可しているか?"} FIX5 --> CHK6 CHK6 -- No --> FIX6["ACLルールを修正する"] CHK6 -- Yes --> DONE(["接続確認: ping google.com"]) FIX6 --> DONE style START fill:#FF9900,color:#fff style DONE fill:#34A853,color:#fff

ステップ1 — Internet GatewayのVPCアタッチ状態を確認する

IGWが存在していてもVPCにアタッチされていなければ意味がない。detached状態のIGWはよく見落とされる。コンソールで作成した直後にアタッチを忘れるケースが多い。

# 対象VPCにアタッチされているIGWを確認
aws ec2 describe-internet-gateways \
  --filters 'Name=attachment.vpc-id,Values=vpc-0123456789abcdef0' \
  --query 'InternetGateways[*].{IGW_ID:InternetGatewayId,State:Attachments[0].State}' \
  --output table

出力に何も表示されない場合、またはStateがdetachedの場合はアタッチが必要だ。IGWが存在しない場合は作成から始める。

# IGWを作成する
aws ec2 create-internet-gateway \
  --tag-specifications 'ResourceType=internet-gateway,Tags=[{Key=Name,Value=my-igw}]'

# 出力されたInternetGatewayIdを使ってVPCにアタッチする
aws ec2 attach-internet-gateway \
  --internet-gateway-id igw-0123456789abcdef0 \
  --vpc-id vpc-0123456789abcdef0

ステップ2 — Route Tableにデフォルトルートを追加する

IGWがアタッチされていても、Route Tableに0.0.0.0/0 → IGWのルートがなければパケットはVPC内に閉じ込められる。まず対象サブネットがどのRoute Tableに関連付けられているかを確認する。

# サブネットに関連付けられているRoute Tableを確認
aws ec2 describe-route-tables \
  --filters 'Name=association.subnet-id,Values=subnet-0123456789abcdef0' \
  --query 'RouteTables[*].{RT_ID:RouteTableId,Routes:Routes}' \
  --output json

出力のRoutesの中にDestinationCidrBlock: 0.0.0.0/0のエントリが存在しない場合、またはサブネットがメインRoute Tableに暗黙的に関連付けられているだけの場合は、カスタムRoute Tableを作成してルートを追加する。

# カスタムRoute Tableを作成する
aws ec2 create-route-table \
  --vpc-id vpc-0123456789abcdef0 \
  --tag-specifications 'ResourceType=route-table,Tags=[{Key=Name,Value=public-rt}]'

# IGWへのデフォルトルートを追加する
aws ec2 create-route \
  --route-table-id rtb-0123456789abcdef0 \
  --destination-cidr-block 0.0.0.0/0 \
  --gateway-id igw-0123456789abcdef0

# パブリックサブネットをRoute Tableに関連付ける
aws ec2 associate-route-table \
  --route-table-id rtb-0123456789abcdef0 \
  --subnet-id subnet-0123456789abcdef0

ステップ3 — EC2インスタンスのパブリックIPアドレスを確認する

IGWとRoute Tableが正しく設定されていても、インスタンス自体にパブリックIPがなければインターネット側からの応答は返ってこない。これは見落としやすい。Route Tableを直した後に「まだ繋がらない」と悩む場合の多くはここが原因だ。

# インスタンスのパブリックIPアドレスを確認する
aws ec2 describe-instances \
  --instance-ids i-0123456789abcdef0 \
  --query 'Reservations[*].Instances[*].{InstanceId:InstanceId,PublicIP:PublicIpAddress,State:State.Name}' \
  --output table

PublicIPがNoneの場合、サブネットのパブリックIP自動割り当て設定を有効化するか、Elastic IPを割り当てる。

# サブネットのパブリックIP自動割り当てを有効化する
aws ec2 modify-subnet-attribute \
  --subnet-id subnet-0123456789abcdef0 \
  --map-public-ip-on-launch

# 既存インスタンスにはElastic IPを割り当てる
# まずElastic IPを確保する
aws ec2 allocate-address --domain vpc

# 出力されたAllocationIdを使ってインスタンスに関連付ける
aws ec2 associate-address \
  --instance-id i-0123456789abcdef0 \
  --allocation-id eipalloc-0123456789abcdef0

ステップ4 — Security Groupのアウトバウンドルールを確認する

Security Groupはステートフルなので、アウトバウンドが許可されていればレスポンスは自動的に許可される。ただし、セキュリティ強化のためにアウトバウンドを制限している場合は明示的な許可が必要になる。IGWとRoute Tableが正しくてもpingが通らないなら、ここを疑う。

# インスタンスのSecurity Groupを確認する
aws ec2 describe-instances \
  --instance-ids i-0123456789abcdef0 \
  --query 'Reservations[*].Instances[*].SecurityGroups' \
  --output json

# Security Groupのアウトバウンドルールを確認する
aws ec2 describe-security-groups \
  --group-ids sg-0123456789abcdef0 \
  --query 'SecurityGroups[*].{GroupId:GroupId,Outbound:IpPermissionsEgress}' \
  --output json

アウトバウンドルールが空またはHTTPS/HTTPのみに制限されている場合、ICMPを許可するルールを追加する。

# ICMPアウトバウンドを許可する (ping用)
aws ec2 authorize-security-group-egress \
  --group-id sg-0123456789abcdef0 \
  --protocol icmp \
  --port -1 \
  --cidr 0.0.0.0/0

ステップ5 — Network ACLのルールを確認する

Network ACLはステートレスなため、アウトバウンドとインバウンド両方のルールを個別に設定する必要がある。Security Groupと違い、レスポンストラフィックは自動的に許可されない。pingのレスポンス(ICMPタイプ0)が戻ってこない場合、ACLのインバウンドルールがブロックしている可能性がある。

# サブネットに関連付けられているNetwork ACLを確認する
aws ec2 describe-network-acls \
  --filters 'Name=association.subnet-id,Values=subnet-0123456789abcdef0' \
  --query 'NetworkAcls[*].{AclId:NetworkAclId,Entries:Entries}' \
  --output json

デフォルトのNetwork ACLはすべてのトラフィックを許可する。カスタムACLを使用している場合は、ICMPのインバウンド(エフェメラルポートを含む)とアウトバウンドの両方が許可されていることを確認する。

実際の障害パターン — IGWはアタッチ済みなのに繋がらない

IGWをVPCにアタッチしてRoute Tableにデフォルトルートも追加した。それでもpingが通らない。コンソールを見ると設定は正しそうに見える。こういうとき、次に疑うべきはサブネットとRoute Tableの関連付けだ。

カスタムRoute Tableを作成してルートを追加しても、サブネットをそのRoute Tableに明示的に関連付けなければ、サブネットはメインRoute Tableを使い続ける。メインRoute Tableにはデフォルトルートがない。コンソールでRoute Tableを見ると正しいルートが表示されているのに繋がらない、という状況の正体はこれだ。

# サブネットの現在のRoute Table関連付けを確認する
aws ec2 describe-route-tables \
  --filters 'Name=association.subnet-id,Values=subnet-0123456789abcdef0' \
  --query 'RouteTables[*].{RT_ID:RouteTableId,Main:Associations[0].Main}' \
  --output table

Main: trueが返ってきた場合、そのサブネットはメインRoute Tableに関連付けられている。カスタムRoute Tableへの明示的な関連付けが必要だ。ステップ2のassociate-route-tableコマンドを実行する。

設定変更後に接続を確認するには、EC2 Instance ConnectまたはSSMセッションマネージャーでインスタンスに接続してpingを実行する。

# SSM Session Managerで接続確認 (SSMエージェントが必要)
aws ssm start-session --target i-0123456789abcdef0

最小権限IAMポリシー — VPCネットワーク設定に必要な権限

VPCのネットワーク設定を行うオペレーターには、以下の権限が必要になる。本番環境では管理者権限を使わず、必要な権限のみを付与したロールを使うこと。

🔽 IAMポリシーを展開して確認する
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "VPCNetworkConfiguration",
      "Effect": "Allow",
      "Action": [
        "ec2:CreateInternetGateway",
        "ec2:AttachInternetGateway",
        "ec2:DetachInternetGateway",
        "ec2:DeleteInternetGateway",
        "ec2:DescribeInternetGateways",
        "ec2:CreateRouteTable",
        "ec2:CreateRoute",
        "ec2:DeleteRoute",
        "ec2:AssociateRouteTable",
        "ec2:DisassociateRouteTable",
        "ec2:DescribeRouteTables",
        "ec2:ModifySubnetAttribute",
        "ec2:DescribeSubnets",
        "ec2:AllocateAddress",
        "ec2:AssociateAddress",
        "ec2:DescribeAddresses",
        "ec2:DescribeInstances",
        "ec2:DescribeSecurityGroups",
        "ec2:AuthorizeSecurityGroupEgress",
        "ec2:DescribeNetworkAcls",
        "ec2:CreateTags"
      ],
      "Resource": "*"
    }
  ]
}

Read/Describe系のアクションはリソースレベルの制限をサポートしていないものが多く、"Resource": "*"が必要になる。Write系のアクションについては、AWS Service Authorization Referenceで各アクションがサポートするリソースタイプを確認した上で、可能な範囲でARN制限を追加することを推奨する。

EC2インターネット接続不可 — 完全な診断フロー

graph LR subgraph VPC["カスタムVPC"] subgraph PublicSubnet["パブリックサブネット"] EC2["EC2 パブリックIP"] NACL["Network ACL"] end RT["Route Table 0.0.0.0/0 → IGW"] SG["Security Group"] end IGW["Internet Gateway"] INET["インターネット"] EC2 --> SG --> NACL --> RT --> IGW --> INET style IGW fill:#232F3E,color:#fff style INET fill:#34A853,color:#fff style EC2 fill:#FF9900,color:#fff
  1. IGWがVPCにアタッチされているかを最初に確認する。ここが未設定なら後続の確認は不要。
  2. Route Tableに0.0.0.0/0のルートが存在し、かつ対象サブネットがそのRoute Tableに関連付けられているかを確認する。
  3. インスタンスにパブリックIPが割り当てられているかを確認する。
  4. Security Groupのアウトバウンドルールを確認する。
  5. Network ACLのインバウンド/アウトバウンド両方のルールを確認する。

まとめとネクストステップ — EC2インターネット接続の確立

カスタムVPCでEC2インターネット接続不可になる原因の大半は、IGWのアタッチ漏れ、Route Tableのデフォルトルート未設定、またはサブネットとRoute Tableの関連付け漏れの3つに集約される。パブリックIPの割り当て確認はその次に確認すべき項目だ。

本番環境でこの構成を管理する場合は、AWS CloudFormationまたはTerraformでインフラをコード化することで、手動設定の抜け漏れを防ぐことができる。また、プライベートサブネットのEC2インスタンスからインターネットへのアウトバウンド通信が必要な場合は、NAT GatewayをパブリックサブネットにデプロイしてRoute Tableを設定する構成が必要になる。

用語集

用語説明
Internet Gateway (IGW)VPCとインターネット間の通信を可能にする水平スケーリング対応のVPCコンポーネント。VPCに1つアタッチする。
Route Tableサブネット内のトラフィックのルーティングルールを定義するテーブル。各サブネットは1つのRoute Tableに関連付けられる。
パブリックサブネットIGWへのルートを持つRoute Tableに関連付けられたサブネット。インターネットへの直接疎通が可能。
Elastic IP (EIP)AWSアカウントに割り当てられる静的なパブリックIPアドレス。インスタンスの停止/起動後もIPアドレスが変わらない。
Network ACLサブネットレベルで動作するステートレスなパケットフィルター。インバウンドとアウトバウンドを個別に制御する。

コメント

このブログの人気の投稿

EC2 SSH接続タイムアウトの原因と修正方法 — セキュリティグループのインバウンドルール完全ガイド

S3パブリックアクセス拒否の原因と解決策:バケットレベルの「Block Public Access」が優先される仕組み

EC2インスタンスIDをメタデータから取得する方法 — IMDSv2が安全な理由