Transit Gatewayを試す
VPCピアリングと違い、Transit Gatewayを使えば複数のVPCを一元的に接続できるため、拡張性のある構成を簡単に実現できます。 各VPCのルートテーブルを設定するだけで、すべてのEC2が相互に通信できるようになるのを試してみました。
目次
はじめに
- VPCピアリングを試すで、2つのVPCにまたがるEC2間の通信ができたのを確認した
- VPCピアリングはあくまで1:1間の通信で、VPCが複数になったときに管理するのが大変になる。
- 大量になったときはTransit Gatewayを使うのがセオリーということで試してみた
- SAP勉強してたらよく出てきたので試してみた
作るもの
- VPCピアリングの例のVPCを3個に拡張する
- 各VPCのプライベートサブネットにnginxをインストールしておき、各VPCから別のVPCのEC2に向かってcurlを飛ばしてnginxのトップページが返ってくるかを確認する
- 各VPCへの接続にはSession Managerを使う。よって、プライベートサブネットからインターネットに出ていける必要があり、NATインスタンスとしてfck-natを使用。
VPCモジュール
ディレクトリは以下の通り。VPCモジュールはmodules/vpc
以下。
.
├── main.tf
├── vpc_cluster.tf
├── ec2.tf
├── modules
│ └── vpc
│ ├── main.tf
│ ├── variables.tf
│ └── outputs.tf
VPCピアリングのときのVPCモジュールをそのまま使い回す。
Transit Gateway(vpc_cluster.tf)
以下のコードで、VPCを3個作成し、Transit Gatewayに紐づけられる。
VPCピアリングとの違いは以下の通り。
- Transit Gateway自体にルートテーブルがある
- 各VPCのアップデートのほかに、Transit Gatewayのルートテーブルへの登録が必要。
- デフォルトのTransit Gatewayのルートテーブルで良ければ、各VPCのTransit Gatewayに紐づけた時点で登録される
- (同一アカウントであるかぎりは)VPCピアリングのような承認は不要
- VPCピアリングのときは同一アカウント間でも承認が必要だったが、Transit Gatewayは不要。クロスアカウントになったときはわからない
- Transit GatewayにVPCを紐づけた時点で自動的に通信ができるようになる
- 各VPCで、通信したい他のVPCをルートテーブルに登録する操作は、VPCピアリングのときと同様に必要
##########################
# VPC Modules Deployment #
##########################
module "vpc1" {
source = "./modules/vpc"
vpc_name = "VPC1"
vpc_cidr_block = "10.10.0.0/20"
availability_zones = ["ap-northeast-1a", "ap-northeast-1c", "ap-northeast-1d"]
}
module "vpc2" {
source = "./modules/vpc"
vpc_name = "VPC2"
vpc_cidr_block = "10.10.16.0/20"
availability_zones = ["ap-northeast-1a", "ap-northeast-1c", "ap-northeast-1d"]
}
module "vpc3" {
source = "./modules/vpc"
vpc_name = "VPC3"
vpc_cidr_block = "10.10.32.0/20"
availability_zones = ["ap-northeast-1a", "ap-northeast-1c", "ap-northeast-1d"]
}
locals {
vpc_modles = {
VPC1 = module.vpc1
VPC2 = module.vpc2
VPC3 = module.vpc3
}
}
##########################
# Transit Gateway Setup #
##########################
# Create Transit Gateway
resource "aws_ec2_transit_gateway" "tgw" {
description = "Transit Gateway for inter-VPC communication"
}
# Create Transit Gateway Attachments for each VPC
resource "aws_ec2_transit_gateway_vpc_attachment" "tgw_attach_vpc" {
for_each = local.vpc_modles
transit_gateway_id = aws_ec2_transit_gateway.tgw.id
vpc_id = each.value.vpc_id
subnet_ids = each.value.private_subnet_ids
tags = {
Name = "TGW-Attachment-${each.key}"
}
}
# Create routes in each VPC's private route table to direct traffic to the Transit Gateway
resource "aws_route" "vpc1_to_tgw" {
for_each = {
vpc2 = module.vpc2.vpc_cidr_block
vpc3 = module.vpc3.vpc_cidr_block
}
route_table_id = module.vpc1.private_route_table_id
destination_cidr_block = each.value
transit_gateway_id = aws_ec2_transit_gateway.tgw.id
}
resource "aws_route" "vpc2_to_tgw" {
for_each = {
vpc1 = module.vpc1.vpc_cidr_block
vpc3 = module.vpc3.vpc_cidr_block
}
route_table_id = module.vpc2.private_route_table_id
destination_cidr_block = each.value
transit_gateway_id = aws_ec2_transit_gateway.tgw.id
}
resource "aws_route" "vpc3_to_tgw" {
for_each = {
vpc1 = module.vpc1.vpc_cidr_block
vpc2 = module.vpc2.vpc_cidr_block
}
route_table_id = module.vpc3.private_route_table_id
destination_cidr_block = each.value
transit_gateway_id = aws_ec2_transit_gateway.tgw.id
}
各VPCのルートテーブル
マネジメントコンソールで確認してみる。各VPCのCIDRへは、ターゲットがtgw-*
となっており、Transit Gateway経由で接続していることがわかる。
Transit Gatewayのルートテーブル
Transit Gatewayのデフォルトルートテーブル。各VPCが関連付けられているのがわかる。
nginxのEC2(ec2.tf)
VPCピアリングと同様に各VPCのEC2を定義する。セキュリティグループは「接続相手だけ許可」をするとコードが煩雑になるので、「全VPCのEC2があるサブネットからの80からの接続を許可」に変える。
##########################
# EC2 Instances and Supporting Resources
##########################
# Amazon Linux 2023 AMI lookup
data "aws_ami" "amazon_linux" {
most_recent = true
owners = ["137112412989"]
filter {
name = "name"
values = ["al2023-ami-2023*-kernel-*-x86_64"]
}
filter {
name = "architecture"
values = ["x86_64"]
}
filter {
name = "virtualization-type"
values = ["hvm"]
}
}
# Security Groups for EC2 instances in all subnets
resource "aws_security_group" "ec2_sgs" {
for_each = local.vpc_modles
name = "${each.key}-ec2_sg"
description = "A security group for EC2 instances"
vpc_id = each.value.vpc_id
ingress {
description = "Allow HTTP traffic from all EC2 subnet"
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = [for key, vpc in local.vpc_modles : vpc.private_subnet_cidr_blocks[0]]
}
egress {
description = "Allow all outbound traffic"
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
ipv6_cidr_blocks = ["::/0"]
}
}
# IAM Role for SSM
resource "aws_iam_role" "ssm_role" {
name = "ec2_ssm_role_nginx"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Principal = { Service = "ec2.amazonaws.com" }
Action = "sts:AssumeRole"
}]
})
}
resource "aws_iam_role_policy_attachment" "ssm_policy_attachment" {
role = aws_iam_role.ssm_role.name
policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
}
resource "aws_iam_instance_profile" "ssm_instance_profile" {
name = "ec2_ssm_instance_profile_nginx"
role = aws_iam_role.ssm_role.name
}
# nginx EC2 instances in VPC1 and VPC2
resource "aws_instance" "nginx" {
for_each = local.vpc_modles
ami = data.aws_ami.amazon_linux.id
instance_type = "t3.micro"
subnet_id = each.value.private_subnet_ids[0]
associate_public_ip_address = false
vpc_security_group_ids = [aws_security_group.ec2_sgs[each.key].id]
iam_instance_profile = aws_iam_instance_profile.ssm_instance_profile.name
user_data = <<-EOF
#!/bin/bash
dnf update -y
dnf install nginx -y
systemctl start nginx
systemctl enable nginx
EOF
tags = {
Name = "${each.key}-nginx"
}
}
# 出力: EC2のプライベートIP
output "nginx_ips" {
value = { for k, v in aws_instance.nginx : k => v.private_ip }
}
テスト
terraform apply
をすると以下のような出力になったとする。
nginx_ips = {
"VPC1" = "10.10.4.14"
"VPC2" = "10.10.21.140"
"VPC3" = "10.10.37.211"
}
VPC1のEC2インスタンスからの接続
Session ManagerからEC2に入り、VPC2のEC2(10.10.21.140
)、VPC3のEC2(10.10.37.211
)に対してcurlが飛ばせるか確認する。nginxのトップページが返ってきており、正常にアクセスできている。
[root@ip-10-10-4-14 ~]# curl http://10.10.21.140
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
[root@ip-10-10-4-14 ~]# curl http://10.10.37.211
(略)
<h1>Welcome to nginx!</h1>
(略)
VPC2のEC2インスタンスからの接続確認
VPC1のEC2(10.10.4.14
)、VPC3のEC2(10.10.37.211
)に対してcurlが飛ばせるか確認する。正常にアクセスできている。
[root@ip-10-10-21-140 ~]# curl http://10.10.4.14
(略)
<h1>Welcome to nginx!</h1>
(略)
[root@ip-10-10-21-140 ~]# curl http://10.10.37.211
(略)
<h1>Welcome to nginx!</h1>
(略)
VPC3のEC2インスタンスからの接続確認
VPC1のEC2(10.10.4.14
)、VPC2のEC2(10.10.21.140
)に対してcurlが飛ばせるか確認する。正常にアクセスできている。
[root@ip-10-10-37-211 ~]# curl http://10.10.4.14
(略)
<h1>Welcome to nginx!</h1>
(略)
[root@ip-10-10-37-211 ~]# curl http://10.10.21.140
(略)
<h1>Welcome to nginx!</h1>
(略)
また自分自身のIPのnginxに対しても接続できる。(10.10.37.211
)
[root@ip-10-10-37-211 ~]# curl http://10.10.37.211
(略)
<h1>Welcome to nginx!</h1>
(略)
所感
- Transit Gateway難しそうだったけど思ったより簡単だった。CIDRが重複しないという縛りは必要だけど、VPCが増えたらこれかな
- あとはコスト次第
Shikoan's ML Blogの中の人が運営しているサークル「じゅ~しぃ~すくりぷと」の本のご案内
技術書コーナー
北海道の駅巡りコーナー