Creating AWS Resources with Terraform: AWS Private Resources in VPC

Sagar Kharab
3 min readAug 18, 2020

In previous post we created a Custom VPC with a custom route table and public subnets. In general pubic subnets are used to provision Internet facing Instances e.g. web servers. In one AZ we can have public as well as private subnets which are not open to internet connection and can be used for internal processing instance e.g. database or process layer APIs. Below is what we have created in last tutorial.

VPC with Public Subnet

Now we need to create another Subnet for private instances which will only receive traffic from within VPC. Here we create one subnet per AZ as public subnet but we don’t map public ip on launch in this subnet.

# Private subnets
resource "aws_subnet" "private_subnet" {
count = length(data.aws_availability_zones.availability_zones.names)
vpc_id = aws_vpc.dev_vpc.id
cidr_block = "10.0.${count.index+50}.0/24"
map_public_ip_on_launch = false
availability_zone = data.aws_availability_zones.availability_zones.names[count.index]
tags = {
Name = "AZ_${count.index}_Private_Subnet"
}
}

Once these subnets are created, we expect no traffic from outside the to these subnets. It’s recommended to create a custom route table for public subnets and not open internet route on Main Route Table. We associate public subnets to the custom route table and those which are not associated with any custom route table explicitly are associated with Main route table default. (See below)

Main and Custom Route Table
Main Route Table Routes.
Public Route Table Routes.

Now we have custom route table and main route table where custom is exposed to internet and main doesn’t have a route to internet. Now the Infra is as below:

In case if we try to connect to internet from private subnet for e.g. patching, updates, install packages etc, it will not be possible for instances. Hence we need to create a NAT Gateway here which will be provisioned in Public subnet and then routing to internet address will be done via NAT Gateway from Public Subnet. Network Address Translation (NAT) Gateway is used for accessing Internet from private subnets but hiding inflow from internet. In order to create a NAT Gateway we need to have one E-IP (elastic IP or static IP) that is required to be attached to Nat Gateway and available in Public Subnet. Add below for elastic_ip and nat_gateway in main.tf

resource "aws_eip" "eip_nat" {
vpc = true
}
resource "aws_nat_gateway" "nat_gw" {
allocation_id = aws_eip.eip_nat.id
subnet_id = aws_subnet.public_subnet.id[0]
depends_on = ["aws_internet_gateway.ig_gw"]
}

Once this NAT Gateway is created we need to create a route in Main Route table (or alternatively create a Private route table). For that we retrieve Main Route table in terraform data

data "aws_route_table" "main_table" {
subnet_id = var.private_subnet_id[0]
}
resource "aws_route" "r" {
route_table_id = data.aws_route_table.main_table.id
destination_cidr_block = "0.0.0.0/0"
nat_gateway_id = "aws_nat_gateway.nat_gw.id"
}

Once we have this, our private subnet instances can also connect with Internet via NAT gateway without exposing Instances to Internet.

VPC with Public / Private Subnet

Let’s cover Creating EC2 instances in next post.

--

--

Sagar Kharab

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