Creating an Architecture using Terraform on AWS —Terraform Case Study

Visal Tyagi
DevOps-Guides
Published in
10 min readApr 22, 2024

--

You work as a DevOps Engineer in a leading software company. You have been asked to build an infrastructure safely and efficiently.

The company’s requirements:

1. Use AWS Cloud Provider and the software to be installed is Apache2

2. Use Ubuntu AMI

The company wants the architecture to have the following services:

1. Create a template with a VPC, 2 subnets, and 1 instance in each subnet

2. Attach security groups, internet gateway, and network interface to the instance

Apache2 Installed
Apache2 Installed

Terraform Case Study Git Repository, Click here to check:

1. Create an EC2 Instance as “Master”

Step 1: Go to the “Services” section & search “EC2” here.

Search EC2
Search EC2

Step 2: Click on “Launch Instance”.

Launch Instance
Launch Instance

Step 3: Choose “Name” as “Master” in the “Name and tags” section.

Master Instance
Master Instance

Step 4: Choose “AMI” as “ubuntu”.

Ubuntu AMI
Ubuntu AMI

Step 5: Choose “Instance type” as “t2.micro”.

t2.micro
t2.micro

Step 6: Choose “key pair (login)” as “Terraform”.

Terraform Key Pair
Terraform Key Pair

Step 7: Choose “Select existing security group” as “launch-wizard-1”.

Select Security Group
Select Security Group

Step 8: Click on “Launch Instance”.

Launch Instance Click
Launch Instance Click

Step 9: Instance will be launched. Click on “hyperlink”.

Click Hyperlink
Click Hyperlink

Step 10: The instance will be in the “Running” State.

Running State
Running State

Step 11: Select the instance & click on “Connect”.

Click Connect
Click Connect

Step 12: Click on “Connect” again.

Connect Again
Connect Again

Step 13: The instance will be successfully connected.

Instance Connected
Instance Connected

2. Install “Terraform” on “Master”

Step 1: Install Terraform, create a “terraform-install.sh” file to install Terraform.

terraform-install.sh
terraform-install.sh

Step 2: Paste this Script here:

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 -y
Terraform Installation Script
Terraform Installation Script

Save & exit from the file. Use CTRL+X to exit & press “Yes” to save. Press “enter” to completely exit from the file.

Step 3: Run this command: bash install.sh to install Terraform.

Run Bash Command
Run Bash Command

Step 4: Terraform will be successfully installed.

bash
bash
Terraform Installed
Terraform Installed

Step 5: Run this command: terraform –version to check the “Terraform Version”.

terraform --version
Terraform Version
Terraform Version

3. Create a Script for VPC, 2 Subnets, Security Group, Elastic Network Interface & Internet Gateway with 2 Instances.

A. Create a VPC

# Create a VPC

resource "aws_vpc" "testvpc" {
cidr_block = "10.0.0.0/16"

tags = {
Name = "testvpc"
}
}

B. Create a Public & Private Subnet

# Create a Public Subnet

resource "aws_subnet" "testsbnt1" {
vpc_id = aws_vpc.testvpc.id
cidr_block = "10.0.1.0/24"
map_public_ip_on_launch = "true"
availability_zone = "us-east-2a"

tags = {
Name = "testsbnt1"
}
}
# Create a Private Subnet

resource "aws_subnet" "testsbnt2" {
vpc_id = aws_vpc.testvpc.id
cidr_block = "10.0.2.0/24"
map_public_ip_on_launch = "false"
availability_zone = "us-east-2b"

tags = {
Name = "testsbnt2"
}
}

C. Create an Internet Gateway

# Create an Internet Gateway

resource "aws_internet_gateway" "testigw" {
vpc_id = aws_vpc.testvpc.id
tags = {
Name = "testigw"
}
}

D. Create Route Tables for Public & Private Subnets

# Create a Route Table for Public Subnet

resource "aws_route_table" "testrtb1" {
vpc_id = aws_vpc.testvpc.id

route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.testigw.id
}

route {
ipv6_cidr_block = "::/0"
gateway_id = aws_internet_gateway.testigw.id
}
}
# Associate Public Route Table with Public Subnet

resource "aws_route_table_association" "testassoc1" {
subnet_id = aws_subnet.testsbnt1.id
route_table_id = aws_route_table.testrtb1.id
}
# Create a Private Route Table for Subnet 2

resource "aws_route_table" "testrtb2" {
vpc_id = aws_vpc.testvpc.id

route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_nat_gateway.nat.id
}

tags = {
Name = "testrtb2"
}
}
# Associate Route Table with Private Subnet

resource "aws_route_table_association" "testassoc2" {
subnet_id = aws_subnet.testsbnt2.id
route_table_id = aws_route_table.testrtb2.id
}

E. Create Elastic Network Interface with Elastic IP

  # Assign ENI with IP

resource "aws_network_interface" "testeni1" {
subnet_id = aws_subnet.testsbnt1.id
private_ips = ["10.0.1.10"]
security_groups = [aws_security_group.testsg.id]
}

