How to setup VPC via Terraform

coding script
Reading Time: 3 minutes

In this blog, we will create a Terraform script for setting up the VPC in aws. VPC enables us to launch the aws resources into a virtual network that we define. It is logically isolated from other virtual networks in the AWS Cloud. You can specify an IP address range for the VPC, add subnets, associate security groups, and configure route tables. Terraform scripts enables us to spin up the infrastructure at once and also check the current state of the system.


				VPC with the main route table

Creating the VPC script in Terraform

On Amazon AWS, we have a default VPC created to launch instances on. The best practice is to launch an instance in a VPC, either on a default VPC or in a custom made VPC. We will start by creating our own VPC, to deploy instances on. This VPC uses the 10.0.0.0/16 addressing space. Every available zone in a VPC has its own private and public subnet.

Terraform script to create a vpc:
vpc.tf

resource “aws_vpc” “terra-vpc” {
cidr_block           = “10.0.0.0/16”   
 instance_tenancy     = “default”
  enable_dns_support   = “true”
enable_dns_hostnames = “true”
  enable_classiclink   = “false”
tags = {
Name = “terra-vpc”
}
}

I have defined a cidr block address of 10.0.0.0/16. Instance tenancy means that every instance that we launch will have a default tenancy. You can change this according to your requirements. DNS support and DNS hostname would provide the internal domain name and host name. If you want to link your VPC to ec2 classic, then you can enable the classic link as true. I have kept it false.

Defining subnets

Now, we will create the subnets. I have created three public and 3 private subnets. 

resource “aws_subnet” “terra-public-1” {
vpc_id                  = aws_vpc.terra-vpc.id
cidr_block              = “10.0.1.0/24”
map_public_ip_on_launch = “true”
 availability_zone       = “us-east-1a”
  tags = {
Name = “terra-public-1”
  }
}
resource “aws_subnet” “terra-public-2” {
 vpc_id                  = aws_vpc.terra-vpc.id
cidr_block              = “10.0.2.0/24”
map_public_ip_on_launch = “true”
availability_zone       = “us-east-1b”
  tags = {
 Name = “terra-public-2”
  }
resource “aws_subnet” “terra-public-3” {
vpc_id                  = aws_vpc.terra-vpc.id
cidr_block              = “10.0.3.0/24”
map_public_ip_on_launch = “true”
  availability_zone       = “us-east-1c”
  tags = {
 Name = “terra-public-3”
}
}
resource “aws_subnet” “terra-private-1” {
vpc_id                  = aws_vpc.terra-vpc.id
 cidr_block              = “10.0.4.0/24”
 map_public_ip_on_launch = “false”
 availability_zone       = “us-east-1a”
tags = {
 Name = “terra-private-1”
}
}
resource “aws_subnet” “terra-private-2” {
  vpc_id                  = aws_vpc.terra-vpc.id
cidr_block              = “10.0.5.0/24”
map_public_ip_on_launch = “false”
availability_zone       = “us-east-1b”
tags = {
    Name = “terra-private-2”
  }
}
resource “aws_subnet” “terra-private-3” {
  vpc_id                  = aws_vpc.terra-vpc.id
  cidr_block              = “10.0.6.0/24”
  map_public_ip_on_launch = “false”
  availability_zone       = “us-east-1c”
  tags = {
 Name = “terra-private-3”
}
}

We refer to the vpc we have created earlier. In public subnets,  map_public_ip_on_launch is set to true, because we would want our instances to have a public IP on launch. Whereas, in private subnets, we don’t want the instances to have a public IP so we have set  map_public_ip_on_launch to false.

Internet gateway

resource “aws_internet_gateway” “tig-gw” {
  vpc_id = aws_vpc.terra-vpc.id
tags = {
   Name = “terra-ig”
  }
  }

The public subnets are only public when they connect to the internet gateway. So I have created an internet gateway in the same VPC. 

Defining a route of traffic to internet gateway

resource “aws_route_table” “terra-public” {
  vpc_id = aws_vpc.terra-vpc.id
  route {
    cidr_block = “0.0.0.0/0”
    gateway_id = aws_internet_gateway.tig-gw.id
  }
  tags = {
    Name = “rt-public-1”
  }
}

Now, we will have to associate this route to the subnets.

resource “aws_route_table_association” “terra-public-1-a” {
 subnet_id      = aws_subnet.terra-public-1.id
 route_table_id = aws_route_table.terra-public.id
}
resource “aws_route_table_association” “terra-public-2-a” {
 subnet_id      = aws_subnet.terra-public-2.id
route_table_id = aws_route_table.terra-public.id
}
resource “aws_route_table_association” “terra-public-3-a” {
subnet_id      = aws_subnet.terra-public-3.id
  route_table_id = aws_route_table.terra-public.id
}

Creating a NAT gateway for the instances to access the internet

To do this, we need a static IP address or elastic IP. 

resource “aws_eip” “nat” {
  vpc = true
}

 With this ip address, we will create a NAT gateway.

resource “aws_nat_gateway” “nat-gw” {
 allocation_id = aws_eip.nat.id
subnet_id     = aws_subnet.terra-public-1.id
 depends_on    = [aws_internet_gateway.tig-gw]
}

Now we will create routes for the NAT

resource “aws_route_table” “terra-private” {
  vpc_id = aws_vpc.terra-vpc.id
 route {
  cidr_block     = “0.0.0.0/0”
nat_gateway_id = aws_nat_gateway.nat-gw.id
  }
  tags = {
Name = “terra-private-1”
  }
  }

 Associate these routes with private subnets:

resource “aws_route_table_association” “terra-private-1-a” {
  subnet_id      = aws_subnet.terra-private-1.id
  route_table_id = aws_route_table.terra-private.id
}
resource “aws_route_table_association” “terra-private-2-a” {
  subnet_id      = aws_subnet.terra-private-2.id
  route_table_id = aws_route_table.terra-private.id
}
resource “aws_route_table_association” “terra-private-3-a” {
  subnet_id      = aws_subnet.terra-private-3.id
  route_table_id = aws_route_table.terra-private.id
}

So now we have created the required configurations for VPC. You can also check the code here. In the next blog, we will create an instance in the same vpc.

References:

https://docs.aws.amazon.com/vpc/index.html

Written by 

Vidushi Bansal is a Software Consultant [Devops] at Knoldus Inc. She is passionate about learning and exploring new technologies.