❌

Normal view

There are new articles available, click to refresh the page.
Before yesterdayMain stream

Deploying a Scalable AWS Infrastructure with VPC, ALB, and Target Groups Using Terraform

By: Ragul.M
11 March 2025 at 06:01

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 :)

Terraform code for AWS Postgresql RDS

7 January 2024 at 17:19

create directory postgres and navigate
$ mkdir postgres && cd postgres
create main.tf file
$ vim main.tf

provider "aws" {
}
resource "aws_security_group" "rds_sg" {
name = "rds_sg"
ingress {
from_port = 5432
to_port = 5432
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}

resource "aws_db_instance" "myinstance" {
engine = "postgres"
identifier = "myrdsinstance"
allocated_storage = 20
engine_version = "14"
instance_class = "db.t3.micro"
username = "myrdsuser"
password = "myrdspassword"
parameter_group_name = "default.postgres14"
vpc_security_group_ids = ["${aws_security_group.rds_sg.id}"]
skip_final_snapshot = true
publicly_accessible = true
}

output "rds_endpoint" {
value = "${aws_db_instance.myinstance.endpoint}"
}

save and exit
$ terraform init
$ terraform plan
$ terraform apply -auto-approve
Install postgres client in local machine
$ sudo apt install -y postgresql-client
To access AWS postgresql RDS instance
$ psql -h <end_point_URL> –p=5432 –username=myrdsuser –password –dbname=mydb
To destroy postgresql RDS instance
$ terraform destroy -auto-approve

Terraform code for AWS MySQL RDS

7 January 2024 at 17:12

create directory mysql and navigate
$ mkdir mysql && cd mysql
create main.tf
$ vim main.tf

provider "aws" {
}
resource "aws_security_group" "rds_sg" {
name = "rds_sg"
ingress {
from_port = 3306
to_port = 3306
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}

resource "aws_db_instance" "myinstance" {
engine = "mysql"
identifier = "myrdsinstance"
allocated_storage = 20
engine_version = "5.7"
instance_class = "db.t2.micro"
username = "myrdsuser"
password = "myrdspassword"
parameter_group_name = "default.mysql5.7"
vpc_security_group_ids = ["${aws_security_group.rds_sg.id}"]
skip_final_snapshot = true
publicly_accessible = true
}

output "rds_endpoint" {
value = "${aws_db_instance.myinstance.endpoint}"
}

save and exit
$ terraform init
$ terraform plan
$ terraform apply -auto-approve
install mysql client in local host
$ sudo apt install mysql-client
To access the mysql
$ mysql -h <end_point_URL> -P 3306 -u <username> -p
To destroy the mysql RDS instance
$ terraform destroy -auto-approve

code for s3 bucket creation and public access

7 January 2024 at 12:55
provider "aws" {
region = "ap-south-1"
}

resource "aws_s3_bucket" "example" {
bucket = "example-my"
}

resource "aws_s3_bucket_ownership_controls" "ownership" {
bucket = aws_s3_bucket.example.id
rule {
object_ownership = "BucketOwnerPreferred"
}
}

resource "aws_s3_bucket_public_access_block" "pb" {
bucket = aws_s3_bucket.example.id

block_public_acls = false
block_public_policy = false
ignore_public_acls = false
restrict_public_buckets = false
}

resource "aws_s3_bucket_acl" "acl" {
depends_on = [aws_s3_bucket_ownership_controls.ownership]
bucket = aws_s3_bucket.example.id
acl = "private"
}

S3 bucket creation and object storage

7 January 2024 at 12:51

create directory s3-demo and navigate
$ mkdir s3-demo && cd s3-demo
create a demo file sample.txt and contents
$ echo β€œthis is sample object to store in demo-bucket” > sample.txt
create main.tf file
$ vim main.tf

provider "aws" {
region = "ap-south-1"
}

resource "aws_s3_bucket" "example" {
bucket = "mydemo-bucket1"
}

resource "aws_s3_object" "object" {
bucket = aws_s3_bucket.example.bucket
key = "sample.txt"
source = "./sample.txt"
}

save and exit
$ terraform init
$ terraform plan
$ terraform apply -auto-approve

create S3 bucket using terraform

7 January 2024 at 12:45

create directory s3 and navigate to the directory
$ mkdir s3 && cd s3
create main.tf file
$ vim main.tf

provider "aws" {
region = "ap-south-1"
}

resource "aws_s3_bucket" "my_bucket" {
bucket = "mydemo-bucket"
}

save and exit
$ terraform init
$ terraform plan
$ terraform apply -auto-approve
To destroy the bucket
$ terraform destroy -auto-approve

How to create AWS EC2 instance using Terraform

7 January 2024 at 06:36

create directory ec2 and navigate to the directory
$ mkdir ec2 && cd ec2
create main.tf file
$ vim main.tf

provider "aws" {
region = "ap-south-1"
}

resource "aws_instance" "app_server" {
ami = "ami-03f4878755434977f"
instance_type = "t2.nano"
subnet_id = "subnet-0ccba3b8cfd0645e2"
key_name = "awskey"
associate_public_ip_address = "true"
tags = {
Name = "demo-server"
}
}

output "public_ip" {
description = "public ip of the instance"
value = aws_instance.app_server.public_ip
}

save and exit
initialize the terraform
$ terraform init
$ terraform plan
$ terraform apply -auto-approve
it will create the AWS EC2 instance with output the public ip of the instance

To destroy the instance
$ terraform destroy -auto-approve

How to install Terraform in Ubuntu

7 January 2024 at 06:16

Method1: Package manager
$ wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg –dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
$ echo β€œdeb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main” | sudo tee /etc/apt/sources.list.d/hashicorp.list
$ sudo apt update && sudo apt install terraform
$ terraform version
To get help options
$ terraform -h

Method2: Binary download
download the binary from wget https://developer.hashicorp.com/terraform/downloads
$ wget https://releases.hashicorp.com/terraform/1.6.6/terraform_1.6.6_linux_amd64.zip

extract using unzip
$ unzip terraform_1.6.6_linux_amd64.zip
$ mv terraform /usr/local/bin/
$ terraform version
$ terraform -h

To remove terraform binary method
$ sudo rm -f /usr/local/bin/terraform

To remove terraform package manager method
$ sudo apt remove terraform --purge

❌
❌