resource "aws_network_interface" "testeni2" {
subnet_id = aws_subnet.testsbnt2.id
private_ips = ["10.0.2.10"]
security_groups = [aws_security_group.testsg.id]
}

# Assign Elastic IP to ENI

resource "aws_eip" "testeip1" {
domain = "vpc"
network_interface = aws_network_interface.testeni1.id
associate_with_private_ip = "10.0.1.10"
depends_on= [aws_internet_gateway.testigw, aws_instance.Instance1]
tags = {
Name = "testeip1"
}
}
# Create an Elastic IP Address for NAT Gateway

resource "aws_eip" "testeip2" {
domain = "vpc"
associate_with_private_ip = "10.0.2.10"
depends_on= [aws_internet_gateway.testigw]
tags = {
Name = "testeip2"
}
}

F. Create a NAT Gateway for VPC

# Create a NAT Gateway for VPC

resource "aws_nat_gateway" "nat" {
allocation_id = aws_eip.testeip2.id
subnet_id = aws_subnet.testsbnt2.id

tags = {
Name = "nat"
}
}

G. Create a Security Group for Instance

# Create a Security Group

resource "aws_security_group" "testsg" {
description = "Allow limited inbound external traffic"
vpc_id = aws_vpc.testvpc.id
name = "testsg"

ingress {
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
from_port = 22
to_port = 22
}

ingress {
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
from_port = 80
to_port = 80
}

ingress {
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
from_port = 443
to_port = 443
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]

}
tags = {
Name = "testsg"
}
}

H. Create Linux Server & Install/Enable Apache2 on Both Instances

# Create Linux Server & Install/Enable Apache2 (Instance 1)

resource "aws_instance" "Instance1" {
ami = "ami-0b8b44ec9a8f90422"
instance_type = "t2.micro"
availability_zone = "us-east-2a"
key_name = "Terraform"
network_interface {
device_index = 0
network_interface_id = aws_network_interface.testeni1.id
}

user_data = <<-EOF
#!/bin/bash
sudo apt update -y
sudo apt install apache2 -y
sudo systemctl start apache2
sudo systemctl enable apache2
EOF

tags = {
Name = "Instance1"
}
}

# Create Linux Server & Install/Enable Apache2 Here (Instance 2)

resource "aws_instance" "Instance2" {
ami = "ami-0b8b44ec9a8f90422"
instance_type = "t2.micro"
availability_zone = "us-east-2b"
key_name = "Terraform"
network_interface {
device_index = 0
network_interface_id = aws_network_interface.testeni2.id
}

user_data = <<-EOF
#!/bin/bash
sudo apt update -y
sudo apt install apache2 -y
sudo systemctl start apache2
sudo systemctl enable apache2
EOF

tags = {
Name = "Instance2"
}
}

4. Run the Created Terraform Script

Step 1: Create a “main.tf” file using the command: sudo nano main.tf

main.tf
main.tf

Step 2: Paste the Created Script here:

provider "aws" {
region = "us-east-2"
access_key = "AKIAQRH4ND34WNGRNWOP"
secret_key = "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"
}
# Create a VPC

resource "aws_vpc" "testvpc" {
cidr_block = "10.0.0.0/16"

tags = {
Name = "testvpc"
}
}
# Create a Public Subnet

resource "aws_subnet" "testsbnt1" {
vpc_id = aws_vpc.testvpc.id
cidr_block = "10.0.1.0/24"
map_public_ip_on_launch = "true"
availability_zone = "us-east-2a"

tags = {
Name = "testsbnt1"
}
}
# Create a Private Subnet

resource "aws_subnet" "testsbnt2" {
vpc_id = aws_vpc.testvpc.id
cidr_block = "10.0.2.0/24"
map_public_ip_on_launch = "false"
availability_zone = "us-east-2b"

tags = {
Name = "testsbnt2"
}
}
# Create an Internet Gateway

resource "aws_internet_gateway" "testigw" {
vpc_id = aws_vpc.testvpc.id
tags = {
Name = "testigw"
}
}
# Create a Route Table for Public Subnet

resource "aws_route_table" "testrtb1" {
vpc_id = aws_vpc.testvpc.id

route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.testigw.id
}

route {
ipv6_cidr_block = "::/0"
gateway_id = aws_internet_gateway.testigw.id
}
}
# Associate Public Route Table with Public Subnet

resource "aws_route_table_association" "testassoc1" {
subnet_id = aws_subnet.testsbnt1.id
route_table_id = aws_route_table.testrtb1.id
}
# Create a Private Route Table for Subnet 2

resource "aws_route_table" "testrtb2" {
vpc_id = aws_vpc.testvpc.id

route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_nat_gateway.nat.id
}

tags = {
Name = "testrtb2"
}
}
# Associate Route Table with Private Subnet

