【実務・中級編】 VPCピアリング接続(VPC Peering)の推移的ルーティング(Transitive Routing)の制限 – クラウド&コンテナネットワーク実践ガイド

VPCピアリングの「推移的ルーティング禁止」という壁:メッシュ構造の罠と現実解

こんにちは、シニアSREの私です。これまでに幾度となく、本番環境のネットワーク設計ミスによる障害対応や、夜間でのルートテーブルの総見直しを経験してきました。

クラウドインフラの設計において、VPC(Virtual Private Cloud)の切り分けは最初期に行う重要なステップです。しかし、事業の拡大とともにマイクロサービスが増殖し、「VPCを分けすぎて通信ができなくなった」「なぜか特定のパスだけパケットがブラックホールに消える」という悲鳴を、後輩エンジニアから何度聞いてきたことでしょう。

今回は、AWSのVPCピアリング(GCPのVPCネットワークピアリングも同等ですが、今回は最もよくあるAWSをベースに話を進めます)における最大の罠、「推移的ルーティング(Transitive Routing)の非サポート」について、パケットの挙動から実際のルーティング設計、そして現代的な回避策まで、現場の知見を交えて徹底解説します。

—

1. なぜ「A→B→C」の通信はできないのか?(アーキテクチャの制約)

まず大前提として、VPCピアリング接続は非推移的(Non-transitive)です。

文字だけだと抽象的なので、次のようなよくある構成を想像してください。

  • VPC-A (10.1.0.0/16): フロントエンド層
  • VPC-B (10.2.0.0/16): バックエンド層(APIサーバー)
  • VPC-C (10.3.0.0/16): データストア層(DB)

ここで、「VPC-A と VPC-B」「VPC-B と VPC-C」の間でそれぞれVPCピアリングを結びました。このとき、多くの初心者が「VPC-Bを経由すれば、VPC-AからVPC-Cのデータベースにアクセスできるだろう」と考えます。

結論から言うと、VPC-AからVPC-Cへの通信は失敗します。

パケットの旅路:なぜ途中でドロップされるのか?

AWSのVPCピアリングのデータプレーンは、L3ルーター同士を直接ケーブルで直結したような構造をしています。

1. VPC-A内のEC2インスタンスから、VPC-C内のDB(10.3.x.x)宛てのパケットが送信される。
2. VPC-Aのルートテーブルを確認。「10.3.0.0/16 へのルートはないが、10.2.0.0/16 宛てならピアリング先のVPC-Bへ投げろ」という設定があれば、パケットはVPC-Bへ到達する。
3. パケットがVPC-Bに到着する。しかし、VPC-Bのルーターにとって、そのパケットの宛先は「自分自身(VPC-BのCIDR)」ではなく、あくまでVPC-Cのものである。
4. VPC-Bの仮想ルーターは、「受信したVPCピアリング経由のパケットを、別のVPCピアリング(あるいは他のインターフェイス)へ転送(ルーティング)してはならない」というAWSの厳格なハードウェアレベルのセキュリティポリシーに基づき、そのパケットを容赦なくドロップ(破棄)する。

これが、推移的ルーティングが禁止されている理由です。「ルーターのバケツリレー」はVPCピアリングでは許可されていないのです。

—

2. フルメッシュ構造の限界とルートテーブル設計の現実

「じゃあ、VPC-AからVPC-Cに直接通信させたいなら、VPC-AとVPC-Cの間もピアリングを結べばいいじゃないか」となりますよね。

はい、その通りです。VPCが3つ程度であれば、すべての組み合わせでピアリングを結ぶ「フルメッシュ構造」で解決できます。

フルメッシュの計算式

VPCの数を $N$ とすると、必要なピアリング接続の数は以下の式で爆発的に増加します。

$$\frac{N \times (N – 1)}{2}$$

  • VPCが 3つ の場合: $3 \times 2 / 2 = 3$ 本
  • VPCが 5つ の場合: $5 \times 4 / 2 = 10$ 本
  • VPCが 10個 の場合: $10 \times 9 / 2 = 45$ 本

現場でVPCが10個を超えてくると、もはや管理しきれない「スパゲッティ・ネットワーク」の完成です。どのVPCとどのVPCが繋がっているのか、ルートテーブルには何行のルートを書けばいいのか、誰も把握できなくなります。

実務でのルートテーブル設定例(Terraform風)

もし小規模な構成でピアリングとルートテーブルを構築する場合、TerraformなどのIaCでは次のように記述します。ここで重要なのは、宛先CIDRとピアリングID(pcx-xxxxxxxx)の正確なマッピングです。

# VPC-A のルートテーブル設定
resource "aws_route" "from_a_to_b" {
  route_table_id         = aws_route_table.rt_vpc_a.id
  destination_cidr_block = "10.2.0.0/16" # VPC-BのCIDR
  vpc_peering_connection_id = aws_vpc_peering_connection.a_to_b.id
}

# ⚠️ 注意: VPC-AからVPC-Cへのルートを VPC-B を経由して書こうとしても、
# AWS側でバリデーションエラーになるか、通信が通らないデッドルートになります。

