Setting up AWS VPC Transit Gateway using Terraform

In this article, we’ll use Terraform to set up an AWS VPC Transit Gateway, enabling seamless connectivity and communication between multiple VPCs within your AWS infrastructure.

Setting up AWS VPC Transit Gateway using Terraform 1

What is Terraform?

1280px Terraform Logo.svg removebg preview 1
  • It is an open-source IaaC (Infrastructure as a code) software tool where you define and create resources using providers in the declarative configuration language example JSON.
  • With Terraform, You can package and reuse the code in the form of modules.
  • It supports a number of cloud infrastructure providers such as AWS, Azure, GCP, IBM Cloud, OCI, etc.

What is AWS Transit Gateway?

AWS Transit Gateway is a service that simplifies network connectivity for multiple Amazon Virtual Private Clouds (VPCs) and on-premises networks. It acts as a hub that allows you to connect VPCs and VPN connections, enabling centralized management of network routing and traffic between these resources. This simplifies network architecture, improves scalability, and reduces operational complexity by providing a single gateway for routing traffic across multiple networks.

Setting up AWS VPC Transit Gateway 2

Example:

  1. VPC 1: This VPC hosts a web application that needs to communicate with backend services in VPC 2 and also needs access to a shared database in VPC 3.
  2. VPC 2: This VPC contains backend services such as application servers, databases, and message queues that support the web application in VPC 1.
  3. VPC 3: This VPC hosts a shared database that is used by multiple applications and services, including the web application in VPC 1.

Using AWS Transit Gateway:

  • You deploy an AWS Transit Gateway in Region A.
  • You attach all three VPCs (VPC 1, VPC 2, and VPC 3) to the Transit Gateway.
  • You configure route tables in the Transit Gateway to allow communication between these VPCs.
  • The web application in VPC 1 can now securely communicate with backend services in VPC 2 through the Transit Gateway without requiring direct peering connections.
  • Similarly, the web application can access the shared database in VPC 3 via the Transit Gateway.
  • You can also connect on-premises networks or other VPCs from different regions to the Transit Gateway, enabling centralized network connectivity management.

This setup simplifies network architecture, reduces the number of peering connections, and provides a scalable and centralized solution for managing network traffic between multiple VPCs and external networks.

Prerequisites

  • AWS Account: You should have an active AWS account with the necessary permissions to create and manage resources.
  • Terraform: Terraform is an infrastructure provisioning tool that you’ll need to install on your local machine.
  • Visual Studio Code Editor Installed

Steps for Setting up AWS VPC Transit Gateway using Terraform

Summary view of the terraform files in VS code:

Setting up AWS VPC Transit Gateway using Terraform 2

Step#1:Create provider.tf file

The provider.tf file in Terraform is a configuration file that specifies the cloud provider and its corresponding plugin that Terraform will use to manage resources in that provider.

Provider.tf
provider "aws" {
region = "ap-south-1"
profile= "default"
}

terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "5.43.0"
}
}
}
Setting up AWS VPC Transit Gateway using Terraform 3

Step#2:Create Web App VPC in Mumbai Region

The Vpc.tf file in Terraform configures an Amazon VPC in Mumbai, defining CIDR blocks, public and private subnets, an internet gateway for external access, route tables, and routes for internet-bound traffic.

web-app-vpc.tf
resource "aws_vpc" "WEB_APP_VPC" {
cidr_block = "10.0.0.0/16"


tags = {
Name = "WEB_APP_VPC"
}
}

resource "aws_subnet" "WEB_APP_SUBNET" {
vpc_id = aws_vpc.WEB_APP_VPC.id
cidr_block = "10.0.1.0/24"
availability_zone = "ap-south-1a"
tags = {
Name = "WEB_APP_SUBNET"
}
}

resource "aws_internet_gateway" "WEB_APP_IGW" {
vpc_id = aws_vpc.WEB_APP_VPC.id

tags = {
Name = "WEB_APP_IGW"
}
}

resource "aws_default_route_table" "WEB_APP_ROUTE" {
default_route_table_id = aws_vpc.WEB_APP_VPC.default_route_table_id

tags = {
Name = "WEB_APP_ROUTE"
}
}

resource "aws_route" "web_app_route" {
route_table_id = aws_default_route_table.WEB_APP_ROUTE.id
destination_cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.WEB_APP_IGW.id

depends_on = [aws_vpc.WEB_APP_VPC] # Ensure VPC is created before route
}

