概要
VPCピアリングは、2つのVPC間でプライベートIPアドレスを使った通信を可能にする機能です。例えば、アプリケーション用VPCとログ収集用VPCを分離しつつ、プライベートネットワーク経由でログを送信するといった構成で利用されます。
VPCピアリング接続自体は正常に確立されているにもかかわらず、通信ができないというトラブルは実務でも試験でも頻出のシナリオです。原因として多いのが、ルートテーブルの設定漏れとセキュリティグループのインバウンドルール不足です。特にセキュリティグループについては、ピアリング接続の両端のVPCでそれぞれ適切なルールを設定する必要があり、片方のVPCのルール設定を見落としがちです。
本記事では、2つのVPCをピアリング接続した環境で、セキュリティグループのインバウンドルール不足により通信が失敗するケースを再現し、ルールを追加して通信が復旧するまでの手順を確認します。VPC Flow Logsも活用して、通信の成功・失敗をログレベルで確認します。

この記事のメリット
- VPCピアリング環境で必要なルートテーブルとセキュリティグループの設定を理解できる
- セキュリティグループのインバウンドルール不足による通信失敗を実機で確認できる
- 通信失敗時のトラブルシューティング手順(セキュリティグループの確認→ルール追加→通信確認)を習得できる
- VPC Flow Logsを使った通信の成功・失敗の確認方法を把握できる
- SCS試験でVPCピアリング環境のセキュリティグループに関する問いに正確に答えられるようになる
技術解説
VPCピアリングの通信要件
VPCピアリングを使った通信を成立させるには、ピアリング接続の確立に加えて、以下の設定が必要です。
| 設定項目 | 説明 |
|---|---|
| ルートテーブル | 両方のVPCのルートテーブルに、相手VPCのCIDRブロックへのルートをピアリング接続をターゲットとして追加する |
| セキュリティグループ | 通信を受信する側のインスタンスのセキュリティグループに、送信元からのインバウンドルールを追加する |
| ネットワークACL | 必要に応じて、サブネットのネットワークACLで通信を許可する(デフォルトACLはすべて許可) |
ルートテーブルの設定
VPCピアリング接続を確立しただけでは、VPC間でトラフィックはルーティングされません。各VPCのルートテーブルに、相手VPCのCIDRブロックを宛先としてピアリング接続をターゲットに指定するルートを追加する必要があります。
flowchart LR
subgraph VPCA["VPC A (10.0.0.0/16)"]
RTA["ルートテーブル<br/>━━━━━━━━━━<br/>10.0.0.0/16 → local<br/><b>10.1.0.0/16 → pcx-xxxxxxxx</b>"]
end
PCX{{"VPC ピアリング接続<br/>pcx-xxxxxxxx"}}
subgraph VPCB["VPC B (10.1.0.0/16)"]
RTB["ルートテーブル<br/>━━━━━━━━━━<br/>10.1.0.0/16 → local<br/><b>10.0.0.0/16 → pcx-xxxxxxxx</b>"]
end
RTA -->|"宛先 10.1.0.0/16<br/>(VPC B 宛)"| PCX
PCX -->|"宛先 10.0.0.0/16<br/>(VPC A 宛)"| RTA
RTB -->|"宛先 10.0.0.0/16<br/>(VPC A 宛)"| PCX
PCX -->|"宛先 10.1.0.0/16<br/>(VPC B 宛)"| RTB
classDef vpc fill:#eef6ff,stroke:#4a90d9
classDef pcx fill:#fff3e0,stroke:#e8a33d,font-weight:bold
class VPCA,VPCB vpc
class PCX pcxルートテーブルの設定は 双方向 に必要です。片方のVPCだけにルートを追加しても、応答パケットが戻れないため通信は成立しません。
セキュリティグループの双方向設定
VPCピアリング環境では、通信の方向に応じて各インスタンスのセキュリティグループを適切に設定する必要があります。
以下のシナリオを考えます。
flowchart LR
WEB(["web-server<br/>VPC A (10.0.0.0/16)"])
PCX{{"VPC ピアリング接続<br/>pcx-xxxxxxxx"}}
LOG(["log-server<br/>VPC B (10.1.0.0/16)"])
WEB -->|"ログ送信"| PCX --> LOG
LOG -.->|"応答(自動)"| WEBこの場合に必要なセキュリティグループの設定は以下の通りです。
| インスタンス | 方向 | ルール |
|---|---|---|
| web-server | アウトバウンド | log-serverのIPアドレス(またはVPC BのCIDR)への通信を許可 |
| log-server | インバウンド | web-serverのIPアドレス(またはVPC AのCIDR)からの通信を許可 |
セキュリティグループはステートフルであるため、インバウンドルールで許可した通信の応答トラフィックは自動的に許可されます。しかし、通信を受信する側にインバウンドルールがなければ、そもそも通信が拒否されるため、応答も発生しません。
ピアリング先のセキュリティグループ参照
同一VPC内ではセキュリティグループIDを参照してルールを定義できますが、VPCピアリング環境でもピアリング先VPCのセキュリティグループIDを参照することが可能です。ただし、ピアリング先のセキュリティグループを参照するには、VPCピアリング接続のオプションで「リモートセキュリティグループの参照を有効にする」設定が必要です。
CIDRブロックで指定する方法と比較すると、セキュリティグループ参照にはIPアドレスの変更に影響されないというメリットがあります。
VPC Flow Logsによる通信確認
VPC Flow Logsは、VPC内のネットワークインターフェイスを通過するIPトラフィックの情報をキャプチャします。Flow Logsの action フィールドで通信の許可(ACCEPT)または拒否(REJECT)を確認できるため、セキュリティグループやネットワークACLのルール設定が正しいかどうかのトラブルシューティングに活用できます。
実践
ここでは、2つのVPCをVPCピアリングで接続した環境で、セキュリティグループのインバウンドルール不足による通信失敗を確認した後、ルールを追加して通信を復旧させます。
前提条件
- リージョン:
ap-northeast-1(東京) - 以下のリソースが作成済みであること
| リソース種別 | リソース名 | 用途 |
|---|---|---|
| VPC | vpc-a (10.0.0.0/16) | web-server用VPC |
| VPC | vpc-b (10.1.0.0/16) | log-server用VPC |
| パブリックサブネット | vpc-a-public-subnet | web-server配置用 |
| パブリックサブネット | vpc-b-public-subnet | log-server配置用 |
| VPCピアリング接続 | vpc-a-to-vpc-b | 2つのVPC間の接続 |
| EC2インスタンス | web-server | VPC A内のWebサーバー |
| EC2インスタンス | log-server | VPC B内のログサーバー |
| セキュリティグループ | web-server-sg | SSHのみインバウンド許可(VPC Bからのインバウンドルールなし=トラブル対象) |
| セキュリティグループ | log-server-sg | web-serverからのインバウンド許可 |
VPCピアリング接続の確認
AWSマネジメントコンソールにログインし、リージョンが ap-northeast-1(東京)であることを確認します。
上部の検索バーに VPC と入力し、表示された「VPC」を選択します。
左側ナビゲーションの「ピアリング接続」を選択します。
vpc-a-to-vpc-b という名前のピアリング接続が表示され、ステータスが「アクティブ」であることを確認します。

