こんにちは。シニアSREの私です。
これまで数々の巨大なクラウドインフラを見てきましたが、マルチVPC、オンプレミス、そして複数リージョンが絡み合う大規模環境において、ネットワークの「ハブ」の設計を誤ると、後々地獄を見ることになります。VPCピアリングのメッシュ構造がスパゲッティ状に絡まり合い、「どのルートでパケットが流れているのか誰にもわからない」という悪夢のような状態に陥った経験はありませんか?
そんなカオスを華麗に解消してくれるのが AWS Transit Gateway (TGW) です。しかし、このTGW、非常に強力であるがゆえに、適当にデフォルトルートテーブルへ突っ込むだけでは、セキュリティも運用性もあったものではありません。
今回は、本番環境で確実に機能する「TGWアタッチメントとルートテーブル分離のベストプラクティス」について、現場の泥臭い知見とパケットの気持ちになりきった解説を交えてお伝えします。
—
なぜTGWのルートテーブル分離が「正義」なのか
初期のTGW設計でよくある失敗が、「すべてのVPCアタッチメントを、1つのデフォルトルートテーブルにぶら下げる」という構成です。これでは従来の全社共通フラットネットワークと何ら変わりません。
本番環境(Production)、検証環境(Staging)、共有サービス(Shared Services)、そして外部からのVPN接続。これらを同じ土俵に立たせるのは、セキュリティの観点から自殺行為です。例えば、検証環境の踏み台サーバーから、本番のデータベースVPCへパケットが到達できてしまう状態を想像してください。冷や汗が出ますよね。
ここで登場するのが、TGW独自のアタッチメント(Attachment)概念と、複数のTGWルートテーブルによる論理的分離(ルーティングドメインの形成)です。
TGWのルーティングの基本思想
1. アタッチメントはVPCやVPNをTGWに接続する「物理的(論理的)なプラグ」である。
2. TGWルートテーブルは「どのプラグから入ってきたパケットを、どのプラグへ流すか」の交通整理をする「交差点の信号機」である。
3. このプラグと信号機を多対多、あるいは意図的に切り離して紐付けることで、マルチテナントなネットワーク隔离(アイソレーション)を実現する。
—
実践! 堅牢なTGWルーティングドメイン設計
ここでは、実務で最もよく使われる3つのルーティングドメイン(ルートテーブル)に分離する設計モデルを解説します。
rtb-shared-services(共有基盤用)rtb-workloads(ワークロード用:本番・検証など)rtb-edge(インターネット・VPN/Direct Connect用)
アーキテクチャの全体像とパケットの動き
[ 本番VPC ] ──(Attachment A)──┐
├──> [ TGW Route Table: rtb-workloads ]
[ 検証VPC ] ──(Attachment B)──┘ │
▼ (共有サービスへの通信のみ許可)
[ 共有VPC (DNS/踏み台) ] ──────────> [ TGW Route Table: rt-shared-services ]
▲
[ Direct Connect / VPN ] ──(Edge)───┴──> [ TGW Route Table: rtb-edge ]
この分離モデルの肝は、「ワークロードVPC同士は直接通信させず、通信が必要な場合は必ず共有サービスVPC(プロキシやファイアウォール経由)を挟む」あるいは「エッジを経由させる」という鉄則をTGWのルートテーブルレベルで強制することです。
—
Terraformによるコード実装例
口で言うのは簡単です。実際にInfrastructure as Code (IaC) で、この分離されたTGW環境を構築するTerraformコードを見てみましょう。ここではAWS Providerを利用し、TGW本体、ルートテーブル、そしてVPCアタッチメントの紐付けを定義します。
# 1. AWS Transit Gateway 本体の作成
resource "aws_ec2_transit_gateway" "main" {
description = "Production Network Hub TGW"
amazon_side_asn = 64512
auto_accept_shared_attachments = "enable"
default_route_table_association = "disable" # デフォルトの紐付けは必ず無効化する(これがベストプラクティスの第一歩!)
default_route_table_propagation = "disable" # 伝播も無効化し、完全に手動制御下に置く
tags = {
Name = "tgw-prod-hub"
}
}
# 2. ルートテーブルの作成:ワークロード用(本番・検証など)
resource "aws_ec2_transit_gateway_route_table" "workloads" {
transit_gateway_id = aws_ec2_transit_gateway.main.id
tags = {
Name = "tgw-rtb-workloads"
}
}
# 3. ルートテーブルの作成:共有サービス用(DNS, 監視, 踏み台など)
resource "aws_ec2_transit_gateway_route_table" "shared" {
transit_gateway_id = aws_ec2_transit_gateway.main.id
tags = {
Name = "tgw-rtb-shared"
}
}
# 4. 本番VPCのアタッチメント
resource "aws_ec2_transit_gateway_vpc_attachment" "prod_vpc" {
transit_gateway_id = aws_ec2_transit_gateway.main.id
vpc_id = var.prod_vpc_id
subnet_ids = var.prod_tgw_subnet_ids
# DNSサポートは必要に応じて有効化
dns_support = "enable"
tags = {
Name = "tgw-attach-prod-vpc"
}
}
# 5. 本番VPCのアタッチメントを「workloads」ルートテーブルに関連付け(Association)
resource "aws_ec2_transit_gateway_route_table_association" "prod_assoc" {
transit_gateway_attachment_id = aws_ec2_transit_gateway_vpc_attachment.prod_vpc.id
transit_gateway_route_table_id = aws_ec2_transit_gateway_route_table.workloads.id
}
# 6. workloadsルートテーブルから共有サービスVPCへのルート伝播(Propagation)、または静的ルートの設定
# ワークロードから共有サービス(例: 10.100.0.0/16)への通信を許可する静的ルート
resource "aws_ec2_transit_gateway_route" "workloads_to_shared" {
transit_gateway_route_table_id = aws_ec2_transit_gateway_route_table.workloads.id
destination_cidr_block = "10.100.0.0/16" # 共有サービスVPCのCIDR
transit_gateway_attachment_id = aws_ec2_transit_gateway_vpc_attachment.shared_vpc.id
}
—
現場で役立つ! トラブルシューティングと運用のTips
実際に構築し、APIの疎通確認やコンテナ間の通信テストを行っていると、「あれ、パケットが返ってこないぞ?」という壁にぶぶつかります。SREが現場で必ず確認するチェックリストを共有します。
1. VPC側のルートテーブル(ルートエントリ)の確認忘れ
TGW側でいくらルートを綺麗に整備しても、VPC側のサブネットルートテーブルに 0.0.0.0/0 や目的のCIDRへのターゲットとして tgw-xxxxxx(TGWアタッチメントID)が向いていなければ、パケットはVPCから一歩も外に出ません。
「往きはよいよい帰りは怖い」の原則通り、双方向のルート(VPCルートテーブル ⇄ TGWルートテーブル)が確実に通っているかを aws ec2 describe-route-tables コマンドなどで必ず確認してください。
2. セキュリティグループ(SG)の落とし穴
TGWを介した通信であっても、宛先のEC2やコンテナ(ECS/EKSのENI)のセキュリティグループは容赦なくパケットを評価します。「他のVPCからの通信だから大丈夫」という甘えは捨て、送信元IP(またはVPCのCIDRブロック)が明確に許可されているか確認しましょう。
3. クロスアカウント共有(RAM: Resource Access Manager)の罠
別アカウントにあるVPCをTGWにアタッチする場合、AWS RAMを使った共有が必須になります。
アタッチメントの承認ステータスが pending のまま何分も固まっている場合は、共有側(オーナーアカウント)でのアクセプタンス(承認)処理が漏れていないか、IAM権限が正しく付与されているかを疑ってください。
—
クラウドネットワークの設計は、一度本番稼働させると後からの変更コストが非常に高い領域です。だからこそ、初期段階で「アタッチメントとルートテーブルの分離」というベストプラクティスを迷わず導入し、美しくセキュアなネットワーク基盤を構築してください。あなたの運用の平穏を、陰ながら応援しています。
コメント