AWS VPC Architecture Explained: From Beginner to Pro

AWS VPC Architecture Explained: From Beginner to Pro

A comprehensive guide to Amazon Virtual Private Cloud (VPC) — CIDR math, public/private subnets, Internet & NAT Gateways, Security Groups vs NACLs, VPC Endpoints, and packet routing mechanics.

In cloud engineering, security and isolation begin at the network layer. Every server, database, load balancer, and serverless function you deploy in Amazon Web Services (AWS) lives inside a Virtual Private Cloud (VPC).

An incorrectly configured VPC can expose private database clusters directly to the public internet, cause silent packet drops, or incur thousands of dollars in unexpected NAT Gateway data transfer charges. In this deep dive, we break down AWS networking from first principles: calculating subnets with CIDR math, designing multi-AZ high-availability public/private layouts, mastering stateful vs stateless firewalls, tracing network packet traversals, and automating infrastructure using Terraform.


1. What Is an AWS VPC? Building the Core Mental Model

1.1 The Corporate Office Building Analogy

To understand a Virtual Private Cloud (VPC), imagine renting an entire corporate office building. The building perimeter represents your VPC — an isolated section of the AWS cloud reserved exclusively for your AWS account. Inside the building, you divide space into separate floors and secure departments representing Subnets.

The main reception desk is your Internet Gateway (IGW), allowing public visitors in and out of the public lobby. Private executive offices represent Private Subnets where sensitive databases reside. To allow executives in private offices to download software updates without exposing their offices to outside visitors, you install a one-way security exit door — a NAT Gateway. Individual office door keycards represent Security Groups, while the building perimeter guard posts represent Network Access Control Lists (NACLs).

flowchart TD VPC["AWS VPC (10.0.0.0/16)"] IGW["Internet Gateway (igw-xxx)"] PubSub["Public Subnet (10.0.1.0/24)"] PrivSub["Private Subnet (10.0.2.0/24)"] NAT["NAT Gateway (nat-xxx)"] DB["RDS Database (Private)"] WEB["EC2 Web Server (Public)"] IGW <--> PubSub PubSub --> WEB PubSub --> NAT NAT --> PrivSub PrivSub --> DB

Diagram: The basic architectural isolation inside an AWS Virtual Private Cloud.

Pitfall — Overlapping CIDR blocks during multi-VPC architecture planning: Assigning default `172.31.0.0/16` or `10.0.0.0/16` IP ranges to all your VPCs prevents future VPC Peering or Transit Gateway connections. IP routing requires non-overlapping CIDR blocks across peered networks. Always allocate distinct, non-overlapping IP blocks (e.g. `10.100.0.0/16` for Production, `10.200.0.0/16` for Staging).


2. CIDR Block Allocation & Subnetting Mathematics

2.1 Classless Inter-Domain Routing (CIDR) Notation

A VPC is defined by a primary IPv4 CIDR block (e.g., 10.0.0.0/16). CIDR notation consists of an IP address followed by a slash and a prefix mask length $N \in [16, 28]$ indicating how many bits are fixed for the network prefix.

The number of total IP addresses in a $/N$ CIDR block is calculated as:

$$ \text{Total IPs} = 2^{32 - N} $$

For a /16 VPC block ($N=16$), the total address space contains $2^{16} = 65,536$ IP addresses ranging from 10.0.0.0 to 10.0.255.255. When you divide a /16 VPC into smaller /24 subnets ($N=24$), each subnet contains $2^{8} = 256$ total addresses.

2.2 The 5 Reserved AWS Subnet IP Addresses

In standard networking, 2 IP addresses per subnet are reserved (Network Address and Broadcast Address). However, AWS reserves 5 IP addresses in every subnet for internal infrastructure management:

  • 10.0.1.0 — Network Address (cannot be assigned to instances).
  • 10.0.1.1 — Reserved by AWS for the VPC Router.
  • 10.0.1.2 — Reserved by AWS for the VPC DNS Server (AmazonProvidedDNS).
  • 10.0.1.3 — Reserved by AWS for future expansion.
  • 10.0.1.255 — Network Broadcast Address (AWS VPC does not support broadcast).