ルートテーブルの確認
左側ナビゲーションの「ルートテーブル」を選択します。
vpc-a-public-rt を選択し、「ルート」タブを確認します。以下のルートが設定されていることを確認します。
10.0.0.0/16→ ターゲット:local10.1.0.0/16→ ターゲット:pcx-xxxxxxxx(ピアリング接続)0.0.0.0/0→ ターゲット:igw-xxxxxxxx(インターネットゲートウェイ)

同様に vpc-b-public-rt を選択し、VPC AのCIDRブロック 10.0.0.0/16 へのルートがピアリング接続をターゲットとして設定されていることを確認します。
通信失敗の確認
セキュリティグループはステートフルなため、web-serverが通信を開始する場合(web-server→log-server)は、応答パケットがweb-server-sgのインバウンドルールになくても自動的に許可されます。問題が顕在化するのは、log-server側が通信を開始するケース(log-server→web-server)です。ここではその方向で通信を試します。
log-serverにSSHで接続し、web-serverのプライベートIPアドレスに対して通信を試みます。
ssh -i ~/.ssh/luxy_common.pem ec2-user@<log-server-public-ip>log-server上で、web-serverのプライベートIPアドレスに対してpingを実行します。
ping -c 3 <web-server-private-ip>web-server-sgにVPC B(log-server)からのインバウンドルールが存在しないため、pingの応答が返りません(タイムアウトします)。
PING 10.0.1.xx (10.0.1.xx) 56(84) bytes of data.
--- 10.0.1.xx ping statistics ---
3 packets transmitted, 0 received, 100% packet loss, time 2003ms同様に、curlコマンドでweb-serverのポート80への接続を試みます。
curl -m 5 http://<web-server-private-ip>:80こちらもタイムアウトします。
curl: (28) Connection timed out after 5001 millisecondsセキュリティグループの確認
通信が失敗する原因を確認するため、web-server-sgのインバウンドルールを確認します。
上部の検索バーに EC2 と入力し、表示された「EC2」を選択します。
左側ナビゲーションの「ネットワーク&セキュリティ」→「セキュリティグループ」を選択します。
web-server-sg を選択し、「インバウンドルール」タブを確認します。
SSHのみが許可されており、VPC BのCIDR(10.1.0.0/16、log-server側)からのインバウンドルールが存在しないことが確認できます。

