How to create a VPC using Terraform?

Simranjeet Singh
4 min readAug 1, 2021

Running your applications comes up with other challenges too and one of those challenges is having a robust network set up to host all parts in one place. We have to set up VPC (Virtual Private Cloud), internet gateway, subnet, etc. to make sure our application is working properly. The other aspect of this is to manage the infrastructure once it is ready and deployed. This is where Terraform comes in handy. Terraform is an Infrastructure-as-a-code that helps you to define infrastructure in code and you can easily maintain it for future updates.

If you are not aware of the networking fundamentals on AWS, read the article AWS Networking Fundamentals before going deep with Terraform in this article.

You need to have some information about how Terraform works. If you don’t know about Terraform, I suggest going through its documentation to have a basic idea about it before diving into the article.

I will post the snippets and add some description in steps here. You can also find the complete module at a GitHub repo aws-vpc-terraform.

Directory Structure

The above directory structure of the module has the following key files:

  • main: Contains the entire module and all the resources we will discuss in some time.
  • output: Defines the output provided by the module. This provider returns the vpcId of the VPC created by the module.
  • provider: Defines the provider required for the module to work properly. You can also think of it as dependencies required for the module. This module needs the AWS module from Hashicorp (creators of Terraform). The AWS module will allow us to use the resources available in the AWS to create our desired infrastructure.
  • variables: It contains the input variables required by the module to complete its task. For the sale of this article, I have set default values to the variables but they can be easily made required by removing the default value.

As mentioned above the most important file is main.tf which contains all the code for the resources we are about to create. Let’s go through each resource statement in file and understand them a bit.

data "aws_availability_zones" "availableAZ" {}# VPC 
resource "aws_vpc" "vpc" {
cidr_block = var.cidr
instance_tenancy = "default"
enable_dns_support = true
enable_dns_hostnames = true
assign_generated_ipv6_cidr_block = true
tags = {
Name = var.namespace
Namespace = var.namespace
}
}
# Public Subnet
resource "aws_subnet" "publicsubnet" {
count = 3
cidr_block = tolist(var.publicSubnetCIDR)[count.index]
vpc_id = aws_vpc.vpc.id
map_public_ip_on_launch = true
availability_zone = data.aws_availability_zones.availableAZ.names[count.index]
tags = {
Name = "${var.namespace}-publicsubnet-${count.index + 1}"
AZ = data.aws_availability_zones.availableAZ.names[count.index]
Namespace = var.namespace
}
depends_on = [aws_vpc.vpc]
}
# Private Subnet
resource "aws_subnet" "privatesubnet" {
count = 3
cidr_block = tolist(var.privateSubnetCIDR)[count.index]
vpc_id = aws_vpc.vpc.id
availability_zone = data.aws_availability_zones.availableAZ.names[count.index]
tags = {
Name = "${var.namespace}-privatesubnet-${count.index + 1}"
AZ = data.aws_availability_zones.availableAZ.names[count.index]
Namespace = var.namespace
}
depends_on = [aws_vpc.vpc]
}
# Internet Gateway
resource "aws_internet_gateway" "internetgateway" {
vpc_id = aws_vpc.vpc.id
tags = {
Name = "${var.namespace}-InternetGateway"
Namespace = var.namespace
}
depends_on = [aws_vpc.vpc]
}
# Elastic IP
resource "aws_eip" "elasticIPs" {
count = 3
vpc = true
tags = {
Name = "elasticIP-${count.index + 1}"
Namespace = var.namespace
}
depends_on = [aws_internet_gateway.internetgateway]
}
# NAT Gateway
resource "aws_nat_gateway" "natgateway" {
count = 3
allocation_id = aws_eip.elasticIPs[count.index].id
subnet_id = aws_subnet.publicsubnet[count.index].id
tags = {
Name = "${var.namespace}-NATGateway-${count.index + 1}"
AZ = data.aws_availability_zones.availableAZ.names[count.index]
Namespace = var.namespace
}
depends_on = [aws_internet_gateway.internetgateway]
}
  • We have all the major parts of the network and now it is time to create route tables. Route Tables define which traffic can flow to which resource. We will create a Route Table for public and private subnets.
  • Public Route Table will have the traffic flowing from Internet Gateway directly. We will also create an association record to associate the newly created route table with the public subnets.
# Route Table for Public Routes 
resource "aws_route_table" "publicroutetable" {
vpc_id = aws_vpc.vpc.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.internetgateway.id
}
tags = {
Name = "${var.namespace}-publicroutetable"
Namespace = var.namespace
}
depends_on = [aws_internet_gateway.internetgateway]
}
# Route Table Association - Public Routes
resource "aws_route_table_association" "routeTableAssociationPublicRoute" {
count = 3
route_table_id = aws_route_table.publicroutetable.id
subnet_id = aws_subnet.publicsubnet[count.index].id
depends_on = [aws_subnet.publicsubnet, aws_route_table.publicroutetable]
}
# Route Table for Private Routes
resource "aws_route_table" "privateroutetable" {
count = 3
vpc_id = aws_vpc.vpc.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_nat_gateway.natgateway[count.index].id
}
tags = {
Name = "${var.namespace}-privateroutetable-${count.index + 1}"
AZ = data.aws_availability_zones.availableAZ.names[count.index]
Namespace = var.namespace
}
depends_on = [aws_nat_gateway.natgateway]
}
# Route Table Association - Private Routes
resource "aws_route_table_association" "routeTableAssociationPrivateRoute" {
count = 3
route_table_id = aws_route_table.privateroutetable[count.index].id
subnet_id = aws_subnet.privatesubnet[count.index].id
depends_on = [aws_subnet.privatesubnet, aws_route_table.privateroutetable]
}

Our entire module is ready. In order to run it, you have to first initialize the Terraform, see the plan and apply it to create your VPC using Terraform.

terraform init 
terraform plan
terraform apply

That’s all related to deploying and managing your VPC using Terraform. In upcoming articles, I will write more about creating other services and deploying some common things using Terraform. Till then Happy Coding.

Originally published at https://awsmag.com on August 1, 2021.

--

--