Thus, the number of **usable host IP addresses** in an AWS subnet of size $/N$ is given by:

$$ \text{Usable Host IPs} = 2^{32 - N} - 5 $$

For a /24 subnet ($256$ total IPs), exactly $256 - 5 = 251$ IP addresses are usable for EC2 instances, containers, or RDS endpoints.

Pitfall — Subnet exhaustion in Kubernetes/EKS clusters: Provisioning small subnets (e.g. `/28` with only $16 - 5 = 11$ usable IPs) for Elastic Kubernetes Service (EKS) worker nodes quickly exhausts IP addresses because AWS CNI assigns a unique private IP to every single Pod running on an EC2 node. Use `/22` or `/20` subnets for container workloads.


3. Public vs Private Subnets & Internet Routing

3.1 What Makes a Subnet "Public"?

In AWS, subnets are technically identical in structure. What turns a subnet into a **Public Subnet** is its associated **Route Table**.

A subnet is classified as public if its Route Table contains a default route (0.0.0.0/0) pointing to an attached **Internet Gateway (IGW)**:

Destination CIDR Target Object Routing Behavior
`10.0.0.0/16` `local` Routes packets internally within the VPC
`0.0.0.0/0` `igw-0a1b2c3d4e5f` Routes outbound traffic to the Public Internet

3.2 Private Subnet Routing

A **Private Subnet** has a Route Table with NO route to an Internet Gateway. Instances inside private subnets receive only private IP addresses (e.g. 10.0.2.45) and are completely unreachable from external internet traffic.

3.3 Dual-Stack IPv6 Subnetting Mechanics

Modern AWS VPCs support **Dual-Stack** architecture, where subnets carry both IPv4 and IPv6 address ranges simultaneously. AWS allocates a fixed `/56` IPv6 CIDR block (providing $2^{72}$ addresses) to your VPC, from which you assign fixed `/64` subnets to each Availability Zone:

$$ \text{IPv6 Subnet Block} = 2^{64} = 18,446,744,073,709,551,616 \text{ Addresses} $$

Unlike IPv4 where NAT Gateways perform translation, IPv6 uses globally unique public IP addresses for all instances. For private IPv6 workloads requiring outbound internet connectivity without inbound accessibility, AWS provides an **Egress-Only Internet Gateway (EOIGW)**, acting as a stateless one-way IPv6 firewall equivalent to a NAT device.

Pitfall — Forgetting Auto-Assign Public IPv4 on Public Subnets: Creating an EC2 instance in a public subnet without enabling `Auto-Assign Public IP` leaves the instance with only a private IP. Even with an Internet Gateway route present, the instance cannot send or receive internet traffic because external routers cannot route private RFC 1918 IPs.


4. Outbound Internet Access: NAT Gateways vs NAT Instances

4.1 One-Way Outbound Access for Private Workloads

Private instances (e.g. backend microservices, database clusters) often require outbound access to the internet to download security patches, pull Docker base images, or call third-party APIs (like Stripe or Twilio). However, they must remain protected against incoming connection requests.

A **NAT Gateway (Network Address Translation)** provides this one-way outbound translation. The NAT Gateway MUST be deployed inside a **Public Subnet** and assigned a static **Elastic IP (EIP)**. The Private Subnet's Route Table is configured with a default route pointing to the NAT Gateway:

$$ \text{Private Route Table: } 0.0.0.0/0 \implies \text{nat-0a9b8c7d6e5f} $$

4.2 NAT Gateway vs NAT Instance Architectural Comparison

Historical AWS architectures used EC2 instances running Linux NAT software (NAT Instances). Modern architectures use managed NAT Gateways:

