Create VPC infrastructure with NAT Gateway using terraform.

deepak kapse
6 min readAug 21, 2020

What is NAT Gateway?

NAT stands for Network Address Translation. It is a managed service of AWS that makes it easy to connect to the Internet from instances within a private subnet in an Virtual Private Cloud (VPC).

Here going to perform task-3 with an additional feature to be added that is NAT Gateway to provide the internet access to instances running in the private subnet.

Task discription :-

1. Write an Infrastructure as code using terraform, which automatically create a VPC.

Before creating VPC, first we have to mention provider of AWS for understanding API interactions.

provider "aws" {
region = "ap-south-1"
profile = "ankit"
}

We have to initialize it so that it can download AWS provider plugin.

Now we create VPC. For this we require CIDR block to specify range of IPv4 addresses for the VPC and a name tag for unique identification.

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

On applying this we get:

In that VPC we have to create 2 subnets:

1. public subnet [ Accessible for Public World! ]

2. private subnet [ Restricted for Public World! ]

Creating Private Subnet:

resource "aws_subnet" "privateSn" {
vpc_id = "${aws_vpc.main.id}"
cidr_block = "192.168.0.0/24"
availability_zone = "ap-south-1a"
tags = {
Name = "fvcsubnet-1"
}
}

Creating Public Subnet:

resource "aws_subnet" "publicSn" {
vpc_id = "${aws_vpc.main.id}"
cidr_block = "192.168.1.0/24"
availability_zone = "ap-south-1b"
map_public_ip_on_launch = true
tags = {
Name = "fvpcsubnet-2"
}
}

Create a public facing internet gateway for connect our VPC/Network to the internet world and attach this gateway to our VPC.

resource "aws_internet_gateway" "gw" {
vpc_id = "${aws_vpc.main.id}"
tags = {
Name = "vpca"
}
}

Here we have to give our VPC ID and name whatever er want to give to internet gateway.

Create a routing table for Internet gateway so that instance can connect to outside world, update and associate it with public subnet.

resource "aws_route_table" "vpcRouteTable" {
vpc_id = "${aws_vpc.main.id}"
route {
cidr_block = "0.0.0.0/0"
gateway_id = "${aws_internet_gateway.gw.id}"
}
tags = {
Name = "vpcroute"
}
}

Associating Public subnet to this route table:

resource "aws_route_table_association" "associate" {
subnet_id = "${aws_subnet.publicSn.id}"
route_table_id = "${aws_route_table.vpcRouteTable.id}"
}

We create routing table because when we connect to some system , packet reached from one system to another . But if target system won’t accept that packets then connectivity will never establish. To resolve this we have to create routing table to add internet gateway details.

Create a NAT gateway for connect our VPC/Network to the internet world and attach this gateway to our VPC in the public network.

Before creating NAT gateway we require Elastic IP because It wouldn’t make any sense to have a dynamic IP on a NAT device as if the address changed, then there may be chances of breaking any sessions in progress and the only way to allocate a static address is by allocating an Elastic IP address (EIP).

resource "aws_eip" "ip" {
vpc = true
}

Now creating NAT gateway:

resource "aws_nat_gateway" "natgw" {
allocation_id = "${aws_eip.ip.id}"
subnet_id = "${aws_subnet.publicSn.id}"
tags = {
Name = "NAT"
}
}

Update the routing table of the private subnet, so that to access the internet it uses the nat gateway created in the public subnet.

urce "aws_route_table" "vpcRouteTable2" {
vpc_id = "${aws_vpc.main.id}"
route {
cidr_block = "0.0.0.0/0"
nat_gateway_id = "${aws_nat_gateway.natgw.id}"
}
tags = {
Name = "vpcroute2"
}
}

Associating Private subnet to this route table:

resource "aws_route_table_association" "associate2" {
subnet_id = aws_subnet.privateSn.id
route_table_id = aws_route_table.vpcRouteTable2.id
}

Launch an ec2 instance which has Wordpress setup already having the security group allowing port 80 so that our client can connect to our wordpress site. Also attach the key to instance for further login into it.

Before creating WordPress instance we have to create security group to allow only relevant traffic.

Creating Security Group: This security group only allow ping,ssh and httpd.

resource "aws_security_group" "wpsg" {
name = "wp"
description = "Allow TLS inbound traffic"
vpc_id = "${aws_vpc.main.id}"
ingress {
description = "ICMP"
from_port = 8
to_port = 0
protocol = "icmp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
description = "http"
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
description = "ssh"
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"]
}
tags = {
Name = "wpsg"
}
}

Now we can create our instance. For creating any instance we need AMI,instance type,availability zone which we have mentioned earlier in subnet and key — here I used pre-existing key. For WordPress AMI, I used WordPress Base Version which requires subscription for that.

resource "aws_instance" "wpinstance" {
ami = "ami-7e257211"
instance_type = "t2.micro"
key_name = "clusterKey"
subnet_id = aws_subnet.publicSn.id
vpc_security_group_ids = [ aws_security_group.wpsg.id ]
tags = {
Name = "wpos"
}
}

Launch an ec2 instance which has MYSQL setup already with security group allowing port 3306 in private subnet so that our WordPress instance can connect with the same.Also attach the key with the same.

Creating MySQL Security group:

In this security group, we allow only MYSQL port as our database is crucial.

resource "aws_security_group" "mysqlsg" {
name = "basic"
description = "Allow TLS inbound traffic"
vpc_id = "${aws_vpc.main.id}"
ingress {
description = "mysql"
from_port = 3306
to_port = 3306
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}

Creating Instance:

resource "aws_instance" "mysqlinstance" {
ami = "ami-08706cb5f68222d09"
instance_type = "t2.micro"
key_name = "clusterKey"
subnet_id = aws_subnet.privateSn.id
vpc_security_group_ids = [ aws_security_group.mysqlsg.id ]
tags = {
Name = "mysqlos"
}
}

We get:

As In this Instance, we don’t have Public DNS and Public IP which proves that is an instance belongs to private subnet.

Applying complete code gives:

By using Public IP or Public DNS we can access our WordPress site.

--

--