# Route to BACKEND_SERVICES_VPC via Transit Gateway Attachment
resource "aws_route" "web_app_to_backend_services" {
route_table_id = aws_default_route_table.WEB_APP_ROUTE.id
destination_cidr_block = "11.0.0.0/16" # Replace with actual VPC 2 CIDR block
transit_gateway_id = aws_ec2_transit_gateway_vpc_attachment.web_app_attachment.transit_gateway_id

depends_on = [aws_ec2_transit_gateway_vpc_attachment.web_app_attachment]
}

# Route to SHARED_DATABASE_VPC via Transit Gateway Attachment
resource "aws_route" "web_app_to_shared_database" {
route_table_id = aws_default_route_table.WEB_APP_ROUTE.id
destination_cidr_block = "12.0.0.0/16" # Replace with actual VPC 3 CIDR block
transit_gateway_id = aws_ec2_transit_gateway_vpc_attachment.web_app_attachment.transit_gateway_id

depends_on = [aws_ec2_transit_gateway_vpc_attachment.web_app_attachment]
}
Setting up AWS VPC Transit Gateway using Terraform 4

Step#3:Create Backend Services VPC in Mumbai Region

bakcend-services-vpc.tf
resource "aws_vpc" "BACKEND_SERVICES_VPC" {
cidr_block = "11.0.0.0/16"


tags = {
Name = "BACKEND_SERVICES_VPC"
}
}

resource "aws_subnet" "BACKEND_SERVICES_SUBNET" {
vpc_id = aws_vpc.BACKEND_SERVICES_VPC.id
cidr_block = "11.0.1.0/24"
availability_zone = "ap-south-1a"
tags = {
Name = "BACKEND_SERVICES_SUBNET"
}
}

resource "aws_internet_gateway" "BACKEND_SERVICES_IGW" {
vpc_id = aws_vpc.BACKEND_SERVICES_VPC.id

tags = {
Name = "BACKEND_SERVICES_IGW"
}
}

# Create a default route table for backend services VPC
resource "aws_default_route_table" "BACKEND_SERVICES_ROUTE" {
default_route_table_id = aws_vpc.BACKEND_SERVICES_VPC.default_route_table_id

tags = {
Name = "BACKEND_SERVICES_ROUTE"
}
}

# Create a default route for backend services VPC
resource "aws_route" "backend_services_route" {
route_table_id = aws_default_route_table.BACKEND_SERVICES_ROUTE.id
destination_cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.BACKEND_SERVICES_IGW.id # Replace with actual internet gateway ID

depends_on = [aws_vpc.BACKEND_SERVICES_VPC] # Ensure VPC is created before route
}

resource "aws_route" "backend_services_to_web_app" {
route_table_id = aws_default_route_table.BACKEND_SERVICES_ROUTE.id
destination_cidr_block = "10.0.0.0/16" # Replace with actual WEB_APP VPC CIDR block
transit_gateway_id = aws_ec2_transit_gateway_vpc_attachment.backend_services_attachment.transit_gateway_id

depends_on = [aws_ec2_transit_gateway_vpc_attachment.backend_services_attachment]
}

resource "aws_route" "backend_services_to_shared_database" {
route_table_id = aws_default_route_table.BACKEND_SERVICES_ROUTE.id
destination_cidr_block = "12.0.0.0/16" # Replace with actual SHARED_DATABASE VPC CIDR block
transit_gateway_id = aws_ec2_transit_gateway_vpc_attachment.backend_services_attachment.transit_gateway_id

depends_on = [aws_ec2_transit_gateway_vpc_attachment.backend_services_attachment]
}
Setting up AWS VPC Transit Gateway using Terraform 5

Step#4:Create Shared Database VPC in Mumbai Region

shared-database-vpc.tf
resource "aws_vpc" "SHARED_DATABASE_VPC" {
cidr_block = "12.0.0.0/16"


tags = {
Name = "SHARED_DATABASE_VPC"
}
}

resource "aws_subnet" "SHARED_DATABASE_SUBNET" {
vpc_id = aws_vpc.SHARED_DATABASE_VPC.id
cidr_block = "12.0.1.0/24"
availability_zone = "ap-south-1a"
tags = {
Name = "SHARED_DAYABASE_SUBNET"
}
}

resource "aws_internet_gateway" "SHARED_DATABASE_IGW" {
vpc_id = aws_vpc.SHARED_DATABASE_VPC.id

tags = {
Name = "SHARED_DATABASE_IGW"
}
}
# Create a default route table for shared database VPC
resource "aws_default_route_table" "SHARED_DATABASE_ROUTE" {
default_route_table_id = aws_vpc.SHARED_DATABASE_VPC.default_route_table_id

tags = {
Name = "SHARED_DATABASE_ROUTE"
}
}