Feature Managed NAT Gateway Legacy NAT Instance
Management Overhead Fully managed by AWS (No OS patches) Self-managed EC2 Linux instance
Bandwidth Scaling Scales automatically up to 100 Gbps Limited by EC2 instance network capacity
High Availability Redundant within the specific Availability Zone Single point of failure unless scripted
Cost Profile ~$32/mo per AZ + $0.045/GB processed Cost of small t4g.nano instance

Pitfall — Surprise NAT Gateway data processing charges: NAT Gateways charge per-GB data processing fees ($0.045/GB). If a private EC2 instance backs up terabytes of data to an Amazon S3 bucket via a NAT Gateway, data processing fees can run into thousands of dollars. Use a free S3 Gateway VPC Endpoint instead!


5. Stateful vs Stateless Security: Security Groups vs NACLs

5.1 Dual-Layer Firewall Architecture

AWS enforces network security through two complementary firewall layers: **Security Groups (SGs)** operating at the Elastic Network Interface (ENI) level, and **Network Access Control Lists (NACLs)** operating at the Subnet boundary.

5.2 TCP Connection State Tracking Mathematics

Why are Security Groups stateful while NACLs are stateless? The answer lies in Linux kernel `conntrack` connection tracking mechanics implemented inside AWS Nitro hypervisors. When a packet enters an Elastic Network Interface (ENI), the hypervisor checks its connection tracking table $\mathcal{T}_{\text{conn}}$:

$$ \mathcal{T}_{\text{conn}} = \left\{ \text{Tuple}(\text{SrcIP}, \, \text{SrcPort}, \, \text{DstIP}, \, \text{DstPort}, \, \text{Protocol}) \mapsto \text{State} \right\} $$

If an inbound packet matches a Security Group `ALLOW` rule, the hypervisor inserts a new 5-tuple entry into $\mathcal{T}_{\text{conn}}$ marked as `ESTABLISHED`. When the instance sends a response packet back to the client, the hypervisor performs an $O(1)$ hash lookup in $\mathcal{T}_{\text{conn}}$. Because the tuple exists, the response packet is allowed out immediately without checking outbound rules.

However, connection tracking tables have finite capacity. On Nitro hypervisors, untracked security group rules (e.g. using `10.0.0.0/16` for both inbound and outbound) bypass connection tracking tables entirely, supporting higher packet-per-second throughput without table overflow risk.

5.3 Comparative Security Matrix

Security Attribute Security Group (SG) Network ACL (NACL)
Enforcement Boundary Instance / ENI Interface level Subnet boundary level
State Behavior Stateful (Return traffic automatically allowed) Stateless (Inbound & Outbound rules required)
Rule Action Support ALLOW rules only (Default deny all) ALLOW and DENY rules supported
Rule Evaluation Order All rules evaluated simultaneously Evaluated in numbered order (lowest first)

Pitfall — Ephemeral port blocking in custom NACLs: Because NACLs are stateless, allowing inbound HTTP traffic on port 80 requires explicitly allowing outbound return traffic on Ephemeral Ports (ports 1024–65535). Forgetting outbound ephemeral rules in custom NACLs causes connection timeouts on outbound requests.


6. Private Connections: VPC Endpoints & PrivateLink

6.1 Gateway Endpoints vs Interface Endpoints

By default, accessing AWS services like S3 or DynamoDB from EC2 requires sending traffic out over the internet or through a NAT Gateway. **VPC Endpoints** allow instances in private subnets to communicate privately with supported AWS services without using internet gateways, NAT devices, or VPN connections.

  • Gateway Endpoints: Free route-table targets supported for Amazon S3 and DynamoDB. They inject a prefix-list route directly into your subnet Route Table.
  • Interface Endpoints (AWS PrivateLink): Elastic Network Interfaces (ENIs) with private IP addresses created in your subnet. Powered by PrivateLink, they support S3, KMS, SQS, SNS, and custom private services.

