Creating an Architecture using Terraform on AWS —Terraform Case Study
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
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.
Step 2: Click on “Launch Instance”.
Step 3: Choose “Name” as “Master” in the “Name and tags” section.
Step 4: Choose “AMI” as “ubuntu”.
Step 5: Choose “Instance type” as “t2.micro”.
Step 6: Choose “key pair (login)” as “Terraform”.
Step 7: Choose “Select existing security group” as “launch-wizard-1”.
Step 8: Click on “Launch Instance”.
Step 9: Instance will be launched. Click on “hyperlink”.
Step 10: The instance will be in the “Running” State.
Step 11: Select the instance & click on “Connect”.
Step 12: Click on “Connect” again.
Step 13: The instance will be successfully connected.
2. Install “Terraform” on “Master”
Step 1: Install Terraform, create a “terraform-install.sh” file to install Terraform.
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
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.
Step 4: Terraform will be successfully installed.
Step 5: Run this command: terraform –version to check the “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
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"
}
}
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.
Step 4: Run the “terraform plan” command to execute the plan.
Step 5: Now, run the “terraform apply” command to create the infrastructure.
Step 6: Type “yes” to continue.
Step 7: All “Resources” will be successfully created.
Step 8: All “Instances” will be successfully created.
Step 9: Click on “Open Address” in “Public IP Address (18.216.147.115)” of “Instance1”.
“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
How to Deploy a Sample Website on Kubernetes Using Ingress — Kubernetes Case Study