Terraform Project🤩
Two-Tier AWS Architecture
A highly available two-tier AWS architecture can be created by creating a custom VPC with two public subnets for the web server tier and two private subnets for the RDS tier.
An internet-facing application load balancer is also created to distribute traffic to the web servers.
The ALB security group is configured with needed permissions and modifications are made to the web servers security group to reflect the new architecture.
Custom modules are used to build out the code for repeatability. Terraform Cloud is used as a CI/CD tool to check the build and push the code to GitHub.
Prerequisite:
kindly visit the Terraform basics before getting into this project, My previous blogs on Terraform Installation, Code Explanation, Backup State files on DynamoDB… | DAY -1 | DAY -2 | DAY -3 | DAY-4 |
STEP 1: Create AWS Instance by adding userdata
#!/bin/bash
# Install dependencies
sudo apt-get update
sudo apt install fish -y
# Terraform Installation
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
sudo su
terraform --version
STEP 2: Login as an IAM user
apt install awscli
aws configure
#login with user access_key and secret_key
aws s3 ls
STEP 3: Log-in to the Terraform Cloud
The Terraform login command is used to authenticate with a Terraform Cloud or Terraform Enterprise server.
Terraform login
git clone https://github.com/hashicorp/tfc-getting-started.git
cd tfc-getting-started
scripts/setup.sh
apt install jq
scripts/setup.sh
STEP 4: Set ENV VARIABLES
export TF_VAR_AWS_ACCESS_KEY_ID=AKIAVFX3BOVUEAJMF7YK
export TF_VAR_AWS_SECRET_ACCESS_KEY=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
mkdir -p ./ProviderModule
ls -lrta
STEP 5: Create terraform.tf file and provider.tf file
terraform {
cloud {
organization = "rajcloud12"
workspaces {
name = "rajcloud12"
}
}
}
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 4.0"
}
}
required_version = ">= 1.3.0"
}
provider "aws" {
region = "us-east-1"
}
#VPC
resource "aws_vpc" "main" {
cidr_block = "10.10.0.0/16"
instance_tenancy = "default"
tags = {
Name = "2TierArchitecture"
}
}
#AWS instance - linux
resource "aws_instance" "web_tier1" {
ami = "ami-09988af04120b3591"
key_name = "Project4EC2"
associate_public_ip_address = true
subnet_id = aws_subnet.public1.id
instance_type = "t2.micro"
vpc_security_group_ids = [aws_security_group.web_tier.id]
user_data = <<-EOF
#!/bin/bash
yum update -y
yum install httpd -y
systemctl start httpd
systemctl enable httpd
echo "<html><body><h1>Welcome to AWS WebTier One 2023! Powered byTerraform
</h1></body></html>" > /var/www/html/index.html
EOF
}
resource "aws_instance" "web_tier2" {
ami = "ami-09988af04120b3591"
key_name = "Project4EC2"
associate_public_ip_address = true
subnet_id = aws_subnet.public2.id
instance_type = "t2.micro"
vpc_security_group_ids = [aws_security_group.web_tier.id]
user_data = <<-EOF
#!/bin/bash
yum update -y
yum install httpd -y
systemctl start httpd
systemctl enable httpd
echo "<html><body><h1>Welcome to AWS WebTier Two 2023!!! Powered by Terrafrom
</h1></body></html>" > /var/www/html/index.html
EOF
}
#create Load Balancer
resource "aws_lb" "myalb" {
name = "2TierApplicationLoadBalancer"
internal = false
load_balancer_type = "application"
subnets = [aws_subnet.public1.id, aws_subnet.public2.id]
security_groups = [aws_security_group.albsg.id]
}
#create Security group
resource "aws_security_group" "albsg" {
name = "albsg"
description = "security group for alb"
vpc_id = aws_vpc.main.id
ingress {
from_port = "0"
to_port = "0"
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = "0"
to_port = "0"
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
#create Target group
resource "aws_lb_target_group" "tg" {
name = "projecttg"
port = 80
protocol = "HTTP"
vpc_id = aws_vpc.main.id
depends_on = [aws_vpc.main]
}
#attaches an EC2 instance to an Elastic Load Balancing (ELB) target group
resource "aws_lb_target_group_attachment" "tgattach1" {
target_group_arn = aws_lb_target_group.tg.arn
target_id = aws_instance.web_tier1.id
port = 80
depends_on = [aws_instance.web_tier1]
}
#attaches an EC2 instance to an Elastic Load Balancing (ELB) target group
resource "aws_lb_target_group_attachment" "tgattach2" {
target_group_arn = aws_lb_target_group.tg.arn
target_id = aws_instance.web_tier2.id
port = 80
depends_on = [aws_instance.web_tier2]
}
#Elastic Load Balancing (ELB) listener.
resource "aws_lb_listener" "listenerlb" {
load_balancer_arn = aws_lb.myalb.arn
port = "80"
protocol = "HTTP"
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.tg.arn
}
}
#public subnets
resource "aws_subnet" "public1" {
vpc_id = aws_vpc.main.id
cidr_block = "10.10.1.0/24"
availability_zone = "us-east-1a"
map_public_ip_on_launch = true
tags = {
Name = "public1"
}
}
resource "aws_subnet" "public2" {
vpc_id = aws_vpc.main.id
cidr_block = "10.10.2.0/24"
availability_zone = "us-east-1b"
map_public_ip_on_launch = true
tags = {
Name = "public2"
}
}
#private subnets
resource "aws_subnet" "private1" {
vpc_id = aws_vpc.main.id
cidr_block = "10.10.3.0/24"
availability_zone = "us-east-1a"
map_public_ip_on_launch = false
tags = {
Name = "private1"
}
}
resource "aws_subnet" "private2" {
vpc_id = aws_vpc.main.id
cidr_block = "10.10.4.0/24"
availability_zone = "us-east-1b"
map_public_ip_on_launch = false
tags = {
Name = "private2"
}
}
#Rational Database Service (RDS)
resource "aws_db_subnet_group" "sub_4_db" {
name = "sub_4_db"
subnet_ids = [aws_subnet.private1.id, aws_subnet.private2.id]
tags = {
Name = "My DB subnet group"
}
}
#IGW Internet Gateway
resource "aws_internet_gateway" "gw" {
vpc_id = aws_vpc.main.id
tags = {
Name = "InternetGateway2023"
}
}
#route table
resource "aws_route_table" "Web_Tier" {
tags = {
Name = "Web_Tier"
}
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.gw.id
}
}
#associate route table with the subnet
resource "aws_route_table_association" "Web_tier" {
subnet_id = aws_subnet.public1.id
route_table_id = aws_route_table.Web_Tier.id
}
resource "aws_route_table_association" "Web_tier2" {
subnet_id = aws_subnet.public2.id
route_table_id = aws_route_table.Web_Tier.id
}
#create another route table
resource "aws_route_table" "DabaseTier" {
tags = {
Name = "DatabaseTier"
}
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.gw.id
}
}
#create Elastic ip
resource "aws_eip" "nat_eip" {
vpc = true
}
#Create a NAT gateway
resource "aws_nat_gateway" "gw" {
allocation_id = aws_eip.nat_eip.id
subnet_id = aws_subnet.public2.id
}
#creates a route table in VPC and associates it with a NAT gateway
resource "aws_route_table" "my_public2_nated" {
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0"
nat_gateway_id = aws_nat_gateway.gw.id
}
tags = {
Name = "Main Route Table for NAT- subnet"
}
}
#Terrafrom resource associates two subnets in VPC with a route table that is configured for NAT.
resource "aws_route_table_association" "my_public2_nated1" {
subnet_id = aws_subnet.private1.id
route_table_id = aws_route_table.my_public2_nated.id
}
resource "aws_route_table_association" "my_public2_nated2" {
subnet_id = aws_subnet.private2.id
route_table_id = aws_route_table.my_public2_nated.id
}
# Terraform resource creates a security group in an Amazon Web Services (AWS) VPC and allows inbound
#traffic on ports 22 (SSH) and 80 (HTTP).
resource "aws_security_group" "web_tier" {
name = "web_tier"
description = "web and SSH allowed"
vpc_id = aws_vpc.main.id
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
# Terraform resource creates a security group in an Amazon Web Services (AWS) VPC and allows inbound traffic
#on port 3306 (MySQL) from the web tier security group and on port 22 (SSH) from anywhere.
resource "aws_security_group" "db_tier" {
name = "Database SecurityGroup 2023"
description = "allow traffic from Web Tier & SSH"
vpc_id = aws_vpc.main.id
ingress {
from_port = 3306
to_port = 3306
protocol = "tcp"
cidr_blocks = ["10.10.0.0/16"]
security_groups = [aws_security_group.web_tier.id]
}
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
#Terraform configuration that defines an Amazon Relational Database Service (RDS) database instance
resource "aws_db_instance" "the_db" {
allocated_storage = 10
db_name = "mydb"
engine = "mysql"
engine_version = "5.7"
instance_class = "db.t2.micro"
db_subnet_group_name = aws_db_subnet_group.sub_4_db.id
vpc_security_group_ids = [aws_security_group.db_tier.id]
username = "admin"
password = "admin"
parameter_group_name = "default.mysql5.7"
skip_final_snapshot = true
}
AWS InternetGateway |AWS SubnetGroups |
AWS Subnets |VPC | LoadBalancer | SecurityGroup |
DatabaseSecurityGroup |LB-TargetGroup | LB-Listener|
RouteTable |RouteTableAssociation | Elastic IPaddress |
NAT Gateway | EC2 Instances |RDS |
The Individual Links for the Terraform AWS Documentation
STEP 6: Initialize Terraform 😍
Enter the terraform init — upgrade command, it will upgrade all of the providers that are used in the Terraform configuration to the latest version and The terraform fmt command is used to format Terraform configuration files into a canonical format and style
terraform init -upgrade
terraform fmt
terraform validate
terraform plan
(If you face any error for credentials, add access_key and secret_key on the provider.tf file)
STEP 7: Terraform Cloud as a CI/CD tool
terraform apply
🔥BOOM!!!! Successfully created our two-tier architecture
STEP 8: OUTPUTS
STEP 9: Implementing CICD with Terraform Cloud Version Control.
- Login to GitHub and Create a New Repo
In Terraform Cloud, rajcloud12/ settings/ version control
Select Version Control Workflow
Select Github
Checkout my GitHub Page: rajcloud12/Terraform_project
STEP 10: Terraform Destroy
Don’t forget to delete the created architecture
terraform destroy
We’ve created a scalable AWS architecture with a custom VPC, load balancer, and secure subnets. Our use of custom modules and Terraform Cloud ensures repeatability and CI/CD. This highly available design demonstrates our expertise in delivering reliable and high-performance infrastructure.
#devops #CICD #terraform #hcl #aws
Thanks for taking the time to read my blog,I welcome any constructive feedback you may have, as it will help me to improve.let's stay connected
Linkedin: https://www.linkedin.com/in/raj-kumar-devops/
Website: https://bento.me/rajdevops
For more Projects: https://medium.com/@rajdevops
I’m actively searching for new opportunities and eager to broaden my professional network.