6.2 Prefix-List Routing vs PrivateLink ENI Architecture

To understand how Gateway Endpoints avoid data processing charges, look at Route Table prefix-lists. When you create an S3 Gateway Endpoint, AWS automatically populates your Route Table with a dynamic prefix-list destination:

$$ \text{Destination: } \text{pl-63a5400a (com.amazonaws.us-east-1.s3)} \implies \text{Target: } \text{vpce-0a1b2c3d} $$

Traffic destined for S3 bypasses the default internet route completely, routing through internal AWS software-defined network (SDN) backplanes. Because no physical network interfaces or NAT instances are instantiated, AWS offers Gateway Endpoints free of charge.

In contrast, **Interface Endpoints (PrivateLink)** instantiate actual Elastic Network Interfaces (ENIs) inside your private subnets, consuming a private IP address per Availability Zone. Traffic destined for `kms.us-east-1.amazonaws.com` resolves via Amazon DNS to the private IP of the endpoint ENI (`10.0.2.88`). Traffic traverses private hypervisor cross-links directly to the AWS service infrastructure, providing high security and isolated data paths.


7. Advanced: Packet Flow Lifecycle Through a VPC Network

7.1 Step-by-Step Inbound Packet Traversal Trace

To understand AWS networking at a senior architect level, trace the step-by-step path of an HTTP GET packet originating from client IP 198.51.100.45 arriving at an EC2 instance in a public subnet:

sequenceDiagram autonumber actor Client as External Client (198.51.100.45) participant IGW as Internet Gateway (IGW) participant NACL as Inbound Subnet NACL participant RT as Subnet Route Table participant SG as Security Group (ENI) participant EC2 as EC2 Instance OS Client->>IGW: 1. Send HTTP Request to Public EIP IGW->>NACL: 2. Translate EIP to Private IP (10.0.1.15) Note over NACL: Evaluate Inbound Rules in Order NACL->>RT: 3. Pass Packet if ALLOW matched RT->>SG: 4. Route to Local ENI Note over SG: Evaluate Security Group Rules SG->>EC2: 5. Pass to Kernel Network Stack EC2-->>Client: 6. Return Traffic (Auto-allowed by SG state)

Sequence Diagram: Packet lifecycle traversing AWS IGW, NACLs, Route Tables, and Security Groups.


8. Advanced: Infrastructure-as-Code Implementation in Terraform

8.1 Production-Ready Multi-AZ VPC Module

The following complete Terraform configuration provisions a production-grade VPC spanning 2 Availability Zones with Public/Private subnets, an Internet Gateway, a NAT Gateway, and Route Tables:

# 1. Main VPC
resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"
  enable_dns_hostnames = true
  enable_dns_support = true
  tags = { Name = "prod-vpc" }
}
 
# 2. Internet Gateway
resource "aws_internet_gateway" "gw" {
  vpc_id = aws_vpc.main.id
  tags = { Name = "prod-igw" }
}
 
# 3. Public Subnet (AZ-a)
resource "aws_subnet" "public_a" {
  vpc_id = aws_vpc.main.id
  cidr_block = "10.0.1.0/24"
  availability_zone = "us-east-1a"
  map_public_ip_on_launch = true
  tags = { Name = "public-subnet-a" }
}
 
# 4. Elastic IP & NAT Gateway
resource "aws_eip" "nat_eip" {
  domain = "vpc"
  depends_on = [aws_internet_gateway.gw]
}
 
resource "aws_nat_gateway" "nat" {
  allocation_id = aws_eip.nat_eip.id
  subnet_id = aws_subnet.public_a.id
  tags = { Name = "prod-nat-gw" }
}
 
# 5. Private Subnet (AZ-a)
resource "aws_subnet" "private_a" {
  vpc_id = aws_vpc.main.id
  cidr_block = "10.0.2.0/24"
  availability_zone = "us-east-1a"
  tags = { Name = "private-subnet-a" }
}
 
