AWS Networking & Identity

VPC Fundamentals

18 min Lesson 1 of 28

VPC Fundamentals

A Virtual Private Cloud (VPC) is your logically isolated section of the AWS cloud. Think of it as your own data center inside AWS — you control the IP address ranges, subnets, routing, and access controls completely. Every EC2 instance, RDS database, Lambda function in a VPC, and EKS node lives inside one. Getting VPC design right at the start is one of the highest-leverage decisions in any AWS workload; retrofitting networking is painful at scale.

Why VPCs Exist

Before VPCs (the EC2-Classic era), all instances shared a flat, AWS-managed network. Any instance could reach any other. VPCs, introduced in 2009 and made the default in 2013, give you network isolation at the infrastructure level — not just security-group rules. Your resources are unreachable by default; you explicitly permit traffic inbound and outbound.

At companies like Amazon, Google, and Meta, networking teams enforce strict blast-radius constraints: a misconfiguration or compromise in one environment must not propagate to another. VPC isolation is the first enforcement layer.

CIDR Planning — the Decision That Ages

Every VPC has a primary CIDR block — a range of private IP addresses expressed in CIDR notation. Once assigned, you cannot shrink it; you can only add secondary CIDRs (up to 4 additional, max /28 to /16 each). Choose too small and you run out of IPs under load. Choose carelessly and you create overlapping ranges that make VPC peering, Transit Gateway, and on-premises VPN connections impossible.

RFC 1918 private ranges available for VPCs:
10.0.0.0/8 — ~16.7 million addresses (most headroom)
172.16.0.0/12 — ~1 million addresses
192.168.0.0/16 — ~65,000 addresses (too small for production)

Practical CIDR Strategy for Multi-Account AWS

In a real organization running AWS Organizations with dozens of accounts, you need a global IP plan. A common pattern used at scale:

  • Allocate a /8 or /10 supernet to the entire organization from your private address space.
  • Divide by environment: 10.0.0.0/12 for production, 10.16.0.0/12 for staging, 10.32.0.0/12 for dev.
  • Further divide by region: within production, 10.0.0.0/14 for us-east-1, 10.4.0.0/14 for eu-west-1.
  • Each VPC gets a /16 from its region's block — 65,536 addresses, enough for most workloads.
  • Subnets are carved out of the VPC CIDR as /24 (254 usable) or /22 (1,022 usable) slices.
AWS reserves 5 IPs per subnet — the first four and the last. A /24 gives you 256 − 5 = 251 usable addresses, not 254. A /28 (the smallest allowed subnet) gives only 11 usable IPs. Always size subnets larger than you think you need today; EKS node pools can exhaust a /24 quickly.

Default VPC vs Custom VPC

AWS creates a default VPC in every region for every account. It uses 172.31.0.0/16 and creates a /20 default subnet in each Availability Zone with auto-assign public IPs enabled. This is intentionally permissive for experimentation — not for production.

Problems with the default VPC in production environments:

  • Instances launched without explicitly choosing a subnet land in the default VPC and get public IPs automatically — a serious accidental exposure risk.
  • The 172.31.0.0/16 range frequently conflicts with corporate VPNs and on-premises networks.
  • No granular subnet structure — no separation between public-facing, private application, and data tiers.
  • SCP (Service Control Policies) at many companies now deny use of the default VPC entirely.
Never run production workloads in the default VPC. Many serious AWS data breaches in 2017–2020 involved instances accidentally launched into the default VPC with a permissive security group. Most security-conscious organizations delete the default VPC on account creation via automation (AWS Config rule + Lambda remediation, or a CloudFormation StackSet).

Creating a Custom VPC — CLI and Terraform

Creating a VPC via the AWS CLI is straightforward. Here you create a VPC, tag it, and enable DNS support (required for private hosted zones and EKS):

# Create a VPC with a /16 CIDR aws ec2 create-vpc \ --cidr-block 10.0.0.0/16 \ --tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=prod-us-east-1},{Key=Env,Value=production}]' \ --region us-east-1 # Enable DNS hostnames (required for Route 53 private zones, EKS) aws ec2 modify-vpc-attribute \ --vpc-id vpc-0abc123def456789 \ --enable-dns-hostnames # Enable DNS resolution aws ec2 modify-vpc-attribute \ --vpc-id vpc-0abc123def456789 \ --enable-dns-support

In production, you should manage VPCs with Terraform or AWS CloudFormation, not the CLI, so the configuration is version-controlled, auditable, and repeatable. A minimal Terraform VPC block looks like this:

# terraform/vpc/main.tf resource "aws_vpc" "main" { cidr_block = "10.0.0.0/16" enable_dns_support = true enable_dns_hostnames = true tags = { Name = "prod-us-east-1" Environment = "production" ManagedBy = "terraform" } } # Retrieve VPC ID for downstream resources output "vpc_id" { value = aws_vpc.main.id } output "vpc_cidr" { value = aws_vpc.main.cidr_block }

Anatomy of a VPC: What Lives Inside

A VPC is a container for several interconnected constructs — all of which you will configure in subsequent lessons. At a high level, every production VPC includes:

  • Subnets — partitions of the CIDR across Availability Zones (lesson 2)
  • Route Tables — per-subnet routing rules directing traffic toward gateways (lesson 2)
  • Internet Gateway (IGW) — the door to the public internet for public subnets (lesson 2)
  • NAT Gateway — outbound-only internet access for private subnets (lesson 2)
  • Security Groups — stateful firewall rules attached to ENIs (lesson 3)
  • Network ACLs — stateless subnet-level firewall rules (lesson 3)

VPC Architecture Diagram

Custom VPC architecture showing AZs, public and private subnets, IGW and NAT VPC: 10.0.0.0/16 Availability Zone A Public Subnet 10.0.0.0/24 Load Balancer / Bastion Private Subnet 10.0.10.0/24 App Servers / EKS Nodes Availability Zone B Public Subnet 10.0.1.0/24 Load Balancer / Bastion Private Subnet 10.0.11.0/24 App Servers / EKS Nodes Internet Gateway ↕ Internet
A custom VPC spanning two Availability Zones, with public and private subnets in each AZ and an Internet Gateway at the boundary.

Key Production Considerations

  • Always deploy across at least 2 AZs — one AZ failure must not take down your service.
  • Separate tiers into separate subnets — public (load balancers), private (application), data (RDS, ElastiCache). This gives you granular routing and NACL control.
  • Reserve address space — leave at least one /24 per AZ per tier unallocated for future services. Running out of IPs in a live VPC is an extremely painful migration.
  • Tag everythingName, Env, Team, CostCenter tags on every VPC and subnet. AWS Cost Explorer, Resource Groups, and compliance tooling all rely on tags.
  • Enable VPC Flow Logs from day one — sent to CloudWatch Logs or S3, these are essential for security investigations and network troubleshooting (lesson 9). Enabling them retroactively after an incident is too late.
Document your CIDR allocation in a central registry — a simple DynamoDB table, a Confluence page, or a tool like NetBox. When your organization has 50+ accounts and 200+ VPCs, undocumented CIDR overlap will block VPC peering at the worst possible time.