# Create a default route for shared database VPC
resource "aws_route" "shared_database_route" {
route_table_id = aws_default_route_table.SHARED_DATABASE_ROUTE.id
destination_cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.SHARED_DATABASE_IGW.id # Replace with actual internet gateway ID

depends_on = [aws_vpc.SHARED_DATABASE_VPC] # Ensure VPC is created before route
}

# Route to backend services VPC via Transit Gateway Attachment
resource "aws_route" "shared_database_to_backend_services" {
route_table_id = aws_default_route_table.SHARED_DATABASE_ROUTE.id
destination_cidr_block = "11.0.0.0/16" # Replace with actual BACKEND_SERVICES VPC CIDR block
transit_gateway_id = aws_ec2_transit_gateway_vpc_attachment.shared_database_attachment.transit_gateway_id

depends_on = [aws_ec2_transit_gateway_vpc_attachment.shared_database_attachment]
}

resource "aws_route" "shared_database_to_webapp" {
route_table_id = aws_default_route_table.SHARED_DATABASE_ROUTE.id
destination_cidr_block = "10.0.0.0/16" # Replace with actual web_app VPC CIDR block
transit_gateway_id = aws_ec2_transit_gateway_vpc_attachment.shared_database_attachment.transit_gateway_id

depends_on = [aws_ec2_transit_gateway_vpc_attachment.shared_database_attachment]
}
Setting up AWS VPC Transit Gateway using Terraform 6

Step#5:Create EC2 Instances in each VPC

ec2-web-app.tf

# Create a security group named 'customer-securitygrp' with ingress rules
resource "aws_default_security_group" "default" {
vpc_id = aws_vpc.WEB_APP_VPC.id
tags = {
Name = "Webapp-sg"
}


# Allow SSH access from your specific IP or CIDR block (replace with yours)
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}

# Allow HTTP access from anywhere for testing (consider restricting later)
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}

# Remove unnecessary ICMP rule for web applications (optional)
# ingress {
# from_port = -1
# to_port = -1
# protocol = "icmp"
# cidr_blocks = ["0.0.0.0/0"]
# }

# Allow all outbound traffic for simplicity (consider restricting later)
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}

}

# Launch the EC2 instance
resource "aws_instance" "webapp_linux" {
# Use data source to retrieve the latest Ubuntu AMI
ami = "ami-007020fd9c84e18c7"

instance_type = "t2.micro" # Adjust instance type as needed

# Ensure you have a key pair created and named "customer-keypair" in AWS
key_name = "webapp_keypair"

# Securely encode the user data script with base64encode
user_data = base64encode(<<EOF
#!/bin/bash

# Update package list for Ubuntu
sudo apt update -y

# Install Nginx web server
sudo apt install nginx -y

# Start the Nginx service
sudo systemctl start nginx

# Enable Nginx to start automatically on boot
sudo systemctl enable nginx

# Create and populate the index.html file with hostname and IP address
cat <<EOF > /var/www/html/index.html
<!DOCTYPE html>
<html>
<head>
<title>Welcome to My Web App!</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #f0f0f0;
}
.container {
max-width: 800px;
margin: 50px auto;
padding: 20px;
background-color: #fff;
border-radius: 5px;
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
}
</style>
</head>
<body>
<div class="container">
<h1>Welcome to My Web App!</h1>
<p><strong>Hostname:</strong> $(hostname)</p>
<p><strong>IP Address:</strong> $(hostname -I | awk '{print $1}')</p>
</div>
</body>
</html>
EOF


)

# Tag the instance for easy identification
tags = {
Name = "Webapp-Linux-Instance"
}

# Associate the instance with a security group
vpc_security_group_ids = [aws_default_security_group.default.id]

# Associate the instance with a subnet
subnet_id = aws_subnet.WEB_APP_SUBNET.id

# Enable auto-assign public IP (optional)
associate_public_ip_address = true
}

# Output the public IP address of the instance (optional)
output "webapp_public_ip" {
value = aws_instance.webapp_linux.public_ip
}
Setting up AWS VPC Transit Gateway using Terraform 7
ec2-backend-services.tf
# Create a security group named 'customer-securitygrp' with ingress rules
resource "aws_default_security_group" "default2" {
vpc_id = aws_vpc.BACKEND_SERVICES_VPC.id
tags = {
Name = "BackendServices-sg"
}


# Allow SSH access from your specific IP or CIDR block (replace with yours)
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}

# Allow HTTP access from anywhere for testing (consider restricting later)
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}