# 6. Route Tables
resource "aws_route_table" "public" {
  vpc_id = aws_vpc.main.id
  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.gw.id
  }
}
 
resource "aws_route_table" "private" {
  vpc_id = aws_vpc.main.id
  route {
    cidr_block = "0.0.0.0/0"
    nat_gateway_id = aws_nat_gateway.nat.id
  }
}

9. Performance & Cost Comparison of AWS Data Transfer Paths

The chart below compares network throughput and cost profiles across AWS data access patterns for private workloads:


10. Interactive: VPC Packet Route Simulator

Click "Send Request" to trace how an outbound request from a private EC2 instance traverses the NAT Gateway and Internet Gateway to reach the web:

Simulation Idle. Click button to send request...
1. Private Subnet: EC2 Database (10.0.2.45)
Idle
2. Private Route Table Lookup
Idle
3. Public Subnet: NAT Gateway Translation
Idle
4. Internet Gateway (IGW) Egress
Idle

11. Common Architectural Traps

11.1 The Single-AZ Disaster Pattern

Deploying all subnets within a single Availability Zone (e.g. `us-east-1a`) leaves your entire application vulnerable to AWS data center outages. Always distribute subnets across at least two Availability Zones (Multi-AZ architecture) to maintain high availability.

11.2 Misconfigured Security Group Self-References

When microservices inside the same VPC need to communicate with each other, developers often hardcode IP ranges in Security Groups. Instead, use **Security Group Chaining**: configure the database Security Group to allow inbound traffic on port 5432 directly from the Web Server Security Group ID (e.g. `sg-web-servers`).

Pitfall — Missing DNS Resolution in Peered VPCs: When peering two VPCs, hostname resolution for private IP addresses fails by default. You must explicitly enable `enableDnsHostnames` and `enableDnsSupport` on both VPCs and check "Allow DNS Resolution from Remote VPC" in the Peering Connection settings.


12. Frequently Asked Questions

Q1: What is the maximum CIDR block size allowed for an AWS VPC?

The maximum CIDR block size for a VPC is `/16` (65,536 IPs). The minimum size is `/28` (16 IPs).

Q2: Can I change the primary CIDR block of a VPC after creation?

You cannot modify an existing CIDR block, but you can associate up to 4 secondary IPv4 CIDR blocks to an existing VPC.

Q3: What is the difference between a Stateful and Stateless firewall?

Stateful firewalls (Security Groups) automatically track connection state: if inbound traffic is allowed, return outbound traffic is permitted automatically. Stateless firewalls (NACLs) evaluate inbound and outbound rules independently for every packet.

Q4: Why does S3 Gateway Endpoint not incur any data processing charges?

AWS Gateway Endpoints use internal VPC route table prefix-lists without involving physical ENIs or software proxies, making them free of charge.

Q5: What is the difference between VPC Peering and AWS Transit Gateway?

VPC Peering connects two VPCs in a point-to-point mesh ($O(N^2)$ complexity). Transit Gateway acts as a central hub-and-spoke router connecting hundreds of VPCs and on-premises networks cleanly.

Q6: Can an EC2 instance in a private subnet have a public IP address?

Yes, but without a route to an Internet Gateway (`0.0.0.0/0 -> igw-xxx`), the public IP is non-functional and un-routable from the public internet.

Q7: How many NAT Gateways should I deploy for high availability?

Deploy one NAT Gateway per Availability Zone. NAT Gateways are scoped to a single AZ; if that AZ fails, private subnets in other AZs using that NAT Gateway lose outbound connectivity.

Q8: How do I test if an AWS Security Group is blocking a port?

Use AWS VPC Reachability Analyzer or `nc -zvw3 ` from a connected EC2 instance to test port connectivity.

Post a Comment

Previous Post Next Post