resource "aws_route_table_association" "testassoc2" {
subnet_id = aws_subnet.testsbnt2.id
route_table_id = aws_route_table.testrtb2.id
}
# Assign ENI with IP

resource "aws_network_interface" "testeni1" {
subnet_id = aws_subnet.testsbnt1.id
private_ips = ["10.0.1.10"]
security_groups = [aws_security_group.testsg.id]
}

resource "aws_network_interface" "testeni2" {
subnet_id = aws_subnet.testsbnt2.id
private_ips = ["10.0.2.10"]
security_groups = [aws_security_group.testsg.id]
}
# Assign Elastic IP to ENI

resource "aws_eip" "testeip1" {
domain = "vpc"
network_interface = aws_network_interface.testeni1.id
associate_with_private_ip = "10.0.1.10"
depends_on= [aws_internet_gateway.testigw, aws_instance.Instance1]
tags = {
Name = "testeip1"
}
}
# Create an Elastic IP Address for NAT Gateway

resource "aws_eip" "testeip2" {
domain = "vpc"
associate_with_private_ip = "10.0.2.10"
depends_on= [aws_internet_gateway.testigw]
tags = {
Name = "testeip2"
}
}
# Create a NAT Gateway for VPC

resource "aws_nat_gateway" "nat" {
allocation_id = aws_eip.testeip2.id
subnet_id = aws_subnet.testsbnt2.id

tags = {
Name = "nat"
}
}
# Create a Security Group

resource "aws_security_group" "testsg" {
description = "Allow limited inbound external traffic"
vpc_id = aws_vpc.testvpc.id
name = "testsg"

ingress {
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
from_port = 22
to_port = 22
}

ingress {
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
from_port = 80
to_port = 80
}

ingress {
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
from_port = 443
to_port = 443
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]

}
tags = {
Name = "testsg"
}
}
# Create Linux Server & Install/Enable Apache2 (Instance 1)

resource "aws_instance" "Instance1" {
ami = "ami-0b8b44ec9a8f90422"
instance_type = "t2.micro"
availability_zone = "us-east-2a"
key_name = "Terraform"
network_interface {
device_index = 0
network_interface_id = aws_network_interface.testeni1.id
}

user_data = <<-EOF
#!/bin/bash
sudo apt update -y
sudo apt install apache2 -y
sudo systemctl start apache2
sudo systemctl enable apache2
EOF

tags = {
Name = "Instance1"
}
}
# Create Linux Server & Install/Enable Apache2 Here (Instance 2)

resource "aws_instance" "Instance2" {
ami = "ami-0b8b44ec9a8f90422"
instance_type = "t2.micro"
availability_zone = "us-east-2b"
key_name = "Terraform"
network_interface {
device_index = 0
network_interface_id = aws_network_interface.testeni2.id
}

user_data = <<-EOF
#!/bin/bash
sudo apt update -y
sudo apt install apache2 -y
sudo systemctl start apache2
sudo systemctl enable apache2
EOF

tags = {
Name = "Instance2"
}
}
Paste Terraform Script Here
Paste Terraform Script Here

Save & exit from the file. Use CTRL+X to exit & press “Yes” to save. Press “enter” to completely exit from the file.

Step 3: Initialize the “Terraform” using the command: terraform init.

terraform init command
terraform init command

Step 4: Run the “terraform plan” command to execute the plan.

terraform plan command
terraform plan command
plan created
plan created

Step 5: Now, run the “terraform apply” command to create the infrastructure.

terraform apply
terraform apply

Step 6: Type “yes” to continue.

Type “yes”
Type “yes”

Step 7: All “Resources” will be successfully created.

All Resources Created
All Resources Created

Step 8: All “Instances” will be successfully created.

All Instances Created
All Instances Created
Instance 1
Instance 1
Instance 2
Instance 2

Step 9: Click on “Open Address” in “Public IP Address (18.216.147.115)” of “Instance1”.

Apache2 Installed
Apache2 Installed

“Apache2” will be successfully installed”.

In the second instance, the “Apache2” page will not be shown because of “Public IP Address” is not assigned.

Check Terraform Assignments Here:

Create an EC2 Instance Using Terraform — Assignment 1

Create an EC2 Instance With an Elastic IP Address — Assignment 2

Rename EC2 Instances After Creation — Assignment 3

Create a VPC & Deploy an EC2 Instance Inside It — Assignment 4

Install Apache 2 & Print the IP Address of the Instance in a File on Local: Assignment 5

Also, Check the Other DevOps Case Studies Here:

Containerized an HTML Website using Docker on Production Environment — Docker Case Study

Integration of DevOps Tools with Jenkins — Jenkins Case Study

Suggested a Git Workflow Architecture to Manage the Product Release — Git Case Study 1

Resolve Merge Conflict in The GitHub Repository — Git Case Study 2

Create Two Server Groups & Install Apache on The First Group & NGINX on the Second Group — Ansible Case Study

How to Deploy a Sample Website on Kubernetes Using Ingress — Kubernetes Case Study

--

--