After seeing the AWS latest News that said "AWS Transit Gateway is now available in Europe (Spain) Region (eu-south-2)" the last April 14, 2023, i decided to test the service with Terraform, just for fun...
First we need to create the infrastructure base, wich consists of 3 VPCs and corresponding private subnets. In case VPC-0 we've added also a public subnet, becasue we need for bastion host (EC2-0-bastion), we reach it via SSM.
After terraform apply in base-lab directory, we can get output to connect to bastion host:
➜ base-lab git:(main) ✗ TF_WORKSPACE=spain terraform apply -var-file=spain.tfvars
data.aws_iam_policy.this: Reading...
data.aws_iam_policy_document.this: Reading...
...
...
Apply complete! Resources: 76 added, 0 changed, 0 destroyed.
Outputs:
connect_bastion = "aws ssm start-session --target i-09b923594e90956b8 --region eu-south-2 --profile toninoes-aws2"
ip_ec2_vpc_0 = "10.0.1.71"
ip_ec2_vpc_1 = "10.1.1.40"
ip_ec2_vpc_2 = "10.2.1.10"
we can connect via SSM to bastion with:
➜ base-lab git:(main) ✗ aws ssm start-session --target i-09b923594e90956b8 --region eu-south-2 --profile toninoes-aws2
Starting session with SessionId: Toni-09ca128511bc6426f
sh-5.2$
We need to test connectivity then, from EC2 instances in privates subnets obiously, they can reach at the moment. Let's jump to EC2-0, first we need to copy private key in EC2-0-bastion.
sh-5.2$ echo "your_private_key_content" > tgw-lab.pem
sh-5.2$
sh-5.2$ chmod 400 tgw-lab.pem
sh-5.2$
sh-5.2$ ssh -i tgw-lab.pem ec2-user@10.0.1.71
, #_
~\_ ####_ Amazon Linux 2023
~~ \_#####\
~~ \###|
~~ \#/ ___ https://aws.amazon.com/linux/amazon-linux-2023
~~ V~' '->
~~~ /
~~._. _/
_/ _/
_/m/'
...and then, of course we can't ping to EC2-1 or EC2-2
[ec2-user@ip-10-0-1-71 ~]$ ping 10.1.1.40
PING 10.1.1.40 (10.1.1.40) 56(84) bytes of data.
^C
--- 10.1.1.40 ping statistics ---
4 packets transmitted, 0 received, 100% packet loss, time 3156ms
[ec2-user@ip-10-0-1-71 ~]$ ping 10.2.1.10
PING 10.2.1.10 (10.2.1.10) 56(84) bytes of data.
^C
--- 10.2.1.10 ping statistics ---
3 packets transmitted, 0 received, 100% packet loss, time 2066ms
Let's create our first Transit gateway in the next step.
In this first scenario, we'll create full connectivity between all our privates subnets of 3 VPCs.
For this, apply our terraform configuration in transit-gateway-scenario-1 folder:
In this scenario, we'll enable route table association and default route table propagation.
resource "aws_ec2_transit_gateway" "this" {
default_route_table_association = "enable"
default_route_table_propagation = "enable"
description = "My beginner transit-gateway in spain"
tags = {
"Name" = "TGW-with-RT-association-propagation"
}
}
Then, create 3 Transit Gateway VPC attachments for each VPC
resource "aws_ec2_transit_gateway_vpc_attachment" "this" {
count = var.vpc_number
subnet_ids = data.aws_subnets.private[count.index].ids
transit_gateway_id = aws_ec2_transit_gateway.this.id
vpc_id = data.aws_vpc.this[count.index].id
tags = {
"Name" = "att-${count.index}"
}
}
After this, we can see Associations... ...and propagations automatically in our TGW: But, after that, we cant reach other private subnets from EC2-0 instance, we need to modify all Private subnet route table and add route for 10.0.0.0/8 via the Transit gateway attachment.
resource "aws_route" "route" {
for_each = toset(data.aws_route_tables.this.ids)
route_table_id = each.key
destination_cidr_block = "10.0.0.0/8"
transit_gateway_id = aws_ec2_transit_gateway.this.id
}
and after this:
[ec2-user@ip-10-0-1-71 ~]$ ping 10.1.1.40
PING 10.1.1.40 (10.1.1.40) 56(84) bytes of data.
64 bytes from 10.1.1.40: icmp_seq=1 ttl=126 time=0.483 ms
64 bytes from 10.1.1.40: icmp_seq=2 ttl=126 time=0.274 ms
64 bytes from 10.1.1.40: icmp_seq=3 ttl=126 time=0.266 ms
^C
--- 10.1.1.40 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2089ms
rtt min/avg/max/mdev = 0.266/0.341/0.483/0.100 ms
[ec2-user@ip-10-0-1-71 ~]$
[ec2-user@ip-10-0-1-71 ~]$
[ec2-user@ip-10-0-1-71 ~]$ ping 10.2.1.10
PING 10.2.1.10 (10.2.1.10) 56(84) bytes of data.
64 bytes from 10.2.1.10: icmp_seq=1 ttl=126 time=0.479 ms
64 bytes from 10.2.1.10: icmp_seq=2 ttl=126 time=0.282 ms
64 bytes from 10.2.1.10: icmp_seq=3 ttl=126 time=0.261 ms
^C
--- 10.2.1.10 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2081ms
rtt min/avg/max/mdev = 0.261/0.340/0.479/0.098 ms
Before to test the next scenario, destroy first with terraform destroy in the same directory.
In the previous scenario all private subnets of all VPC can reach to each other, imagine we need specific connectivities, for example:
- VPC-0: Connects only with VPC-1
- VPC-1: Connects with VPC-0 and VPC-2
- VPC-2: Connects only with VPC-1
Apply terraform in transit-gateway-scenario-2 folder.
...in this case do not enable route table association and default route table propagation.
resource "aws_ec2_transit_gateway" "this" {
default_route_table_association = "disable"
default_route_table_propagation = "disable"
description = "My beginner transit-gateway in spain"
tags = {
"Name" = "TGW-without-RT-association-propagation"
}
}
then create 3 Transit Gateway VPC attachments for each VPC
resource "aws_ec2_transit_gateway_vpc_attachment" "this" {
count = var.vpc_number
subnet_ids = data.aws_subnets.private[count.index].ids
transit_gateway_default_route_table_association = false
transit_gateway_default_route_table_propagation = false
transit_gateway_id = aws_ec2_transit_gateway.this.id
vpc_id = data.aws_vpc.this[count.index].id
tags = {
"Name" = "att-${count.index}"
}
}
Now, we cant see our TGW RT (default), we need create specific route table
resource "aws_ec2_transit_gateway_route_table" "this" {
count = var.vpc_number
transit_gateway_id = aws_ec2_transit_gateway.this.id
tags = { Name: "att-${count.index}-RT" }
}
...and associate with corresponding VPC attachments
resource "aws_ec2_transit_gateway_route_table_association" "this" {
count = var.vpc_number
transit_gateway_attachment_id = aws_ec2_transit_gateway_vpc_attachment.this[count.index].id
transit_gateway_route_table_id = aws_ec2_transit_gateway_route_table.this[count.index].id
}
...and propagations
resource "aws_ec2_transit_gateway_route_table_propagation" "vpc_0_to_vpc_1" {
transit_gateway_route_table_id = aws_ec2_transit_gateway_route_table.this[0].id
transit_gateway_attachment_id = aws_ec2_transit_gateway_vpc_attachment.this[1].id
}
resource "aws_ec2_transit_gateway_route_table_propagation" "vpc_1_to_vpc_0" {
transit_gateway_route_table_id = aws_ec2_transit_gateway_route_table.this[1].id
transit_gateway_attachment_id = aws_ec2_transit_gateway_vpc_attachment.this[0].id
}
resource "aws_ec2_transit_gateway_route_table_propagation" "vpc_1_to_vpc_2" {
transit_gateway_route_table_id = aws_ec2_transit_gateway_route_table.this[1].id
transit_gateway_attachment_id = aws_ec2_transit_gateway_vpc_attachment.this[2].id
}
resource "aws_ec2_transit_gateway_route_table_propagation" "vpc_2_to_vpc_1" {
transit_gateway_route_table_id = aws_ec2_transit_gateway_route_table.this[2].id
transit_gateway_attachment_id = aws_ec2_transit_gateway_vpc_attachment.this[1].id
}
and finally add route "10.0.0.0/8" via our TGW in all private-RT of our VPCs
resource "aws_route" "route" {
for_each = toset(data.aws_route_tables.this.ids)
route_table_id = each.key
destination_cidr_block = "10.0.0.0/8"
transit_gateway_id = aws_ec2_transit_gateway.this.id
}
After that, from EC2-0 ca reach EC2-1, but not EC2-2:
[ec2-user@ip-10-0-1-71 ~]$ ping 10.1.1.40
PING 10.1.1.40 (10.1.1.40) 56(84) bytes of data.
64 bytes from 10.1.1.40: icmp_seq=1 ttl=126 time=0.500 ms
64 bytes from 10.1.1.40: icmp_seq=2 ttl=126 time=0.317 ms
64 bytes from 10.1.1.40: icmp_seq=3 ttl=126 time=0.306 ms
^C
--- 10.1.1.40 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2114ms
rtt min/avg/max/mdev = 0.306/0.374/0.500/0.088 ms
[ec2-user@ip-10-0-1-71 ~]$ ping 10.2.1.10
PING 10.2.1.10 (10.2.1.10) 56(84) bytes of data.
^C
--- 10.2.1.10 ping statistics ---
5 packets transmitted, 0 received, 100% packet loss, time 4139ms
and if we jump to EC2-1, we can reach both.
You have to remember to delete the infrastructure of TGW and EC2. Pricing TGW