AWS VPC Networking 101: Subnets, Route Tables and NAT Gateways
Effective network isolation and connectivity form the bedrock of any robust cloud deployment. In Amazon Web Services (AWS), the Virtual Private Cloud…
Effective network isolation and connectivity form the bedrock of any robust cloud deployment. In Amazon Web Services (AWS), the Virtual Private Cloud (VPC) provides this fundamental capability, allowing you to provision a logically isolated section of the AWS Cloud where you can launch AWS resources in a virtual network that you define. Understanding VPC components like subnets, route tables, and NAT gateways is crucial for designing secure, scalable, and resilient architectures.
This article details the core concepts of AWS VPC networking, illustrating a common three-tier architecture with practical configurations. We'll cover subnet planning, routing mechanisms with Internet Gateways and NAT Gateways, and the critical differences between Security Groups and Network ACLs.
VPC and Subnet Design Principles
A VPC is a regional resource, meaning it spans all Availability Zones (AZs) within a given AWS region. When you create a VPC, you specify an IPv4 CIDR block for it. A common choice is a private RFC1918 range, such as 10.0.0.0/16, which provides 65,536 available IP addresses. Within this VPC, you then create subnets, which are segmentations of your VPC's IP address range and are tied to a single Availability Zone.
For high availability, best practice dictates deploying resources across at least two Availability Zones. This often translates to having identical subnet structures in multiple AZs. For a standard three-tier application, this typically involves:
- Public Subnets: These subnets are directly exposed to the internet via an Internet Gateway. They host resources like Load Balancers (ALB/NLB), web servers, or jump boxes that require inbound internet access.
- Private Application Subnets: These subnets host application servers. They need outbound internet access (e.g., to fetch software updates, connect to third-party APIs) but should not be directly reachable from the internet.
- Private Database Subnets: These subnets host databases. They typically require no internet access at all, only communication with application servers within the VPC.
Consider the following CIDR allocations for a VPC 10.0.0.0/16 across two AZs (us-east-1a and us-east-1b):
- Public Subnets:
us-east-1a:10.0.1.0/24(251 usable IPs)us-east-1b:10.0.2.0/24(251 usable IPs)
- Private Application Subnets:
us-east-1a:10.0.11.0/24(251 usable IPs)us-east-1b:10.0.12.0/24(251 usable IPs)
- Private Database Subnets:
us-east-1a:10.0.21.0/24(251 usable IPs)us-east-1b:10.0.22.0/24(251 usable IPs)
Each /24 CIDR block provides 256 IP addresses, but AWS reserves 5 addresses in each subnet for networking purposes (network address, broadcast address, VPC router, DNS, future use), leaving 251 usable IPs.
Internet Gateways and Public Routing
An Internet Gateway (IGW) is a horizontally scaled, redundant, and highly available VPC component that allows communication between instances in your VPC and the internet. It serves two purposes:
- To provide a target in your VPC route tables for internet-routable traffic.
- To perform network address translation (NAT) for instances that have been assigned public IPv4 addresses.
To make a subnet "public," you must attach an IGW to your VPC and then add a route to the IGW in the subnet's associated route table. Traffic destined for 0.0.0.0/0 (all external IP addresses) from this subnet will be routed to the IGW.
Configuration Example: Public Route Table
# Assuming VPC ID: vpc-0abcdef1234567890
# Assuming Internet Gateway ID: igw-0fedcba9876543210
# Create a route table for public subnets
aws ec2 create-route-table --vpc-id vpc-0abcdef1234567890
# Associate a tag for easy identification
aws ec2 create-tags --resources rtb-0123456789abcdef0 --tags Key=Name,Value=Public-Route-Table
# Add the default route to the Internet Gateway
aws ec2 create-route --route-table-id rtb-0123456789abcdef0 --destination-cidr-block 0.0.0.0/0 --gateway-id igw-0fedcba9876543210
# Associate public subnets (e.g., 10.0.1.0/24, 10.0.2.0/24) with this route table
# Example for subnet-0a1b2c3d4e5f6g7h8 (10.0.1.0/24)
aws ec2 associate-route-table --subnet-id subnet-0a1b2c3d4e5f6g7h8 --route-table-id rtb-0123456789abcdef0
# Example for subnet-0b1c2d3e4f5g6h7i8 (10.0.2.0/24)
aws ec2 associate-route-table --subnet-id subnet-0b1c2d3e4f5g6h7i8 --route-table-id rtb-0123456789abcdef0
NAT Gateways and Private Outbound Connectivity
Instances in private subnets cannot directly access the internet via an IGW. However, many private instances (e.g., application servers) require outbound internet access to download patches, connect to external APIs, or access S3/DynamoDB endpoints not configured with VPC endpoints. For this, AWS provides NAT Gateways.
A NAT Gateway is deployed in a public subnet and has an Elastic IP address assigned to it. It routes traffic from private instances to the internet and sends the responses back to those instances. Crucially, a NAT Gateway is a zonal resource. For high availability and to avoid cross-AZ data transfer charges, it is recommended to deploy one NAT Gateway per Availability Zone that contains private subnets needing internet access.
Each NAT Gateway should be placed in a public subnet within its respective AZ. The private subnets in that AZ then have a route for 0.0.0.0/0 pointing to the NAT Gateway.
Configuration Example: Private Route Table with NAT Gateway
# Assuming NAT Gateway ID for us-east-1a: nat-0abcdef1234567890
# Assuming NAT Gateway ID for us-east-1b: nat-0fedcba9876543210
# Route Table for Private App Subnets in us-east-1a
# Create route table
aws ec2 create-route-table --vpc-id vpc-0abcdef1234567890
aws ec2 create-tags --resources rtb-0apprt-1a --tags Key=Name,Value=Private-App-Route-Table-AZ1a
# Add route to NAT Gateway in AZ1a
aws ec2 create-route --route-table-id rtb-0apprt-1a --destination-cidr-block 0.0.0.0/0 --nat-gateway-id nat-0abcdef1234567890
# Associate private app subnet 10.0.11.0/24 (subnet-0h1i2j3k4l5m6n7o8)
aws ec2 associate-route-table --subnet-id subnet-0h1i2j3k4l5m6n7o8 --route-table-id rtb-0apprt-1a
# Route Table for Private App Subnets in us-east-1b
# Create route table
aws ec2 create-route-table --vpc-id vpc-0abcdef1234567890
aws ec2 create-tags --resources rtb-0apprt-1b --tags Key=Name,Value=Private-App-Route-Table-AZ1b
# Add route to NAT Gateway in AZ1b
aws ec2 create-route --route-table-id rtb-0apprt-1b --destination-cidr-block 0.0.0.0/0 --nat-gateway-id nat-0fedcba9876543210
# Associate private app subnet 10.0.12.0/24 (subnet-0p1q2r3s4t5u6v7w8)
aws ec2 associate-route-table --subnet-id subnet-0p1q2r3s4t5u6v7w8 --route-table-id rtb-0apprt-1b
Private Database Subnets
Database subnets (e.g., 10.0.21.0/24, 10.0.22.0/24) typically do not require any internet access, neither inbound nor outbound. Their route tables should only contain local routes for communication within the VPC.
Configuration Example: Private Database Route Table
# Route Table for Private DB Subnets in us-east-1a (no 0.0.0.0/0 route)
aws ec2 create-route-table --vpc-id vpc-0abcdef1234567890
aws ec2 create-tags --resources rtb-0dbrt-1a --tags Key=Name,Value=Private-DB-Route-Table-AZ1a
# The default local route (10.0.0.0/16 -> local) is automatically present.
# Associate private db subnet 10.0.21.0/24 (subnet-0x1y2z3a4b5c6d7e8)
aws ec2 associate-route-table --subnet-id subnet-0x1y2z3a4b5c6d7e8 --route-table-id rtb-0dbrt-1a
# Route Table for Private DB Subnets in us-east-1b
aws ec2 create-route-table --vpc-id vpc-0abcdef1234567890
aws ec2 create-tags --resources rtb-0dbrt-1b --tags Key=Name,Value=Private-DB-Route-Table-AZ1b
# Associate private db subnet 10.0.22.0/24 (subnet-0f1g2h3i4j5k6l7m8)
aws ec2 associate-route-table --subnet-id subnet-0f1g2h3i4j5k6l7m8 --route-table-id rtb-0dbrt-1b
Security Groups vs. Network ACLs
AWS provides two distinct layers of firewall functionality: Security Groups and Network Access Control Lists (NACLs). Understanding their differences is crucial for effective network security.
| Feature | Security Group (SG) | Network ACL (NACL) |
|---|---|---|
| Scope | Instance level (applies to ENIs) | Subnet level |
| Statefulness | Stateful (return traffic automatically allowed) | Stateless (must explicitly allow inbound and outbound return traffic) |
| Default Rule | Implicit deny all inbound, implicit allow all outbound | Implicit deny all inbound and outbound (after explicit rules are processed) |
| Rule Type | Allow rules only | Allow and Deny rules |
| Evaluation Order | All rules evaluated, most permissive takes precedence | Rules processed in numbered order (lowest first), stops at first match |
| Action | Only allows traffic | Allows or denies traffic |
Security Group Example
An application server (EC2 instance) in a private application subnet might have an SG:
- Inbound: Allow TCP port 80/443 from the Load Balancer's Security Group (source:
sg-0loadbalancer) - Inbound: Allow TCP port 22 from the jump box's Security Group (source:
sg-0jumpbox) - Outbound: Allow TCP port 3306 to the database's Security Group (destination:
sg-0database) - Outbound: Allow TCP port 443 to
0.0.0.0/0(for external APIs, updates)
Because SGs are stateful, if you allow inbound 80, outbound 80 return traffic is automatically allowed. If you allow outbound 443, inbound 443 return traffic is automatically allowed.
Network ACL Example
A private application subnet (10.0.11.0/24) might have a NACL:
# Inbound Rules (Order Matters!)
Rule 100: Allow TCP 80, 443 from Public Subnets (10.0.1.0/24, 10.0.2.0/24)
Rule 110: Allow TCP 22 from specific jump box IPs or CIDR
Rule 120: Allow Ephemeral Ports (1024-65535) from Public Subnets (for return traffic from internet)
Rule 130: Allow TCP 3306 from Private App Subnets (e.g., 10.0.11.0/24, 10.0.12.0/24)
*Rule *: Deny All (default, implicit)
# Outbound Rules
Rule 100: Allow TCP 80, 443 to Public Subnets (for ALB responses)
Rule 110: Allow TCP 3306 to Private DB Subnets (10.0.21.0/24, 10.0.22.0/24)
Rule 120: Allow TCP 443 to 0.0.0.0/0 (for outbound internet access via NAT)
Rule 130: Allow Ephemeral Ports (1024-65535) to 0.0.0.0/0 (for return traffic to internet endpoints)
*Rule *: Deny All (default, implicit)
The ephemeral port range for outbound traffic from a private subnet to the internet (via NAT) or for return traffic from the internet is crucial for stateless NACLs. When an instance initiates a connection, it uses a high-numbered ephemeral port as its source port. The response from the destination comes back to that ephemeral port.
Common Pitfalls
- Missing Route Table Associations: A subnet must be explicitly associated with a route table. If not, it uses the VPC's main route table, which might not be configured as intended.
- Incorrect CIDR Blocks: Overlapping CIDR blocks within a VPC or between peered VPCs will cause routing conflicts. Always plan your IP space carefully.
- Single NAT Gateway for Multiple AZs: Deploying one NAT Gateway in AZ1 and routing all private subnet traffic from AZ2 through it will incur cross-AZ data transfer costs and create a single point of failure. Deploy one NAT per AZ for resilience and cost-efficiency.
- NACL Statelessness: Forgetting to add outbound rules for return traffic or inbound rules for ephemeral ports in NACLs is a very common cause of connectivity issues, especially when traffic originates from outside the subnet.
- Security Group Scope: Security Groups apply to individual instances (ENIs), not subnets. Even if instances are in the same subnet, they may have different SGs. NACLs apply to entire subnets.
- DNS Resolution Issues: Ensure your VPC has DNS resolution enabled if your instances need to resolve public hostnames. The Amazon-provided DNS server is typically at
VPC_CIDR_BLOCK_BASE + 2(e.g.,10.0.0.2for a10.0.0.0/16VPC).