In this article, I will demonstrate how to create VPC, Subnets, EC2 instances, Internet gateway, NAT gateway, and Security groups using Terraform in two availability zones.
Architecture
Prerequisite
AWS account and AWS Access key and Secret key created
Terraform installed on your IDE
AWS CLI installed and configured on your IDE
Basic understanding of AWS services and Terraform
Objective
Choose a region in which you want your VPC to reside and availability zones where you want to create public and private subnets for high availability.
Decide the CIDR blocks range for your VPC and Subnets.
Create public and private subnets in each availability zone.
Create an internet gateway to allow communication between your VPC and the internet.
Create an EC2 instance in each public subnet in both the availability zones and create AWS key pair to SSH into your instances.
Create a route table for the public and private subnets and associate the route table with subnets to control where network traffic is directed.
Create a NAT gateway to enable private subnets to connect to services outside your VPC. A NAT gateway must be in a public subnet.
Finally, create a VPC security group and open port 80 to allow HTTP traffic from anywhere and open port 22 to SSH into the instances.
Code Repository
Use GitHub to find providers.tf, variables.tf, and outputs.tf files.
Let's get started with the configuration of the project
Create VPC
We are creating VPC in the us-east-1 region and attaching it to the internet gateway.
resource "aws_vpc" "vpc" {
cidr_block = "10.0.0.0/16"
tags = {
Name = "my-vpc"
}
}
resource "aws_internet_gateway" "internet_gateway" {
vpc_id = aws_vpc.vpc.id
tags = {
Name = "inernetGW"
}
}
Create public and private subnets
Creating one public and one private subnet in both us-east-1a and us-east-1b zones.
resource "aws_subnet" "vpc_public_subnet" {
vpc_id = aws_vpc.vpc.id
count = length(var.subnets_count)
availability_zone = element(var.availability_zone, count.index)
cidr_block = "10.0.${count.index}.0/24"
map_public_ip_on_launch = true
tags = {
Name = "pub-sub-${element(var.availability_zone, count.index)}"
}
}
resource "aws_subnet" "vpc_private_subnet" {
count = length(var.subnets_count)
availability_zone = element(var.availability_zone, count.index)
cidr_block = "10.0.${count.index + 2}.0/24"
vpc_id = aws_vpc.vpc.id
tags = {
Name = "pri-sub-${element(var.availability_zone, count.index)}"
}
}
Create a route table and associate it with the public subnet
A route table contains a set of rules that are used to determine where network traffic is directed. Associate a public subnet with the default route (0.0.0.0/0) pointing to an internet gateway.
resource "aws_route_table" "public_route_table" {
vpc_id = aws_vpc.vpc.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.internet_gateway.id
}
tags = {
Name = "public-route-tbl"
}
}
resource "aws_route_table_association" "public_route_table_association" {
count = length(var.subnets_count)
subnet_id = element(aws_subnet.vpc_public_subnet.*.id, count.index)
route_table_id = aws_route_table.public_route_table.id
}
Create a NAT gateway and associate it with Elastic IP
Create a public NAT gateway in a public subnet and associate it with an elastic IP address to route traffic from the NAT gateway to the Internet gateway for the VPC.
resource "aws_eip" "elasticIP" {
count = length(var.subnets_count)
vpc = true
}
resource "aws_nat_gateway" "nat_gateway" {
count = length(var.subnets_count)
allocation_id = element(aws_eip.elasticIP.*.id, count.index)
subnet_id = element(aws_subnet.vpc_public_subnet.*.id, count.index)
tags = {
Name = "nat-GTW-${count.index}"
}
}
Create a route table and associate it with the private subnet
resource "aws_route_table" "private_route_table" {
count = length(var.subnets_count)
vpc_id = aws_vpc.vpc.id
route {
cidr_block = "0.0.0.0/0"
nat_gateway_id = aws_nat_gateway.nat_gateway[count.index].id
}
tags = {
Name = "private-route-tbl"
}
}
resource "aws_route_table_association" "private_route_table_association" {
count = length(var.subnets_count)
subnet_id = element(aws_subnet.vpc_private_subnet.*.id, count.index)
route_table_id = element(aws_route_table.private_route_table.*.id,
count.index)
}
Create security group
For the inbound connections open port 80 to allow HTTP traffic from anywhere and open port 22 to SSH into the instance and open all the ports for the outbound connections.
resource "aws_security_group" "vpc_sg" {
name = "vpc_sg"
description = "Security group for vpc"
vpc_id = aws_vpc.vpc.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"]
}
tags = {
Name = "vpc-sg"
}
}
Create EC2 instances in public subnets
Create EC2 instance with user-data scripts to install Apache server and access static webpage. Also, create AWS key pair to SSH into instances
resource "tls_private_key" "key" {
algorithm = "RSA"
rsa_bits = 4096
}
resource "local_file" "private_rsa_key" {
content = tls_private_key.key.private_key_pem
filename = "private_rsa_key"
}
resource "aws_key_pair" "public_rsa_key" {
key_name = "public_rsa_key"
public_key = tls_private_key.key.public_key_openssh
}
resource "aws_instance" "my_app_server" {
ami = var.instance_ami
instance_type = var.instance_size
key_name = aws_key_pair.public_rsa_key.key_name
count = length(var.subnets_count)
subnet_id = element(aws_subnet.vpc_public_subnet.*.id, count.index)
security_groups = [aws_security_group.vpc_sg.id]
associate_public_ip_address = true
user_data = <<-EOF
#!/bin/bash
sudo apt update -y
sudo apt install apache2 -y
sudo systemctl start apache2
sudo systemctl enable apache2
sudo apt install git -y
git clone https://github.com/palakbhawsar98/FirstWebsite.git
cd /FirstWebsite
sudo cp index.html /var/www/html/
EOF
tags = {
Name = "my_app_server-${count.index}"
}
}
We are ready to deploy all our changes to AWS. Perform the below commands:
terraform init to initialize the working directory and download all the plugins for providers.
terraform fmt to rewrite Terraform configuration files to a canonical format and style.
terraform validate to check that our code is error-free.
terraform plan to create the execution plan for the resources we are going to create in AWS.
terraform apply to execute the actions proposed in a terraform plan and to deploy your infrastructure.
You can see the resources created in AWS Console. Take the public IPV4 and search it in the browser on port 80 that we opened for HTTP connections.
You can access the HTML static webpage using public IPV4
If you want you can destroy the infrastructure we just create using terraform destroy command.
Top comments (0)