Creating AWS Resources with Terraform: AWS Network Resources

Sagar Kharab
4 min readAug 14, 2020

In previous post, we installed Terraform cli. Let’ start with AWS Basics of Networking.

For the purpose of this post we are going to use AWS Free Tier Account. If you don’t have an account already, create using this link.

AWS Infrastructure’s fundamental components are Regions and Availability Zones (AZ). While region is a geographical area, AZ are the data centers within region located from other AZs and considered are as single point of failure.

With terraform to get start with AWS we need to set this as provider.

provider "aws" {
shared_credentials_file = "$HOME/.aws/credentials"
region = var.region
}

Note: you can need to set aws credentials using aws cli as here. We can also pass region as variable from configuration. To set lots of variables, it is more convenient to specify their values in a variable definitions file (with a filename ending in either .tfvars or .tfvars.json) and then specify that file on the command line with -var-file:

terraform plan -var-file="testing.tfvars"

One of the main component of AWS Cloud is a VPC (Virtual Private cloud). It’s your private network in the cloud where you can control the access to network, resources, connectivity etc. Whenever a new account is created, a default VPC is created in each region. This VPC is open for public access and hence the resources created inside the VPC can be accessed via Internet. There are below components which are important for a VPC

  1. Subnet
  2. Route table
  3. Internet Gateway

In order to create a VPC with terraform, we need to pass a CIDR block as a required param. Create a file named main.tf with below entry. Tags are created for various purpose and it’s a good practice to tag your resource.

# VPC
resource "aws_vpc" "dev_vpc" {
cidr_block = var.vpc_cidr_block
tags = {
Name = "MyVpc"
}
}
variable "vpc_cidr_block" {
type = string
default = "10.0.0.0/16"
}

we can get VPC id out of this as output:

output "vpc_id" {
value = aws_vpc.dev_vpc.id
}

Once we have created VPC we need to create subnets. AWS regions generally have 3 or more AZ per region and we can create one or more subnet per region but one subnet can not span multiple AZ. In order to create subnets in each AZ we need to retrieve the list of AZ in the region and create subnet for each. We can use data to retrieve info from Cloud resource. Add below data entry in main.tf

#####################################################
# Data (used to pull data from aws resources)
#####################################################
data "aws_availability_zones" "availability_zones" {
state = "available"
}

Once we have received the list of AZs in the region, we can use it in the resources. Add below in main.tf. Note (to assign a public ip to instances in this subnet, we set map_public_ip_on_launch to true)

resource "aws_subnet" "public_subnet" {
count = length(data.aws_availability_zones.availability_zones.names)
vpc_id = aws_vpc.dev_vpc.id
cidr_block = "10.0.${count.index+1}.0/24"
map_public_ip_on_launch = true
availability_zone = data.aws_availability_zones.availability_zones.names[count.index]
tags = {
Name = "AZ_${count.index}_Public_Subnet"
}
}

We can take the subnets’ id as output:

output "public_subnet_ids" {
value = [aws_subnet.public_subnet]
}

To Open this VPC to internet we need to attach an internet gateway to this VPC as below:

# Internet Gateway 
resource "aws_internet_gateway" "ig_gw" {
vpc_id = aws_vpc.dev_vpc.id
tags = {
Name = "TAF_IGW"
}
}

When VPC is created a default Route table is create which has association with VPC as Main Table.

VPC Main Route Table

We should not open this to Internet and should create a separate route table. In order to create a route table and associate subnet with that, we need to add below in main.tf

# Route Table
resource "aws_route_table" "public_route_table" {
vpc_id = aws_vpc.taf_vpc.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.ig_gw.id
}
route{
ipv6_cidr_block = "::/0"
gateway_id = aws_internet_gateway.ig_gw.id
}
tags = {
Name = "Public_RouteTable"
}
}
resource "aws_route_table_association" "az_1" {
subnet_id = aws_subnet.public_subnet[0].id
route_table_id = aws_route_table.public_route_table.id
}
resource "aws_route_table_association" "az_2" {
subnet_id = aws_subnet.public_subnet[1].id
route_table_id = aws_route_table.public_route_table.id
}
resource "aws_route_table_association" "az_3" {
subnet_id = aws_subnet.public_subnet[2].id
route_table_id = aws_route_table.public_route_table.id
}

With this our VPC completes and we can provision our resources inside our VPC and connect with internet (if required).

With terraform remote state we can easily save the state of terraform infrastructure to a state file and save it one of the supported backend with terraform e.g. AWS S3, Http, PostGreSQL DB or local. Put a file backend.tf with below entry:

terraform {
backend "s3" {
bucket = "tf-states"
key = "compute_terraform.tfstate"
region = "eu-west-1"
}
}

We can use remote states as data and use the outputs as key info in further layer of resources

data "terraform_remote_state" "vpc" {
backend = "s3"
config = {
bucket = "tf-states"
key = "network_terraform.tfstate"
region = "eu-west-1"
}
}
vpc_id = data.terraform_remote_state.vpc.outputs.vpc_id

Terraform’s two stepped approach make it easier to get an overview of what actions will be performed before execution. We do a terraform plan and apply as below:

terraform plan -var-file=env.tfvarsterraform apply -var-file=env.tfvars

This way we can create our VPC in no time and manage it.

--

--

Sagar Kharab

Software Developer by profession. Chef by chance. Runner by choice. Sums it all.