VPC Infrastructure using TerraForm along with NAT Gateway

Piyush Mehta
6 min readOct 8, 2020

Statement: Perform Task-3 with additional feature of NAT Gateway ,which provides internet access to instance running in the private subnet.

Note: Since This Task is just the upgradation of Task 3, Most of the documentation here is shamelessly copy-pasted from my previous task :p

Amazon Virtual Private Cloud (Amazon VPC) lets you provision a logically isolated section of the AWS Cloud where you can launch AWS resources in a virtual network that you define. You have complete control over your virtual networking environment, including selection of your own IP address range, creation of subnets, and configuration of route tables and network gateways. You can use both IPv4 and IPv6 in your VPC for secure and easy access to resources and applications. You can create a public-facing subnet for your web servers that have access to the internet. You can also place your backend systems, such as databases or application servers, in a private-facing subnet with no internet access.

Now Let’s Start Writing our TerraForm Code.

First we need to provide our AWS Profile and Region

provider “aws” {region = “ap-south-1”profile = “Kaizoku”}

(Optional) Creation of a new KeyPair

resource "tls_private_key" "KeyGen" {algorithm = "RSA"rsa_bits = 4096} // Key Generation Using RSA Algorithmresource "local_file" "KeyFile" {content = tls_private_key.KeyGen.private_key_pemfilename = "TerraKey.pem"file_permission = 0400} // Copying the Key Content to a local fileresource "aws_key_pair" "KeyAWS" {key_name = "TerraKey"public_key = tls_private_key.KeyGen.public_key_openssh}

Creation of VPC

resource "aws_vpc" "TerraVPC" {tags = {Name = "myVPC"}cidr_block       = "192.168.0.0/16"instance_tenancy = "default"enable_dns_hostnames  = true}

Note: cidr_block specifies the IPv4 range.

Now inside this VPC we need to create 2 Subnets:

Private Subnet:

A private subnet sets that route to a NAT instance. Private subnet instances only need a private ip and internet traffic is routed through the NAT in the public subnet.

resource "aws_subnet" "privateSN" {tags = {Name = "subnet_private"}vpc_id     = aws_vpc.TerraVPC.idcidr_block = "192.168.1.0/24"availability_zone = "ap-south-1b"}

Public Subnet:

A public subnet is a subnet that’s associated with a route table that has a route to an Internet gateway.

resource “aws_subnet” “publicSN” {
tags = {
Name = “subnet_public”
}
vpc_id = aws_vpc.TerraVPC.id
cidr_block = “192.168.0.0/24”
availability_zone = “ap-south-1a”
map_public_ip_on_launch = true
}

We’ll now create a Public facing internet gateway to connect our VPC to the internet world and attach this gateway to our VPC.

resource "aws_internet_gateway" "gateway" {tags = {Name = "iGateWay"}vpc_id = aws_vpc.TerraVPC.id}

Creation of Routing Table for Internet Gateway

resource "aws_route_table" "ig_rt" {vpc_id = aws_vpc.TerraVPC.idroute {cidr_block = "0.0.0.0/0"gateway_id = aws_internet_gateway.gateway.id}tags = {Name = "igRouteTable"}}

Associate this to our Public Subnet

resource "aws_route_table_association" "publicAssociation" {subnet_id      = aws_subnet.publicSN.idroute_table_id = aws_route_table.ig_rt.id}

* Elastic IP:

Elastic IP is required for connecting to the internet.

resource "aws_eip" "Eip"{depends_on = [ "aws_internet_gateway.gateway"]vpc        = true}

* NAT Gateway:

You can use a NAT device to enable instances in a private subnet to connect to the internet (for example, for software updates) or other AWS services, but prevent the internet from initiating connections with the instances. A NAT device forwards traffic from the instances in the private subnet to the internet or other AWS services, and then sends the response back to the instances. When traffic goes to the internet, the source IPv4 address is replaced with the NAT device’s address and similarly, when the response traffic goes to those instances, the NAT device translates the address back to those instances’ private IPv4 addresses.

resource "aws_nat_gateway" "NATgatway" {tags = {Name = "gatewayNAT"}depends_on = [ "aws_internet_gateway.gateway"]allocation_id = aws_eip.Eip.idsubnet_id = aws_subnet.publicSN.id}

* NAT Route Table Creation and Association

resource "aws_route_table" "NAT_rt" {tags = {Name = "NAT_Route"}vpc_id = aws_vpc.TerraVPC.idroute {cidr_block = "0.0.0.0/0"gateway_id = aws_nat_gateway.NATgatway.id}}
resource "aws_route_table_association" "NAT_asso" {
subnet_id = aws_subnet.privateSN.idroute_table_id = aws_route_table.NAT_rt.id}

Creation of Security Groups

Before launching our Instances, we’ll require Security Groups, were suitable inbound and outbound traffic details will be defined.

Security Group for our MySql Instance:

resource "aws_security_group" "database" {name        = "mysql"description = "Allow SSH and MYSQL"vpc_id      = aws_vpc.TerraVPC.idingress {description = "MYSQL"protocol    = "tcp"from_port   = 3306to_port     = 3306security_groups = [aws_security_group.webserver.id]}egress {from_port   = 0to_port     = 0protocol    = "-1"cidr_blocks = ["0.0.0.0/0"]}tags = {Name = "DatabaseSG"}}

Security Group for our Webserver Instance:

resource "aws_security_group" "webserver" {name        = "for_wordpress"description = "Allow HTTPS n SSH"vpc_id      = aws_vpc.TerraVPC.idingress {description = "HTTP"from_port   = 80to_port     = 80protocol    = "tcp"cidr_blocks = ["0.0.0.0/0"]}ingress {description = "SSH"from_port   = 22to_port     = 22protocol    = "tcp"cidr_blocks = ["0.0.0.0/0"]}egress {from_port   = 0to_port     = 0protocol    = "-1"cidr_blocks = ["0.0.0.0/0"]}tags = {Name = "mywebserver_sg"}}

All Cool, now at last we need to launch 2 instances:

Database Instance:

resource "aws_instance" "mysql" {ami           = "ami-08706cb5f68222d09"instance_type = "t2.micro"subnet_id = aws_subnet.privateSN.idvpc_security_group_ids = [aws_security_group.database.id]key_name = "TerraKey"tags = {Name = "MySql_os"}}

Webserver Instance:

resource "aws_instance" "wordpress" {ami           = "ami-000cbce3e1b899ebd"instance_type = "t2.micro"associate_public_ip_address = truesubnet_id = aws_subnet.publicSN.idvpc_security_group_ids = [aws_security_group.webserver.id]key_name = "TerraKey"tags = {
Name = "wordpress_os"
}
}

Now that our Code is ready, we need to execute is using terraform command.

terraform init
terraform validate
terraform apply --auto-approve

Final Output:

Just like how easy it was to create the above Infrastructure, its removal is also easy.

terraform destroy --auto-approve

--

--