もしVPC-AからVPC-Cへ通信させたいのであれば、次のようにVPC-Aのルートテーブルに直接VPC-Cへのピアリングを向ける必要があります。

# VPC-A から VPC-C への直接ルート(フルメッシュ化)
resource "aws_route" "from_a_to_c" {
  route_table_id         = aws_route_table.rt_vpc_a.id
  destination_cidr_block = "10.3.0.0/16" # VPC-CのCIDR
  vpc_peering_connection_id = aws_vpc_peering_connection.a_to_c.id
}

—

3. デバッグの現場から:パケットが消えたときのトラブルシューティング

「設定したはずなのに、API通信がタイムアウトする」
そんなとき、SREが現場で踏むべきステップを再現します。Pythonの requests や curl で疎通確認をしつつ、ネットワーク層のどこで止まっているかを切り分けます。

ステップ1: セキュリティグループとネットワークACLの確認

VPCピアリングを越える通信では、送信元と宛先の「セキュリティグループ(SG)」が通信を許可している必要があります。「IPアドレスだけで許可したつもり」で、SGの送信元に相手VPCのCIDR(例: 10.1.0.0/16)ではなく、自身のSGを指定しているミスは新人・ベテラン問わず本当によくあります。

ステップ2: ルートテーブルの双方向性の確認

VPCピアリングは、「往復のルート」が両方のVPCで正しく設定されている必要があります。
VPC-AからVPC-Bへのルートがあっても、VPC-BからVPC-Aへの返り値(Return Traffic)のルートがVPC-B側のルートテーブルにないと、パケットは行きは良くても帰れなくなります。

ステップ3: PythonスクリプトによるAPI疎通とタイムアウト検知

バックエンドAPIの死活やルーティング起因のタイムアウトを切り分けるため、実務では次のような簡単なPythonスクリプトでステータスや例外をキャッチします。

import requests
from requests.exceptions import Timeout, ConnectionError

# VPC-B上のAPIサーバーのエンドポイント(内部ALBやEC2のプライベートIP)
API_ENDPOINT = "http://10.2.10.50:8080/healthz"

def check_vpc_connectivity():
    try:
        # タイムアウトを3秒に設定し、ルーティング障害によるハングを防ぐ
        response = requests.get(API_ENDPOINT, timeout=3.0)
        
        print(f"ステータスコード: {response.status_code}")
        print(f"レスポンスボディ: {response.text}")
        
    except Timeout:
        [1]
        print("【CRITICAL】接続がタイムアウトしました。")
        print("原因の切り分け:")
        print("  - VPCピアリングのルートテーブル(往復)は正しいですか?")
        print("  - セキュリティグループで相手のCIDRが許可されていますか?")
        
    except ConnectionError as e:
        print(f"【ERROR】接続に失敗しました: {e}")
        print("原因の切り分け:")
        print("  - 宛先のIP/ポートでアプリケーションがリスニングしていますか?")
        print("  - ネットワークACLでブロックされていませんか?")

if __name__ == "__main__":
    check_vpc_connectivity()

—

4. 現代的な解決策:AWS Transit Gateway (TGW) への移行

VPCの数が5個を超えたり、オンプレミス環境や複数リージョンとの接続が絡んできたりした瞬間、VPCピアリングのフルメッシュ構成は破綻します。

ここで登場するのが AWS Transit Gateway (TGW) です。

TGWがもたらす「推移的ルーティング」の解放

Transit Gatewayは、いわば「クラウド時代の巨大なハブ&スポーク型ルーター」です。

  • すべてのVPC(スポーク)を1つのTransit Gateway(ハブ)に接続する。
  • TGWのルートテーブル機能により、「VPC-A → TGW → VPC-B → TGW → VPC-C」という推移的ルーティングが完全にサポートされる。
  • VPCが増えても、TGWとの間にアタッチメントを1本追加し、ルートテーブルを1行追加するだけで済む。

構成変更の判断基準

  • VPCピアリングを選ぶべきケース:
  • VPCが2〜3個程度で、特定の2地点間を直接、高スループット・低コスト(追加のハブ料金なし)でつなぎたい場合。
  • Transit Gatewayを選ぶべきケース:
  • VPCが4個以上あり、今後もスケールする予定がある場合。
  • 複数のAWSアカウントや、VPN/Direct Connect(オンプレミス)を含めた全社ネットワークを統合管理したい場合。

—

まとめ:クラウドネットワーク設計の要諦

VPCピアリングの推移的ルーティングの制限は、一見すると「不便な足かせ」のように感じられます。しかし、これは巨大なクラウドインフラにおいて、意図しないループやルーティングの複雑化を防ぐための堅実なアーキテクチャ上の制約です。

「とりあえずピアリングを繋ぎまくればいいや」という場当たり的な設計は、数ヶ月後に必ず自分たちを苦しめる負債になります。システムの成長を見越し、適切なタイミングでTransit Gatewayなどのハブ型アーキテクチャへ移行する決断こそが、シニアSREとしての腕の見せ所です。

ネットワークのパケットの流れを頭の中でイメージできるようになれば、クラウドインフラの障害シューティングは怖くありません。今日も安全で堅牢なネットワークを構築していきましょう!

コメント

タイトルとURLをコピーしました