Amazon VPC Essentials
VPC essentials, network architecture, CLI commands, and best practices
Amazon VPC (Virtual Private Cloud) is your isolated private virtual network in AWS. It lets you define your own IP address space, create subnets, configure route tables, and control network traffic.
The problem it solves: Network isolation, layer segmentation (web/app/db), granular access control, and secure connectivity between cloud and on-premise resources.
When to use it: ALWAYS. Every EC2, RDS, Lambda (in VPC), etc. resource needs a VPC. The question isn't "should I use VPC?" but rather "how should I design my VPC?"
Key Concepts
| Concept | Description |
|---|---|
| CIDR Blocks (Classless Inter-Domain Routing) | Notation that defines IP ranges. Format: 10.0.0.0/16• The number after / indicates fixed bits (lower number = more IPs)• /16 = 65,536 IPs ∙ /20 = 4,096 IPs ∙ /24 = 256 IPs ∙ /32 = 1 IP• AWS reserves 5 IPs per subnet (first 4 + last) |
| Subnets | Network segments within your VPC. They can be public or private. • Public: Has a route to the Internet Gateway + instances with public IPs • Private: No direct internet access (can use NAT Gateway for outbound) |
| Route Tables | Routing tables that define where traffic goes. • Main Route Table: Default for all subnets without explicit association • Custom Route Table: Manually associated with specific subnets • Common routes: 10.0.0.0/16 → local, 0.0.0.0/0 → igw-xxx |
| Internet Gateway (IGW) | The gateway between your VPC and the internet. Enables bidirectional traffic. • 1 IGW per VPC • Requires attachment to the VPC • Instances need public IPs to communicate |
| NAT Gateway | Allows instances in private subnets to access the internet (outbound only). • Location: Public subnet • Requires an Elastic IP • Unidirectional: private instances → internet (internet CANNOT initiate connections) • Cost: ~0.045/GB processed |
| Security Groups | Stateful virtual firewalls at the instance level. • Stateful: responses are automatically allowed • Only ALLOW rules (no DENY) • Can reference other Security Groups as source • Default egress: allows all when you create the SG |
| Network ACLs (NACLs) | Stateless firewalls at the subnet level (less common). • Stateless: you must allow traffic in both directions • Supports ALLOW and DENY rules • Default: allows everything |
Essential AWS CLI Commands
Creating Resources
# Create VPC
aws ec2 create-vpc \
--cidr-block 10.0.0.0/16 \
--tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=my-vpc}]' \
--region sa-east-1
# Create Subnet
aws ec2 create-subnet \
--vpc-id vpc-xxxxx \
--cidr-block 10.0.1.0/24 \
--availability-zone sa-east-1a \
--tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=public-subnet}]'
# Create Internet Gateway
aws ec2 create-internet-gateway \
--tag-specifications 'ResourceType=internet-gateway,Tags=[{Key=Name,Value=my-igw}]'
# Attach IGW to VPC
aws ec2 attach-internet-gateway \
--internet-gateway-id igw-xxxxx \
--vpc-id vpc-xxxxx
# Create NAT Gateway (requires Elastic IP first)
aws ec2 allocate-address --domain vpc # Get AllocationId
aws ec2 create-nat-gateway \
--subnet-id subnet-xxxxx \
--allocation-id eipalloc-xxxxx
# Create Route Table
aws ec2 create-route-table \
--vpc-id vpc-xxxxx \
--tag-specifications 'ResourceType=route-table,Tags=[{Key=Name,Value=public-rt}]'
# Add route to Route Table
aws ec2 create-route \
--route-table-id rtb-xxxxx \
--destination-cidr-block 0.0.0.0/0 \
--gateway-id igw-xxxxx # Or nat-gateway-id for NAT
# Associate Route Table with Subnet
aws ec2 associate-route-table \
--route-table-id rtb-xxxxx \
--subnet-id subnet-xxxxx
# Create Security Group
aws ec2 create-security-group \
--group-name my-sg \
--description "My security group" \
--vpc-id vpc-xxxxx
# Add rule to Security Group
aws ec2 authorize-security-group-ingress \
--group-id sg-xxxxx \
--protocol tcp \
--port 22 \
--cidr 203.0.113.0/24 # Or --source-group sg-yyyyyQuerying Resources
# List VPCs
aws ec2 describe-vpcs
# List Subnets in a VPC
aws ec2 describe-subnets \
--filters "Name=vpc-id,Values=vpc-xxxxx"
# View Route Tables
aws ec2 describe-route-tables \
--filters "Name=vpc-id,Values=vpc-xxxxx"
# View Internet Gateways
aws ec2 describe-internet-gateways \
--filters "Name=attachment.vpc-id,Values=vpc-xxxxx"
# View NAT Gateways
aws ec2 describe-nat-gateways \
--filter "Name=vpc-id,Values=vpc-xxxxx"
# View Security Groups
aws ec2 describe-security-groups \
--filters "Name=vpc-id,Values=vpc-xxxxx"
# View Security Group rules
aws ec2 describe-security-group-rules \
--filters "Name=group-id,Values=sg-xxxxx"Modifying Resources
# Modify subnet attribute (auto-assign public IP)
aws ec2 modify-subnet-attribute \
--subnet-id subnet-xxxxx \
--map-public-ip-on-launch
# Revoke Security Group rule
aws ec2 revoke-security-group-ingress \
--group-id sg-xxxxx \
--protocol tcp \
--port 22 \
--cidr 203.0.113.0/24Deleting Resources
# Delete NAT Gateway
aws ec2 delete-nat-gateway --nat-gateway-id nat-xxxxx
# Release Elastic IP
aws ec2 release-address --allocation-id eipalloc-xxxxx
# Disassociate Route Table
aws ec2 disassociate-route-table --association-id rtbassoc-xxxxx
# Delete Route Table
aws ec2 delete-route-table --route-table-id rtb-xxxxx
# Detach Internet Gateway
aws ec2 detach-internet-gateway \
--internet-gateway-id igw-xxxxx \
--vpc-id vpc-xxxxx
# Delete Internet Gateway
aws ec2 delete-internet-gateway --internet-gateway-id igw-xxxxx
# Delete Subnet
aws ec2 delete-subnet --subnet-id subnet-xxxxx
# Delete Security Group
aws ec2 delete-security-group --group-id sg-xxxxx
# Delete VPC (must be empty)
aws ec2 delete-vpc --vpc-id vpc-xxxxxArchitecture and Flows
Typical Architecture Diagram
Traffic Flow Diagram
Decision: Public or Private Subnet?
Best Practices Checklist
Security
- Use private subnets for resources that don't need public access (databases, app servers)
- Apply least privilege principle in Security Groups (only necessary ports, specific source IPs)
- Keep Main Route Table without an internet route (force explicit association for public subnets)
- Enable VPC Flow Logs for traffic auditing
- Don't use Default VPC in production (create custom VPCs with intentional design)
- Use NACLs for defense in depth (though Security Groups are usually sufficient)
Cost Optimization
- Delete unused NAT Gateways (32/month per idle NAT)
- Use NAT Gateway in high-availability subnet (avoid cross-AZ data transfer charges)
- Release unassociated Elastic IPs ($0.005/hour per unused EIP)
- Consider NAT Instance instead of NAT Gateway for dev/test environments (cheaper but requires management)
- Monitor data transfer costs (NAT Gateway charges $0.045/GB processed)
Performance
- Subnets in multiple Availability Zones for high availability
- Appropriate subnet sizing (leave room for growth, consider AWS's 5 IP reservation)
- Optimized Route Tables (avoid unnecessary routes that increase latency)
- Use VPC Endpoints for S3/DynamoDB (avoid internet/NAT traffic, reduces latency and costs)
Reliability
- Multi-AZ deployment (subnets in at least 2 AZs)
- Redundant NAT Gateway (1 per AZ in production)
- Route53 health checks for failover between AZs
- Backup VPC configuration (use Infrastructure as Code - Terraform/CloudFormation)
Operational Excellence
- Clear naming conventions (vpc-prod-web, subnet-public-1a, sg-bastion-prod)
- Consistent tagging (Environment, Project, Owner, CostCenter)
- Document network design (diagrams, CIDR allocations, route tables)
- Use Infrastructure as Code (avoid manual configuration, facilitates DR)
- VPC peering or Transit Gateway for inter-VPC communication (avoid public IPs)
Common Mistakes to Avoid
Main Route Table with internet route
Why it happens: When creating an IGW, you add a route to the Main RT thinking it only affects public subnets.
The problem: All subnets without an explicit route table (including private ones) become exposed to the internet.
How to avoid it:
- Main RT with only
localroute - Create a custom RT with IGW route only for public subnets
- Associate explicitly
Forgetting that NAT Gateway goes in a public subnet
Why it happens: Confusion about which subnet needs the NAT.
The problem: NAT Gateway in a private subnet can't reach the internet → private instances can't either.
How to avoid it:
- NAT Gateway ALWAYS in a public subnet (the one with a route to IGW)
- Private subnets have a
0.0.0.0/0 → nat-xxxroute
Security Groups without egress rules
Why it happens: Manually adding an ingress rule can sometimes remove the default egress rule.
The problem: Instances can't respond to requests or make outbound connections.
How to avoid it:
- Verify egress rules after modifying SG
- Explicitly add:
aws ec2 authorize-security-group-egress --protocol -1 --cidr 0.0.0.0/0
Overlapping CIDR blocks
Why it happens: Creating a VPC with the same CIDR as the Default VPC or on-premise network.
The problem: You can't create VPC Peering or VPN connections.
How to avoid it:
- Use
10.x.x.x/16for custom VPCs (avoid172.31.x.xfrom Default VPC) - Document CIDR allocations across your organization
- Plan before creating
Subnet too small
Why it happens: Using /28 (16 IPs) thinking it's enough for 10 instances.
The problem: AWS reserves 5 IPs → only 11 usable. No room to grow.
How to avoid it:
- Use
/24(256 IPs) as the baseline for subnets - Remember: AWS reserves the first 4 IPs + the last one
- Plan for 3-5x growth
Not releasing unassociated Elastic IPs
Why it happens: Deleting a NAT Gateway but forgetting about the EIP.
The problem: 3.60/month) per idle EIP.
How to avoid it:
- Check EIPs before deleting resources:
aws ec2 describe-addresses - Release immediately after deleting NAT:
aws ec2 release-address
Security Group referencing a changing public IP
Why it happens: Allowing SSH from a dynamic ISP IP, then the IP changes.
The problem: Loss of SSH access.
How to avoid it:
- Use Elastic IP for critical access
- Or use a Security Group as source (for bastion → private)
- Or use AWS Systems Manager Session Manager (doesn't require SSH)
Cost Considerations
What generates costs in VPC
| Resource | Cost | Notes |
|---|---|---|
| VPC, Subnets, Route Tables, IGW | FREE | No charge for these base resources |
| NAT Gateway | $0.045/hour | ~$32/month per NAT Gateway |
| NAT Gateway - Data Processing | $0.045/GB | All traffic that passes through NAT |
| Unassociated Elastic IP | $0.005/hour | ~$3.60/month per idle EIP |
| Elastic IP associated with running instance | FREE | Only 1 free EIP per instance |
| VPC Peering - Data Transfer | $0.01/GB | Between AZs in the same region |
| VPN Connection | $0.05/hour | ~$36/month per VPN |
| Transit Gateway | 0.02/GB | Alternative to VPC Peering for many VPCs |
How to optimize costs
-
Delete NAT Gateways in dev/test during off-hours
# Delete NAT Gateway at 8pm aws ec2 delete-nat-gateway --nat-gateway-id nat-xxxxx # Recreate at 8am (automation via Lambda + EventBridge) -
Use VPC Endpoints for S3/DynamoDB
- Avoids traffic through NAT Gateway (saves $0.045/GB)
- Reduces latency
aws ec2 create-vpc-endpoint \ --vpc-id vpc-xxxxx \ --service-name com.amazonaws.us-east-1.s3 \ --route-table-ids rtb-xxxxx -
NAT Instance instead of NAT Gateway (dev/test)
- Use t3.nano (~32/month)
- Trade-off: requires management, less throughput
-
Monitor data transfer with Cost Explorer
- Filter by "Data Transfer" usage type
- Identify top consumers
-
Release unused resources
# List unassociated EIPs (they cost money) aws ec2 describe-addresses \ --query 'Addresses[?AssociationId==`null`]'
Free Tier Limits
- VPC: Unlimited (no charge)
- Subnets: Unlimited (no charge)
- Route Tables: Unlimited (no charge)
- Security Groups: 2,500 per region (no charge)
- Internet Gateway: Unlimited (no charge)
- NAT Gateway: NOT in free tier (charges from hour 1)
- Elastic IPs: 5 per region (free if associated with running instances)
Integration with Other Services
| AWS Service | How it integrates with VPC | Typical use case |
|---|---|---|
| EC2 | Instances are launched in specific subnets | Web/app servers in public/private subnets |
| RDS | DB instances in subnet groups (multi-AZ) | Database tier in private subnet, isolated from internet |
| Lambda | Can run inside VPC | Access RDS or private resources from function |
| ELB | Load balancers in public or private subnets | ALB in public subnet, distributes to EC2 in private |
| S3 | Via VPC Endpoint (without going to internet) | Apps in private subnet access S3 without NAT Gateway |
| DynamoDB | Via VPC Endpoint | Reduce latency and data transfer costs |
| API Gateway | Private API Gateway only accessible from VPC | Internal APIs that shouldn't be exposed to internet |
| CloudFront | Origin can be an ALB in VPC | CDN that caches content from app in VPC |
| Direct Connect | Connects VPC with on-premise datacenter | Hybrid cloud + on-prem architectures |
| VPN | Virtual Private Gateway in VPC | Secure access from office to VPC resources |
| Route53 | Private Hosted Zones for internal DNS | Internal resource DNS resolution (db.internal.com) |
| CloudWatch | VPC Flow Logs for traffic monitoring | Debugging SG rules, anomaly detection |
| IAM | Instance Profiles for EC2 in VPC | Grant permissions to instances without hardcoding keys |
Additional Resources
Official Documentation
Relevant Whitepapers
- AWS Well-Architected Framework - Security Pillar
- Building a Scalable and Secure Multi-VPC AWS Network Infrastructure
- VPC Connectivity Options