AWS VPC Deep Dive: Building Isolated Network Architectures
When building cloud infrastructure, network isolation and security are paramount. AWS Virtual Private Cloud (VPC) provides the foundation for creating logically isolated networks in the cloud. Let me walk you through the essential concepts and practical patterns I've learned from building production systems.
What is a VPC?
A Virtual Private Cloud is your own private network within AWS. Think of it as your own data center in the cloud, where you have complete control over IP address ranges, subnets, routing tables, and network gateways.
Core Components
CIDR Blocks
Every VPC needs a CIDR (Classless Inter-Domain Routing) block that defines the IP address range. Common choices:
- 10.0.0.0/16 - Provides 65,536 IP addresses (most common)
- 172.16.0.0/12 - Alternative private range
- 192.168.0.0/16 - Smaller networks
# Example VPC creation
aws ec2 create-vpc --cidr-block 10.0.0.0/16
Subnets
Subnets divide your VPC into smaller network segments. The key distinction:
- Public Subnets: Have a route to an Internet Gateway (IGW)
- Private Subnets: No direct internet access, typically use NAT Gateway
A best practice is to use multiple Availability Zones (AZs) for high availability:
VPC: 10.0.0.0/16
├── Public Subnet 1a: 10.0.1.0/24 (us-east-1a)
├── Public Subnet 1b: 10.0.2.0/24 (us-east-1b)
├── Private Subnet 1a: 10.0.11.0/24 (us-east-1a)
└── Private Subnet 1b: 10.0.12.0/24 (us-east-1b)
Route Tables
Route tables control traffic flow. Each subnet must be associated with a route table:
- Public Route Table: Routes
0.0.0.0/0to Internet Gateway - Private Route Table: Routes
0.0.0.0/0to NAT Gateway (for outbound internet)
Security Groups vs Network ACLs
Security Groups (stateful, instance-level):
- Act as virtual firewalls for EC2 instances
- Rules are evaluated for both request and response
- Default deny all, explicit allow rules
Network ACLs (stateless, subnet-level):
- Additional layer of security at subnet level
- Rules evaluated separately for inbound/outbound
- Default allow all
Security Groups are usually sufficient for most use cases. Network ACLs add complexity but can be useful for compliance requirements.
Common Architectures
Three-Tier Architecture
Internet
↓
Internet Gateway
↓
Public Subnets (ALB, NAT Gateway)
↓
Private Subnets (Application Servers)
↓
Private Subnets (Database)
This pattern ensures:
- Web servers in public subnets handle user traffic
- Application servers in private subnets process business logic
- Databases in isolated private subnets with no internet access
VPC Peering
Connect two VPCs for private communication:
# Create peering connection
aws ec2 create-vpc-peering-connection \
--vpc-id vpc-12345 \
--peer-vpc-id vpc-67890
Important considerations:
- CIDR blocks must not overlap
- Update route tables in both VPCs
- Security groups must allow traffic
VPC Endpoints
Access AWS services privately without internet:
- Gateway Endpoints: For S3 and DynamoDB (free)
- Interface Endpoints: For other services (charges apply)
This is crucial for compliance and reducing data transfer costs.
Best Practices
- Use separate VPCs for different environments (dev, staging, prod)
- Enable VPC Flow Logs for network monitoring and troubleshooting
- Use AWS PrivateLink for secure service-to-service communication
- Implement least privilege in security group rules
- Use AWS Transit Gateway for complex multi-VPC architectures
Cost Optimization
- NAT Gateways are expensive (~$32/month + data transfer). Consider NAT Instances for non-production
- VPC Endpoints can reduce data transfer costs
- Use VPC Flow Logs selectively (they generate charges)
Real-World Example
Here's a production-ready VPC setup I've used:
# Terraform example
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "production-vpc"
}
}
resource "aws_subnet" "public" {
count = 2
vpc_id = aws_vpc.main.id
cidr_block = "10.0.${count.index + 1}.0/24"
availability_zone = data.aws_availability_zones.available.names[count.index]
map_public_ip_on_launch = true
}
resource "aws_subnet" "private" {
count = 2
vpc_id = aws_vpc.main.id
cidr_block = "10.0.${count.index + 11}.0/24"
availability_zone = data.aws_availability_zones.available.names[count.index]
}
Conclusion
Understanding VPC architecture is fundamental to building secure, scalable AWS infrastructure. Start simple with a basic public/private subnet setup, then evolve based on your needs. The key is balancing security, availability, and cost.
Remember: every production system should have private subnets for sensitive resources, and public subnets should only contain resources that need direct internet access.