VPC Architecture and Subnet Design
VPC Architecture and Subnet Design
A VPC is your private network slice in the cloud. It's the foundation of network security — every resource you deploy lives inside a VPC, and the way you structure that VPC determines your attack surface, your blast radius, and your ability to segment workloads.
The three-tier architecture
The most common VPC pattern separates workloads by their exposure to the internet:
Internet
│
▼
┌─────────────────────────────────────────────┐
│ Public Subnet (ALB, NAT Gateway) │
│ Route: 0.0.0.0/0 → Internet Gateway │
└─────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ Private Subnet (App Servers, Workers) │
│ Route: 0.0.0.0/0 → NAT Gateway │
└─────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ Data Subnet (Databases, Caches) │
│ Route: No internet route at all │
└─────────────────────────────────────────────┘
Public subnets host resources that must accept inbound traffic from the internet — typically only load balancers. The route table sends 0.0.0.0/0 to an Internet Gateway.
Private subnets host application servers that need to make outbound calls (to fetch updates, call APIs) but should never accept direct inbound internet traffic. The route table sends 0.0.0.0/0 to a NAT Gateway, which allows outbound connections but blocks inbound.
Data subnets host databases and caches. They have no route to the internet at all — not even through a NAT Gateway. The only way to reach them is from the application tier in the private subnet.
Why this matters for security
The three-tier design implements defense in depth at the network layer:
- An attacker who compromises the load balancer in the public subnet still faces security groups and network ACLs before reaching the app tier
- An attacker who compromises an app server in the private subnet still faces security groups and network ACLs before reaching the database
- The database has no internet route, so even a fully compromised app server cannot exfiltrate data directly to the internet
CIDR planning
Choosing CIDR blocks is a design decision that's hard to change later. A common pattern:
VPC: 10.0.0.0/16 (65,536 IPs)
Public subnets: 10.0.1.0/24, 10.0.2.0/24 (256 IPs each, multi-AZ)
Private subnets: 10.0.10.0/24, 10.0.11.0/24
Data subnets: 10.0.20.0/24, 10.0.21.0/24
Leave room for growth — resizing a VPC CIDR is possible but operationally complex. Use non-overlapping ranges if you need to peer VPCs or connect to on-premises networks.
Route tables: the traffic cops
Every subnet has an associated route table that determines where traffic goes. The most security-critical route is the default route (0.0.0.0/0):
- Public subnet route table:
0.0.0.0/0 → igw-xxxxxxxx(Internet Gateway) - Private subnet route table:
0.0.0.0/0 → nat-xxxxxxxx(NAT Gateway) - Data subnet route table: No default route — only local VPC traffic
A common mistake is accidentally associating a data subnet with a public route table, giving the database a path to the internet. Always verify route table associations.
Security Groups and Network ACLs
Security Groups and Network ACLs
Security groups and network ACLs are the two firewall layers in a VPC. They operate differently, and understanding those differences is critical for designing effective network security.
Security groups: stateful instance-level firewalls
A security group is a stateful allow-list applied to an ENI (Elastic Network Interface). "Stateful" means that if you allow inbound traffic on a port, the return traffic is automatically allowed — you don't need a separate outbound rule.
# Security group rules for a web server
Inbound:
- Type: HTTP (80) Source: ALB security group
- Type: HTTPS (443) Source: ALB security group
- Type: SSH (22) Source: 10.0.0.0/16 (bastion only)
Outbound:
- Type: All traffic Destination: 0.0.0.0/0
(Return traffic for allowed inbound is automatically permitted)
Key properties of security groups:
- Allow-only: You can only create allow rules, not deny rules. To deny traffic, you simply don't allow it.
- Stateful: Return traffic is automatically allowed for permitted connections.
- Instance-level: Applied to ENIs, not subnets. Different instances in the same subnet can have different security groups.
- Referenced by SG ID: You can use one security group as the source/destination of another SG rule, creating a layered model.
The security group referencing pattern
Instead of using CIDR blocks as sources, reference other security groups:
# ALB security group
Inbound: 0.0.0.0/0 → 80, 443
Outbound: alb-sg → app-sg on 8080
# App server security group
Inbound: app-sg → alb-sg on 8080
Outbound: app-sg → db-sg on 5432
# Database security group
Inbound: db-sg → app-sg on 5432
Outbound: (none needed — return traffic is stateful)
This creates a clean chain: internet → ALB → app → database. Each layer only accepts traffic from the layer above it.
Network ACLs: stateless subnet-level firewalls
Network ACLs operate at the subnet level and are stateless — you must explicitly allow both inbound and outbound traffic, including return traffic.
# Network ACL rules for a private subnet
Inbound:
Rule 100: Allow 10.0.0.0/16 on ports 1024-65535 (return traffic)
Rule 110: Allow 10.0.1.0/24 on port 8080 (from ALB subnet)
Rule *: Deny all
Outbound:
Rule 100: Allow 10.0.0.0/16 on ports 1024-65535 (return traffic)
Rule 110: Allow 0.0.0.0/0 on port 443 (for API calls)
Rule *: Deny all
Key differences from security groups:
| Property | Security Group | Network ACL |
|---|---|---|
| Level | Instance (ENI) | Subnet |
| State | Stateful | Stateless |
| Rules | Allow only | Allow and Deny |
| Evaluation | All rules evaluated | Rules evaluated in order (lowest number first) |
| Default | Deny all inbound/outbound | Default allow (must add deny rules) |
When to use which
Security groups are your primary defense. They're stateful, easy to manage, and sufficient for most use cases. Use them for:
- Controlling traffic between tiers
- Restricting SSH/RDP access to bastion hosts
- Allowing specific ports between specific security groups
Network ACLs are a second layer. They're useful for:
- Subnet-level guardrails (e.g., blocking a specific IP range across an entire subnet)
- Compliance requirements that mandate subnet-level filtering
- Defense in depth — if a security group is misconfigured, the NACL provides a backstop
A common pattern: use security groups for fine-grained instance-level control, and add a NACL rule that denies known-bad IP ranges at the subnet level as an extra layer.
Common mistakes
- Using 0.0.0.0/0 as a source in security group rules — this opens the port to the entire internet. Always reference specific security groups or CIDR blocks.
- Forgetting that security groups are stateful — you don't need outbound rules for return traffic, but you do need them for new outbound connections.
- Leaving the default security group open — the default SG allows all inbound from itself and all outbound. Restrict it or don't use it.
- Not planning for ephemeral ports — when a client connects to a server, the return traffic uses a random port (1024-65535). NACLs must allow these ephemeral ports for return traffic.
Practice Problems
Design security group rules for: (a) an internet-facing ALB, (b) an app server that receives traffic from the ALB on port 8080 and connects to a database on port 5432, and (c) a PostgreSQL database. Use security group referencing, not CIDR blocks.
Solution
```
# ALB Security Group (alb-sg)
Inbound: 0.0.0.0/0 → 80, 443
Outbound: alb-sg → app-sg on 8080
# App Server Security Group (app-sg)
Inbound: app-sg ← alb-sg on 8080
Outbound: app-sg → db-sg on 5432
# Database Security Group (db-sg)
Inbound: db-sg ← app-sg on 5432
Outbound: (none — return traffic is stateful)
```
The key insight: each tier only accepts traffic from the tier above it, referenced by security group ID. The database has no outbound rules because return traffic is automatically allowed by the stateful nature of security groups. An app server in a private subnet can reach the database, but cannot make outbound HTTPS calls to an external API. The security group allows all outbound traffic. The network ACL has: Inbound rule 100 allows 10.0.0.0/16 on ports 1024-65535, Outbound rule 100 allows 0.0.0.0/0 on port 443. What's wrong?
Solution
The network ACL is stateless, so it needs explicit rules for return traffic. The outbound rule allows port 443 (the initial request), but the inbound rule only allows ports 1024-65535 from 10.0.0.0/16. The return traffic from the external API comes from an IP outside 10.0.0.0/16 on an ephemeral port. Fix: add an inbound rule allowing the external API's IP range on ports 1024-65535, or allow 0.0.0/0 on ephemeral ports for return traffic. This is why NACLs are stateless — you must explicitly allow return traffic. Quiz
1. A security group allows inbound traffic on port 443 from a specific source. What happens to the return traffic?
2. You need to block a specific malicious IP range from reaching all instances in a subnet, regardless of their security groups. Which tool is most appropriate?
3. In a three-tier VPC architecture, why should the database subnet have no route to the internet?
Flashcards
Question
What is the key difference between security groups and network ACLs?
Click to reveal answer
Answer
Security groups are stateful (return traffic auto-allowed) and operate at the instance level. Network ACLs are stateless (must explicitly allow return traffic) and operate at the subnet level.
Question
What does 'stateful' mean for security groups?
Click to reveal answer
Answer
If you allow inbound traffic on a port, the return traffic for that connection is automatically permitted without needing an explicit outbound rule.
Question
Why reference security groups instead of CIDR blocks in SG rules?
Click to reveal answer
Answer
SG referencing creates a dynamic, self-maintaining chain — if you add a new instance with the correct SG, it automatically gets the right access. CIDR blocks require manual updates and are less precise.
Question
What is the purpose of a NAT Gateway in a private subnet?
Click to reveal answer
Answer
It allows instances in private subnets to make outbound connections (fetch updates, call APIs) while preventing inbound connections from the internet. Outbound traffic is NATed through the gateway's IP.
Revision Notes
Key Takeaways
- 1. Security groups are stateful instance-level allow-lists; network ACLs are stateless subnet-level firewalls
- 2. Three-tier VPC: public (ALB), private (app), data (no internet route) implements defense in depth
- 3. Reference security groups by ID instead of CIDR blocks for maintainable tiered access
- 4. Database subnets should have no internet route to prevent direct exfiltration even if app tier is compromised
Interview Tips
- • Walk through a concrete example: 'Our three-tier VPC ensures that even a compromised app server can't directly reach the internet from the database subnet.'
- • Explain the stateful vs. stateless distinction: 'Security groups auto-allow return traffic; NACLs require explicit ephemeral port rules.'
- • Discuss the trade-off: 'NACLs add complexity but provide subnet-level guardrails that protect against SG misconfigurations.'
Cheat Sheet
VPC and Security Groups Cheat Sheet
Phase: Cloud Security Foundations | Level: intermediate
Three-tier VPC pattern:
- Public subnet: ALB only, route 0.0.0.0/0 → IGW
- Private subnet: App servers, route 0.0.0.0/0 → NAT GW
- Data subnet: Databases, NO internet route
Security groups:
- Stateful allow-lists at instance level
- Only allow rules (no deny)
- Return traffic auto-allowed
- Reference other SGs by ID for tiered access
Network ACLs:
- Stateless subnet-level firewalls
- Support both allow and deny rules
- Must explicitly allow return traffic (ephemeral ports 1024-65535)
- Rules evaluated in numbered order
SG referencing pattern:
Internet → ALB-SG → App-SG → DB-SG
Each tier only accepts traffic from the tier above.
Common mistakes:
- Using 0.0.0.0/0 as SG source
- Forgetting NACLs are stateless (must allow return traffic)
- Leaving default SG open
- Associating data subnets with public route tables
Continue Learning
Before You Start
- No prerequisites listed.