# Remove unnecessary ICMP rule for web applications (optional)
# ingress {
# from_port = -1
# to_port = -1
# protocol = "icmp"
# cidr_blocks = ["0.0.0.0/0"]
# }

# Allow all outbound traffic for simplicity (consider restricting later)
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}

# Launch the EC2 instance
resource "aws_instance" "backendservices_linux" {
# Use data source to retrieve the latest Ubuntu AMI
ami = "ami-007020fd9c84e18c7"

instance_type = "t2.micro" # Adjust instance type as needed

# Ensure you have a key pair created and named "customer-keypair" in AWS
key_name = "webapp_keypair"

# Securely encode the user data script with base64encode
user_data = base64encode(<<EOF
#!/bin/bash

# Update package list for Ubuntu
sudo apt update -y

# Install Nginx web server
sudo apt install nginx -y

# Start the Nginx service
sudo systemctl start nginx

# Enable Nginx to start automatically on boot
sudo systemctl enable nginx

# Create and populate the index.html file with hostname and IP address
cat <<EOF > /var/www/html/index.html
<!DOCTYPE html>
<html>
<head>
<title>Welcome to My Web App!</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #f0f0f0;
}
.container {
max-width: 800px;
margin: 50px auto;
padding: 20px;
background-color: #fff;
border-radius: 5px;
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
}
</style>
</head>
<body>
<div class="container">
<h1>Welcome to My Web App!</h1>
<p><strong>Hostname:</strong> $(hostname)</p>
<p><strong>IP Address:</strong> $(hostname -I | awk '{print $1}')</p>
</div>
</body>
</html>
EOF


)

# Tag the instance for easy identification
tags = {
Name = "Backend-Services-Linux-Instance"
}

# Associate the instance with a security group
vpc_security_group_ids = [aws_default_security_group.default2.id]

# Associate the instance with a subnet
subnet_id = aws_subnet.BACKEND_SERVICES_SUBNET.id

# Enable auto-assign public IP (optional)
associate_public_ip_address = true
}

# Output the public IP address of the instance (optional)
output "backendservices_public_ip" {
value = aws_instance.backendservices_linux.public_ip
}
Setting up AWS VPC Transit Gateway using Terraform 8
ec2-shared-database.tf
# Create a security group named 'customer-securitygrp' with ingress rules
resource "aws_default_security_group" "default3" {
vpc_id = aws_vpc.SHARED_DATABASE_VPC.id
tags = {
Name = "Shareddatabase-sg"
}


# Allow SSH access from your specific IP or CIDR block (replace with yours)
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}

# Allow HTTP access from anywhere for testing (consider restricting later)
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}

# Remove unnecessary ICMP rule for web applications (optional)
# ingress {
# from_port = -1
# to_port = -1
# protocol = "icmp"
# cidr_blocks = ["0.0.0.0/0"]
# }

# Allow all outbound traffic for simplicity (consider restricting later)
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}

# Launch the EC2 instance
resource "aws_instance" "shareddatabase_linux" {
# Use data source to retrieve the latest Ubuntu AMI
ami = "ami-007020fd9c84e18c7"

instance_type = "t2.micro" # Adjust instance type as needed

# Ensure you have a key pair created and named "customer-keypair" in AWS
key_name = "webapp_keypair"

# Securely encode the user data script with base64encode
user_data = base64encode(<<EOF
#!/bin/bash

# Update package list for Ubuntu
sudo apt update -y

# Install Nginx web server
sudo apt install nginx -y

# Start the Nginx service
sudo systemctl start nginx

# Enable Nginx to start automatically on boot
sudo systemctl enable nginx

# Create and populate the index.html file with hostname and IP address
cat <<EOF > /var/www/html/index.html
<!DOCTYPE html>
<html>
<head>
<title>Welcome to My Web App!</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #f0f0f0;
}
.container {
max-width: 800px;
margin: 50px auto;
padding: 20px;
background-color: #fff;
border-radius: 5px;
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
}
</style>
</head>
<body>
<div class="container">
<h1>Welcome to My Web App!</h1>
<p><strong>Hostname:</strong> $(hostname)</p>
<p><strong>IP Address:</strong> $(hostname -I | awk '{print $1}')</p>
</div>
</body>
</html>
EOF


)

# Tag the instance for easy identification
tags = {
Name = "SharedDatabase-Linux-Instance"
}

# Associate the instance with a security group
vpc_security_group_ids = [aws_default_security_group.default3.id]

# Associate the instance with a subnet
subnet_id = aws_subnet.SHARED_DATABASE_SUBNET.id

