
By default, resources in different Virtual Private Clouds (VPCs) are isolated from each other and cannot communicate with each other. The resources in different Virtual Private Clouds (VPCs) would need to use something like an Internet Gateway to communicate. For example, an EC2 instance in one Virtual Private Cloud (VPC) would have to send traffic onto the Internet via an Internet Gateway to talk to an EC2 instance in a different Virtual Private Clouds (VPC).
There are different ways for resources (such as EC2 instances) in different Virtual Private Clouds to communicate without having to use an Internet Gateway.
- VPC Peering
- Transit Gateway (this article)
A Transit Gateway is often used to:
- Connect together two (or more) Virtual Private Clouds (VPCs)
- Connect a Virtual Private Cloud (VPCs) to your on-prem Network
For example, let's create two VPCs.
- foo-vpc
- bar-vpc
By default, a VPC will only have a local route and no Internet Gateway, so let's create an Internet Gateway for foo-vpc and bar-vpc. By default, the Internet Gateways will not be attached to any VPCs.
Let's attach the foo-internet-gateway to foo-vpc.
aws ec2 attach-internet-gateway --internet-gateway-id igw-0b2060b1673cbf2c5 --vpc-id vpc-0f3854b1b6bf17549
And attach the bar-internet-gateway to bar-vpc.
aws ec2 attach-internet-gateway --internet-gateway-id igw-0aa355b50a65801e8 --vpc-id vpc-0a2a3baf02e36e369
Now each Internet Gateway should be attached to each VPC.
The Route Table in the Subnets in foo-vpc and bar should only have a local route.
Let's update the Route Table being used by foo-vpc to have a route to the foo-internet-gateway.
And let's update the Route Table being used by bar-vpc to have a route to the bar-internet-gateway.
Let's create an EC2 instance in foo-vpc and bar-vpc.
And update the Security Group being used by each EC2 instance to allow SSH connections from your local public IP address. In this example, my local public IP address was 65.17.88.90. You would instead use your local public IP address.
And you should now be able to SSH onto the EC2 instance in foo-vpc.
Using username "ec2-user".
Authenticating with public key "aws"
, #_
~\_ ####_ Amazon Linux 2023
~~ \_#####\
~~ \###|
~~ \#/ ___ https://aws.amazon.com/linux/amazon-linux-2023
~~ V~' '->
~~~ /
~~._. _/
_/ _/
_/m/'
Last login: Wed May 1 00:12:12 2024 from 65.17.88.90
[ec2-user@ip-10-0-4-185 ~]$
And the EC2 instance in bar-vpc. Nice!
Using username "ec2-user".
Authenticating with public key "aws"
, #_
~\_ ####_ Amazon Linux 2023
~~ \_#####\
~~ \###|
~~ \#/ ___ https://aws.amazon.com/linux/amazon-linux-2023
~~ V~' '->
~~~ /
~~._. _/
_/ _/
_/m/'
Last login: Wed May 1 00:12:12 2024 from 65.17.88.90
[ec2-user@ip-172-16-14-14 ~]$
On the EC2 instance in foo-vpc, there should be a public SSH key such as id_rsa.pub.
[ec2-user@ip-10-0-0-5 ~]$ cat /home/ec2-user/.ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDbhEwnvPWnCUthZh/pIhGm2/wHlpEcla4GNKvnti9voszQPQjZw9kksUOKW9ZQ5Ez24mrDmA8djUnwO9lKFZSM/qPfzVpeMkp6e6gYLD8yEmbepC8/TbgxuMa1He+jEFh7SXcaQwx6/Qx1/+RSFh+BcuaCoIJQumhsBuPKyNMknluRmxdU2aHzKjTlSdIzV1I6JmLvhqgFsD6JT3LJotEHNdpjFnu4nWSsFWfRFHKswtwoXvlQWH0g3Kz3fkmqnBSxcB+nCNmsy+zJ82WMBfLKl3UCUrcvjaJWgPSPfck9bB8zwEcixAszG+Atm7CRfg/oUebSauj93XKzgijXgnK3ZbM0nC8uB/l6S5OtbYxdBEalnh/Q/knS1xTItabrBuApQAc+aOR8Ah9hNV2PPVYHmQTuaXbyjTiU6KqERoABazfl0dYwjUq3ZnOJla749z6nqfYN1/2p7E6sCci08H2GbueiS75gufFDHvORpAgsabY/xNyNB5+FAVHJYoI9SeF2Lxp2WVc5I9GcymWQgtgec/yW/gl0TBmFhS1o4ybPOjSUor3UiDBnEXaxIyhPR0gQnpW6Y6s2VYKPeFRO1VKoJ0F/xv8I095OVskn2/j1qtN2OMXQQG7Y7InBzgg+PUdIGC/XxO/G7vAXmcOqKhX1RilVHb/iZEHU2NzDFQIe7w== ec2-user@ip-10-0-0-5.ec2.internal
Let's append the content of id_rsa.pub from the EC2 instance in foo-vpc to the /home/ec2-user/.ssh/authorized_keys file on the EC2 instance in bar-vpc.
[ec2-user@ip-172-31-0-5 ~]$ cat /home/ec2-user/.ssh/authorized_keys
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDbhEwnvPWnCUthZh/pIhGm2/wHlpEcla4GNKvnti9voszQPQjZw9kksUOKW9ZQ5Ez24mrDmA8djUnwO9lKFZSM/qPfzVpeMkp6e6gYLD8yEmbepC8/TbgxuMa1He+jEFh7SXcaQwx6/Qx1/+RSFh+BcuaCoIJQumhsBuPKyNMknluRmxdU2aHzKjTlSdIzV1I6JmLvhqgFsD6JT3LJotEHNdpjFnu4nWSsFWfRFHKswtwoXvlQWH0g3Kz3fkmqnBSxcB+nCNmsy+zJ82WMBfLKl3UCUrcvjaJWgPSPfck9bB8zwEcixAszG+Atm7CRfg/oUebSauj93XKzgijXgnK3ZbM0nC8uB/l6S5OtbYxdBEalnh/Q/knS1xTItabrBuApQAc+aOR8Ah9hNV2PPVYHmQTuaXbyjTiU6KqERoABazfl0dYwjUq3ZnOJla749z6nqfYN1/2p7E6sCci08H2GbueiS75gufFDHvORpAgsabY/xNyNB5+FAVHJYoI9SeF2Lxp2WVc5I9GcymWQgtgec/yW/gl0TBmFhS1o4ybPOjSUor3UiDBnEXaxIyhPR0gQnpW6Y6s2VYKPeFRO1VKoJ0F/xv8I095OVskn2/j1qtN2OMXQQG7Y7InBzgg+PUdIGC/XxO/G7vAXmcOqKhX1RilVHb/iZEHU2NzDFQIe7w== ec2-user@ip-10-0-0-5.ec2.internal
And vice versa. Let's the content of id_rsa.pub from the EC2 instance in bar-vpc to the /home/ec2-user/.ssh/authorized_keys file on the EC2 instance in foo-vpc.
But when attempting to SSH from the EC2 instance in foo-vpc to the EC2 instance in bar-vpc, the SSH connection should eventually time out. And vice versa, when attempting to SSH from the EC2 instance in bar-vpc to the EC2 instance in foo-vpc, the SSH connection should eventually time out. Because we have not yet created and setup a Transit Gateway to allows communication between resources in foo-vpc and bar-vpc.
[ec2-user@ip-10-0-4-185 ~]$ ssh -o ConnectTimeout=5 ec2-user@172.16.14.14
ssh: connect to host 172.16.14.14 port 22: Connection timed out
Since this is just meant to be a simple Getting Started article, in the AWS VPC console, let's create a Transit Gateway, and go with all the defaults.
Or, the aws ec2 create-transit-gateway command can be used.
aws ec2 create-transit-gateway \
--description my-transit-gateway \
--options AmazonSideAsn=64516,AutoAcceptSharedAttachments=disable,DefaultRouteTableAssociation=enable,DefaultRouteTablePropagation=enable,VpnEcmpSupport=enable,DnsSupport=enable
And the aws ec2 describe-transit-gateways command should return your Transit Gateway. I may take a few moments for the Transit Gateway state to be "available".
~]$ aws ec2 describe-transit-gateways
{
"TransitGateways": [
{
"TransitGatewayId": "tgw-0d92bd9f9b45070a7",
"TransitGatewayArn": "arn:aws:ec2:us-east-1:123456789012:transit-gateway/tgw-0d92bd9f9b45070a7",
"State": "available",
"OwnerId": "123456789012",
"Description": "",
"CreationTime": "2024-05-19T08:25:47+00:00",
"Options": {
"AmazonSideAsn": 64512,
"AutoAcceptSharedAttachments": "disable",
"DefaultRouteTableAssociation": "enable",
"AssociationDefaultRouteTableId": "tgw-rtb-0901a28eecf505a89",
"DefaultRouteTablePropagation": "enable",
"PropagationDefaultRouteTableId": "tgw-rtb-0901a28eecf505a89",
"VpnEcmpSupport": "enable",
"DnsSupport": "enable",
"MulticastSupport": "disable"
},
"Tags": [
{
"Key": "Name",
"Value": "my-transit-gateway"
}
]
}
]
}
Now let's attach the Transit Gateway to both VPCs, foo-vpc and bar-vpc.
Or, using the aws ec2 create-transit-gateway-vpc-attachment command to attach the Transit Gateway to foo-vpc.
aws ec2 create-transit-gateway-vpc-attachment \
--transit-gateway-id tgw-036b93068244418ff \
--vpc-id vpc-0f3854b1b6bf17549 \
--subnet-id subnet-0e45c1b3e9cdd1030
And to bar-vpc.
ws ec2 create-transit-gateway-vpc-attachment \
--transit-gateway-id tgw-036b93068244418ff \
--vpc-id vpc-0a2a3baf02e36e369 \
--subnet subnet-0851aa70fbb90d47c
Give it a few minutes, and both VPCs should be Available in the Transit Gateway.
Likewise, the aws ec2 describe-transit-gateway-attachments command should show that both VPCs are now attached to the Transit Gateway, and both are available.
~]$ aws ec2 describe-transit-gateway-attachments
{
"TransitGatewayAttachments": [
{
"TransitGatewayAttachmentId": "tgw-attach-02454889f1d83ac46",
"TransitGatewayId": "tgw-0d92bd9f9b45070a7",
"TransitGatewayOwnerId": "123456789012",
"ResourceOwnerId": "123456789012",
"ResourceType": "vpc",
"ResourceId": "vpc-987ihg654fed321cba",
"State": "available",
"Association": {
"TransitGatewayRouteTableId": "tgw-rtb-0901a28eecf505a89",
"State": "associated"
},
"CreationTime": "2024-05-19T09:54:27+00:00",
"Tags": [
{
"Key": "Name",
"Value": "bar-vpc"
}
]
},
{
"TransitGatewayAttachmentId": "tgw-attach-03d016041bfeae2be",
"TransitGatewayId": "tgw-0d92bd9f9b45070a7",
"TransitGatewayOwnerId": "123456789012",
"ResourceOwnerId": "123456789012",
"ResourceType": "vpc",
"ResourceId": "vpc-abc123def456ghi789",
"State": "available",
"Association": {
"TransitGatewayRouteTableId": "tgw-rtb-0901a28eecf505a89",
"State": "associated"
},
"CreationTime": "2024-05-19T09:50:52+00:00",
"Tags": [
{
"Key": "Name",
"Value": "foo-vpc"
}
]
}
]
}
But we still cannot communicate between foo-vpc and bar-vpc because the Route Tables being used by the EC2 instances in foo-vpc and bar-vpc do not have a route for the Transit Gateway.
The Route Table being used by the EC2 instance in foo-vpc will need to be updated with a Transit Gateway Route to bar-vpc. For example, let's say the CIDR of bar-vpc is 172.16.0.0/16. In this scenario, the Route Table being used by the EC2 instance in foo-vpc would need a Transit Gateway Route to CIDR 172.31.0.0/16.
Or using the aws ec2 create-route command.
aws ec2 create-route \
--route-table-id rtb-045268e65e93d6380 \
--destination-cidr-block 172.16.0.0/16 \
--transit-gateway-id tgw-036b93068244418ff
Likewise, the Route Table being used by the EC2 instance in bar-vpc will need to be updated with a Transit Gateway Route to foo-vpc. For example, let's say the CIDR of foo-vpc is 10.0.0.0/16. In this scenario, the Route Table being used by the EC2 instance in bar-vpc would need a Transit Gateway Route to CIDR 10.0.0.0/16.
Or using the aws ec2 create-route command.
aws ec2 create-route \
--route-table-id rtb-045268e65e93d6380 \
--destination-cidr-block 172.16.0.0/16 \
--transit-gateway-id tgw-036b93068244418ff
Since what we are trying to do here is to make an SSH connection from the EC2 instance in foo-vpc to the EC2 instance in bar-vpc the Security Group attached to the EC2 instance in bar-vpc will need to allow SSH connections from the foo-vpc CIDR. This can be done using the aws ec2 authorize-security-group-ingress command.
aws ec2 authorize-security-group-ingress \
--group-id sg-0778124087b3d14d4 \
--protocol tcp \
--port 22 \
--cidr 172.16.0.0/16
And and EC2 instance in foo-vpc will need to allow SSH connection from the bar-vpc CIDR.
aws ec2 authorize-security-group-ingress \
--group-id sg-sg-04c4f6c3a9cf3816a \
--protocol tcp \
--port 22 \
--cidr 10.0.0.0/16
Now the Security Group being used by the EC2 instance in foo-vpc should allow SSH connections from bar-vpc CIDR 172.16.0.0/16.
And the Security Group being used by the EC2 instance in bar-vpc should allow SSH connections from foo-vpc CIDR 10.0.0.0/16.
And we should now be able to make the SSH connection from the EC2 instance in foo-vpc to the EC2 instance in bar-vpc.
[ec2-user@ip-10-0-4-185 ~]$ ssh ec2-user@172.16.14.14
, #_
~\_ ####_ Amazon Linux 2
~~ \_#####\
~~ \###| AL2 End of Life is 2025-06-30.
~~ \#/ ___
~~ V~' '->
~~~ / A newer version of Amazon Linux is available!
~~._. _/
_/ _/ Amazon Linux 2023, GA and supported until 2028-03-15.
_/m/' https://aws.amazon.com/linux/amazon-linux-2023/
[ec2-user@ip-172-16-14-14 ~]$
And vice versa. It works!
[ec2-user@ip-172-16-14-14 ~]$ ssh ec2-user@10.0.4.185
, #_
~\_ ####_ Amazon Linux 2
~~ \_#####\
~~ \###| AL2 End of Life is 2025-06-30.
~~ \#/ ___
~~ V~' '->
~~~ / A newer version of Amazon Linux is available!
~~._. _/
_/ _/ Amazon Linux 2023, GA and supported until 2028-03-15.
_/m/' https://aws.amazon.com/linux/amazon-linux-2023/
[ec2-user@ip-10-0-4-185 ~]$
Did you find this article helpful?
If so, consider buying me a coffee over at