0
0
AWScloud~5 mins

NAT Gateway for private subnet internet in AWS - Commands & Configuration

Choose your learning style9 modes available
Introduction
Sometimes, servers in a private network need to access the internet without exposing themselves directly. A NAT Gateway helps these private servers connect to the internet safely by acting as a middleman.
When you have servers in a private subnet that need to download updates or access external services.
When you want to keep your database servers private but allow them to reach the internet for backups.
When you want to control internet access for private resources without giving them public IP addresses.
When you want to improve security by isolating private servers from direct internet exposure.
When you need a scalable and managed way to provide internet access to private subnets.
Config File - main.tf
main.tf
provider "aws" {
  region = "us-east-1"
}

resource "aws_vpc" "example" {
  cidr_block = "10.0.0.0/16"
  tags = {
    Name = "example-vpc"
  }
}

resource "aws_subnet" "public" {
  vpc_id            = aws_vpc.example.id
  cidr_block        = "10.0.1.0/24"
  map_public_ip_on_launch = true
  availability_zone = "us-east-1a"
  tags = {
    Name = "public-subnet"
  }
}

resource "aws_subnet" "private" {
  vpc_id            = aws_vpc.example.id
  cidr_block        = "10.0.2.0/24"
  availability_zone = "us-east-1a"
  tags = {
    Name = "private-subnet"
  }
}

resource "aws_internet_gateway" "gw" {
  vpc_id = aws_vpc.example.id
  tags = {
    Name = "example-igw"
  }
}

resource "aws_eip" "nat" {
  vpc = true
  tags = {
    Name = "example-nat-eip"
  }
}

resource "aws_nat_gateway" "nat" {
  allocation_id = aws_eip.nat.id
  subnet_id     = aws_subnet.public.id
  tags = {
    Name = "example-nat-gateway"
  }
}

resource "aws_route_table" "public" {
  vpc_id = aws_vpc.example.id
  tags = {
    Name = "public-route-table"
  }
}

resource "aws_route_table_association" "public_assoc" {
  subnet_id      = aws_subnet.public.id
  route_table_id = aws_route_table.public.id
}

resource "aws_route" "public_internet_access" {
  route_table_id         = aws_route_table.public.id
  destination_cidr_block = "0.0.0.0/0"
  gateway_id             = aws_internet_gateway.gw.id
}

resource "aws_route_table" "private" {
  vpc_id = aws_vpc.example.id
  tags = {
    Name = "private-route-table"
  }
}

resource "aws_route_table_association" "private_assoc" {
  subnet_id      = aws_subnet.private.id
  route_table_id = aws_route_table.private.id
}

resource "aws_route" "private_nat_gateway" {
  route_table_id         = aws_route_table.private.id
  destination_cidr_block = "0.0.0.0/0"
  nat_gateway_id         = aws_nat_gateway.nat.id
}

This Terraform file creates a VPC with one public and one private subnet. It sets up an Internet Gateway for the public subnet and a NAT Gateway in the public subnet with an Elastic IP. The public route table routes internet traffic to the Internet Gateway. The private route table routes internet traffic through the NAT Gateway, allowing private subnet resources to access the internet safely.