# Enable auto-assign public IP (optional)
associate_public_ip_address = true
}

# Output the public IP address of the instance (optional)
output "shared_database_public_ip" {
value = aws_instance.shareddatabase_linux.public_ip
}
Setting up AWS VPC Transit Gateway using Terraform 9

Step#6:Create Transit Gateway

transit_gateway.tf
resource "aws_ec2_transit_gateway" "example" {
description = "tg-web-backend-database"
tags = {
Name = "Web-Backend-Database Transit Gateway"
}
}
Setting up AWS VPC Transit Gateway using Terraform 10

Step#7:Create Transit Gateway Attachment

transit_gateway_attachment.tf
# Attach WEB_APP_VPC to the Transit Gateway
resource "aws_ec2_transit_gateway_vpc_attachment" "web_app_attachment" {
# ID of the Transit Gateway
transit_gateway_id = aws_ec2_transit_gateway.example.id
subnet_ids = [
aws_subnet.WEB_APP_SUBNET.id # Reference the created subnet ID
]
# VPC ID to be attached
vpc_id = aws_vpc.WEB_APP_VPC.id

# Optional tags for identification
tags = {
Name = "Web App VPC Attachment"
}
}
# Attach WEB_APP_VPC to the Transit Gateway
resource "aws_ec2_transit_gateway_vpc_attachment" "backend_services_attachment" {
# ID of the Transit Gateway
transit_gateway_id = aws_ec2_transit_gateway.example.id
subnet_ids = [
aws_subnet.BACKEND_SERVICES_SUBNET.id # Reference the created subnet ID
]
# VPC ID to be attached
vpc_id = aws_vpc.BACKEND_SERVICES_VPC.id

# Optional tags for identification
tags = {
Name = "Backend Services VPC Attachment"
}
}
# Attach WEB_APP_VPC to the Transit Gateway
resource "aws_ec2_transit_gateway_vpc_attachment" "shared_database_attachment" {
# ID of the Transit Gateway
transit_gateway_id = aws_ec2_transit_gateway.example.id
subnet_ids = [
aws_subnet.SHARED_DATABASE_SUBNET.id # Reference the created subnet ID
]
# VPC ID to be attached
vpc_id = aws_vpc.SHARED_DATABASE_VPC.id

# Optional tags for identification
tags = {
Name = "Shared database VPC Attachment"
}
}

Step#8:Let’s Apply Configuration

Let’s run our configuration and make sure everything works correctly. On the command line, run the following commands:

  • terraform init
  • terraform plan
  • terraform apply -auto-approve

Step#9:Verify Connectivity Between VPCs

This step is optional but highly recommended to confirm successful communication between your VPCs through the Transit Gateway. Here’s how to proceed:

1. Gather Private IPs:

  • In the AWS Management Console, navigate to the EC2 service.
  • Locate the EC2 instances you launched in each VPC (web-app-vpc, backend-services-vpc, shared-database-vpc).
  • Identify Private IPs:
    • For each instance, note down its private IP address. You’ll need the private IPs of the backend service instance in backend-services-vpc and the shared database instance in shared-database-vpc.
Setting up AWS VPC Transit Gateway using Terraform 11
Setting up AWS VPC Transit Gateway using Terraform 12

2. Connect to Web Application Instance (web-app-vpc):

  • Use a method like SSH to connect to the EC2 instance launched in web-app-vpc. This is the instance hosting your web application.

3. Test Connectivity with curl:

  • Once connected to the web application instance, use the curl command to attempt communication with the backend service and shared database instances in other VPCs.
Setting up AWS VPC Transit Gateway using Terraform 13
Setting up AWS VPC Transit Gateway using Terraform 14

Step#10:Delete all the resources created

To delete all resources created just enter the below command:

terraform destroy -auto-approve

Conclusion:

In conclusion, leveraging Terraform for AWS VPC Transit Gateway setup streamlines network management, enhances VPC connectivity, and optimizes resource accessibility across multiple VPCs, ensuring efficient and scalable infrastructure deployment.

Reference:-

For reference visit the official website .

Any queries pls contact us @Fosstechnix.com.

Related Articles:

How to Create VPC in AWS using Terraform

Akash Bhujbal

Hey, I am Akash Bhujbal, I am an aspiring DevOps and Cloud enthusiast who is eager to embark on a journey into the world of DevOps and Cloud. With a strong passion for technology and a keen interest in DevOps and Cloud based solutions, I am driven to learn and contribute to the ever-evolving field of DevOps and Cloud.

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Share via
Copy link
Powered by Social Snap