Introduction
In this blog, we will walk through the process of deploying a scalable AWS infrastructure using Terraform. The setup includes:
- A VPC with public and private subnets
- An Internet Gateway for public access
- Application Load Balancers (ALBs) for distributing traffic
- Target Groups and EC2 instances for handling incoming requests
- By the end of this guide, you’ll have a highly available setup with proper networking, security, and load balancing.
Step 1: Creating a VPC with Public and Private Subnets
The first step is to define our Virtual Private Cloud (VPC) with four subnets (two public, two private) spread across multiple Availability Zones.
Terraform Code: vpc.tf
resource "aws_vpc" "main_vpc" {
cidr_block = "10.0.0.0/16"
}
# Public Subnet 1 - ap-south-1a
resource "aws_subnet" "public_subnet_1" {
vpc_id = aws_vpc.main_vpc.id
cidr_block = "10.0.1.0/24"
availability_zone = "ap-south-1a"
map_public_ip_on_launch = true
}
# Public Subnet 2 - ap-south-1b
resource "aws_subnet" "public_subnet_2" {
vpc_id = aws_vpc.main_vpc.id
cidr_block = "10.0.2.0/24"
availability_zone = "ap-south-1b"
map_public_ip_on_launch = true
}
# Private Subnet 1 - ap-south-1a
resource "aws_subnet" "private_subnet_1" {
vpc_id = aws_vpc.main_vpc.id
cidr_block = "10.0.3.0/24"
availability_zone = "ap-south-1a"
}
# Private Subnet 2 - ap-south-1b
resource "aws_subnet" "private_subnet_2" {
vpc_id = aws_vpc.main_vpc.id
cidr_block = "10.0.4.0/24"
availability_zone = "ap-south-1b"
}
# Internet Gateway for Public Access
resource "aws_internet_gateway" "igw" {
vpc_id = aws_vpc.main_vpc.id
}
# Public Route Table
resource "aws_route_table" "public_rt" {
vpc_id = aws_vpc.main_vpc.id
}
resource "aws_route" "internet_access" {
route_table_id = aws_route_table.public_rt.id
destination_cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.igw.id
}
resource "aws_route_table_association" "public_assoc_1" {
subnet_id = aws_subnet.public_subnet_1.id
route_table_id = aws_route_table.public_rt.id
}
resource "aws_route_table_association" "public_assoc_2" {
subnet_id = aws_subnet.public_subnet_2.id
route_table_id = aws_route_table.public_rt.id
}
This configuration ensures that our public subnets can access the internet, while our private subnets remain isolated.
Step 2: Setting Up Security Groups
Next, we define security groups to control access to our ALBs and EC2 instances.
Terraform Code: security_groups.tf
resource "aws_security_group" "alb_sg" {
vpc_id = aws_vpc.main_vpc.id
# Allow HTTP and HTTPS traffic to ALB
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
# Allow outbound traffic
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
This allows public access to the ALB but restricts other traffic.
Step 3: Creating the Application Load Balancers (ALB)
Now, let’s define two ALBs—one public and one private.
Terraform Code: alb.tf
# Public ALB
resource "aws_lb" "public_alb" {
name = "public-alb"
internal = false
load_balancer_type = "application"
security_groups = [aws_security_group.alb_sg.id]
subnets = [aws_subnet.public_subnet_1.id, aws_subnet.public_subnet_2.id]
}
# Private ALB
resource "aws_lb" "private_alb" {
name = "private-alb"
internal = true
load_balancer_type = "application"
security_groups = [aws_security_group.alb_sg.id]
subnets = [aws_subnet.private_subnet_1.id, aws_subnet.private_subnet_2.id]
}
This ensures redundancy and distributes traffic across different subnets.
Step 4: Creating Target Groups for EC2 Instances
Each ALB needs target groups to route traffic to EC2 instances.
Terraform Code: target_groups.tf
resource "aws_lb_target_group" "public_tg" {
name = "public-tg"
port = 80
protocol = "HTTP"
vpc_id = aws_vpc.main_vpc.id
}
resource "aws_lb_target_group" "private_tg" {
name = "private-tg"
port = 80
protocol = "HTTP"
vpc_id = aws_vpc.main_vpc.id
}
These target groups allow ALBs to forward requests to backend EC2 instances.
Step 5: Launching EC2 Instances
Finally, we deploy EC2 instances and register them with the target groups.
Terraform Code: ec2.tf
resource "aws_instance" "public_instance" {
ami = "ami-0abcdef1234567890" # Replace with a valid AMI ID
instance_type = "t2.micro"
subnet_id = aws_subnet.public_subnet_1.id
}
resource "aws_instance" "private_instance" {
ami = "ami-0abcdef1234567890" # Replace with a valid AMI ID
instance_type = "t2.micro"
subnet_id = aws_subnet.private_subnet_1.id
}
These instances will serve web requests.
Step 6: Registering Instances to Target Groups
resource "aws_lb_target_group_attachment" "public_attach" {
target_group_arn = aws_lb_target_group.public_tg.arn
target_id = aws_instance.public_instance.id
}
resource "aws_lb_target_group_attachment" "private_attach" {
target_group_arn = aws_lb_target_group.private_tg.arn
target_id = aws_instance.private_instance.id
}
This registers our EC2 instances as backend servers.
Final Step: Terraform Apply!
Run the following command to deploy everything:
terraform init
terraform apply -auto-approve
Once completed, you’ll get ALB DNS names, which you can use to access your deployed infrastructure.
Conclusion
This guide covered how to deploy a highly available AWS infrastructure using Terraform, including VPC, subnets, ALBs, security groups, target groups, and EC2 instances. This setup ensures a secure and scalable architecture.
Follow for more and happy learning :)
Top comments (0)