Commands
This command initializes Terraform, downloading necessary plugins and preparing the working directory.
Terminal
terraform init
Expected OutputExpected
Initializing the backend... Initializing provider plugins... - Finding latest version of hashicorp/aws... - Installing hashicorp/aws v4.0.0... - Installed hashicorp/aws v4.0.0 (signed by HashiCorp) Terraform has been successfully initialized! You may now begin working with Terraform. Try running "terraform plan" to see any changes that are required for your infrastructure.
This command applies the Terraform configuration, creating all the resources defined in the file automatically without asking for confirmation.
Terminal
terraform apply -auto-approve
Expected OutputExpected
aws_vpc.example: Creating... aws_vpc.example: Creation complete after 2s [id=vpc-0abcd1234efgh5678] aws_subnet.public: Creating... aws_subnet.private: Creating... aws_subnet.public: Creation complete after 1s [id=subnet-0abcd1234efgh5678] aws_subnet.private: Creation complete after 1s [id=subnet-0abcd1234efgh5679] aws_internet_gateway.gw: Creating... aws_eip.nat: Creating... aws_internet_gateway.gw: Creation complete after 1s [id=igw-0abcd1234efgh5678] aws_eip.nat: Creation complete after 1s [id=eipalloc-0abcd1234efgh5678] aws_nat_gateway.nat: Creating... aws_nat_gateway.nat: Creation complete after 30s [id=nat-0abcd1234efgh5678] aws_route_table.public: Creating... aws_route_table.private: Creating... aws_route_table.public: Creation complete after 1s [id=rtb-0abcd1234efgh5678] aws_route_table.private: Creation complete after 1s [id=rtb-0abcd1234efgh5679] aws_route_table_association.public_assoc: Creating... aws_route_table_association.private_assoc: Creating... aws_route_table_association.public_assoc: Creation complete after 1s [id=rtbassoc-0abcd1234efgh5678] aws_route_table_association.private_assoc: Creation complete after 1s [id=rtbassoc-0abcd1234efgh5679] aws_route.public_internet_access: Creating... aws_route.private_nat_gateway: Creating... aws_route.public_internet_access: Creation complete after 1s [id=r-rtb-0abcd1234efgh5678_0] aws_route.private_nat_gateway: Creation complete after 1s [id=r-rtb-0abcd1234efgh5679_0] Apply complete! Resources: 13 added, 0 changed, 0 destroyed.
-auto-approve - Automatically approve the apply without interactive confirmation
This AWS CLI command checks the NAT Gateway created in the VPC to verify it exists and is available.
Terminal
aws ec2 describe-nat-gateways --filter Name=vpc-id,Values=vpc-0abcd1234efgh5678
Expected OutputExpected
{ "NatGateways": [ { "NatGatewayId": "nat-0abcd1234efgh5678", "VpcId": "vpc-0abcd1234efgh5678", "State": "available", "SubnetId": "subnet-0abcd1234efgh5678", "NatGatewayAddresses": [ { "PublicIp": "54.210.123.45", "AllocationId": "eipalloc-0abcd1234efgh5678" } ] } ] }
--filter - Filters the NAT Gateways by VPC ID
This command lists the route tables in the VPC to confirm the private subnet routes internet traffic through the NAT Gateway.
Terminal
aws ec2 describe-route-tables --filters Name=vpc-id,Values=vpc-0abcd1234efgh5678
Expected OutputExpected
{ "RouteTables": [ { "RouteTableId": "rtb-0abcd1234efgh5679", "VpcId": "vpc-0abcd1234efgh5678", "Routes": [ { "DestinationCidrBlock": "10.0.0.0/16", "GatewayId": "local", "State": "active", "Origin": "CreateRouteTable" }, { "DestinationCidrBlock": "0.0.0.0/0", "NatGatewayId": "nat-0abcd1234efgh5678", "State": "active", "Origin": "CreateRoute" } ] } ] }
--filters - Filters route tables by VPC ID
Key Concept

If you remember nothing else from this pattern, remember: a NAT Gateway lets private subnet servers safely access the internet without exposing them directly.

Common Mistakes
Placing the NAT Gateway in the private subnet instead of the public subnet
The NAT Gateway needs a public IP to route traffic to the internet, which private subnets do not have.
Always create the NAT Gateway in a public subnet that has internet access.
Not updating the private subnet's route table to use the NAT Gateway
Without this route, private subnet servers cannot send internet-bound traffic through the NAT Gateway.
Add a route in the private subnet's route table directing 0.0.0.0/0 traffic to the NAT Gateway.
Not allocating an Elastic IP for the NAT Gateway
The NAT Gateway requires an Elastic IP to have a stable public IP address for internet access.
Create and associate an Elastic IP with the NAT Gateway.
Summary
Initialize Terraform to prepare the environment with 'terraform init'.
Apply the configuration to create VPC, subnets, Internet Gateway, NAT Gateway, and route tables with 'terraform apply -auto-approve'.
Verify the NAT Gateway exists and is available using AWS CLI.
Check that the private subnet route table directs internet traffic through the NAT Gateway.