次に、log-server-sg を選択し、「インバウンドルール」タブを確認します。
log-server-sgには、VPC AのCIDRブロック(10.0.0.0/16)からのICMPとTCPの通信が許可されていることを確認します。

ここで問題が明確になります。log-server-sgはweb-serverからの通信を受け入れる設定になっていますが、web-server-sgにはlog-serverが開始する通信を受け入れるルールがありません。
Note: セキュリティグループはステートフルなため、web-serverが通信を開始する場合(web-server→log-server)、web-server-sgのアウトバウンドで許可されていれば応答パケットは自動的に許可されます。一方、log-serverが通信を開始する場合(log-server→web-server)は、web-server-sg側のインバウンドルールで明示的に許可されていない限り、その通信はブロックされます。双方向の通信(log-serverからweb-serverへのデータ送信など)が必要な構成では、この点が問題になります。
セキュリティグループへのインバウンドルール追加
web-server-sgにlog-serverからの通信を許可するインバウンドルールを追加します。
web-server-sg を選択した状態で、「インバウンドルール」タブの「インバウンドルールを編集」をクリックします。
「ルールを追加」をクリックし、以下を入力します。
- タイプ:
すべての ICMP - IPv4 - ソース:
10.1.0.0/16(VPC BのCIDR) - 説明:
ICMP from VPC B (log-server)
もう一度「ルールを追加」をクリックし、以下を入力します。
- タイプ:
カスタム TCP - ポート範囲:
0 - 65535 - ソース:
10.1.0.0/16(VPC BのCIDR) - 説明:
TCP from VPC B (log-server)
セキュリティグループのルールの説明には、日本語などのマルチバイト文字は使用できません(使用できるのは半角英数字と一部の記号のみ)。説明は半角英字で入力します。

「ルールを保存」をクリックします。
インバウンドルール一覧に、追加したルールが表示されることを確認します。

通信復旧の確認
再度log-serverにSSHで接続し、web-serverへの通信を確認します。
ping -c 3 <web-server-private-ip>今度はpingの応答が返ることを確認します。
PING 10.0.1.xx (10.0.1.xx) 56(84) bytes of data.
64 bytes from 10.0.1.xx: icmp_seq=1 ttl=255 time=0.5 ms
64 bytes from 10.0.1.xx: icmp_seq=2 ttl=255 time=0.4 ms
64 bytes from 10.0.1.xx: icmp_seq=3 ttl=255 time=0.4 ms
--- 10.0.1.xx ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 0.400/0.433/0.500/0.047 ms通信が復旧したことが確認できます。
VPC Flow Logsでの通信確認
VPC Flow Logsで通信の成功・失敗をログレベルで確認します。
上部の検索バーに CloudWatch と入力し、表示された「CloudWatch」を選択します。
左側ナビゲーションの「ログ」→「ロググループ」を選択します。
/aws/vpc-peering-lab/flowlogs を選択します。
ログストリーム一覧から、web-serverのENIに対応するログストリームを選択します(ENI IDは eni- で始まります)。
セキュリティグループ修正前のログでは、log-serverのIPアドレスからの通信が REJECT になっていることが確認できます。
2 123456789012 eni-xxxx 10.1.1.xx 10.0.1.xx 0 0 1 1 84 1711111111 1711111115 REJECT OK
セキュリティグループ修正後のログでは、同じ通信が ACCEPT に変わっていることが確認できます。
2 123456789012 eni-xxxx 10.1.1.xx 10.0.1.xx 0 0 1 1 84 1711111116 1711111120 ACCEPT OK

まとめ
- VPCピアリング接続が「アクティブ」であっても、ルートテーブルとセキュリティグループの設定が双方のVPCで正しくなければ通信は成立しない
- VPCピアリング環境で通信できない場合、まず確認すべきは以下の3点である
- ピアリング接続のステータスが「アクティブ」であること
- 両方のVPCのルートテーブルに相手VPCのCIDRへのルートが設定されていること
- 通信を受信する側のセキュリティグループに適切なインバウンドルールが設定されていること
- セキュリティグループはステートフルだが、通信を受信する側にインバウンドルールがなければ通信は拒否される
- VPC Flow Logsの
actionフィールド(ACCEPT/REJECT)で、セキュリティグループやネットワークACLによる通信の許可・拒否を確認できる - ピアリング先のセキュリティグループIDを参照することも可能だが、オプションで有効化が必要である
