← All articles
Cloud Architecture 10 min read

VPC Security Architecture: Defense in Depth from Subnet to Packet

A practical guide to designing AWS VPCs that contain breaches — covering multi-tier subnets, Security Groups vs NACLs, VPC Flow Logs, egress filtering, PrivateLink, and AWS Network Firewall.

CloudDefender Team ·
Three-Tier VPC — Defense in DepthVPC 10.0.0.0/16PUBLIC SUBNET 10.0.1.0/24 — Internet Gateway routeALB / NLB | NAT Gateway | Bastion (if needed) | AWS Network Firewall endpointInbound: 443, 80 from 0.0.0.0/0 | Outbound: restricted via Network FirewallPRIVATE SUBNET 10.0.2.0/24 — NAT Gateway route onlyApp servers | ECS tasks | Lambda (VPC-attached) | EKS nodesInbound: from ALB SG only | Outbound: NAT GW | AWS services via VPC endpointsISOLATED SUBNET 10.0.3.0/24 — No internet route (no NAT, no IGW)RDS | ElastiCache | Secrets Manager endpoint | Internal servicesInbound: from app SG only | No outbound internet route at allControl Layers Applied at Each TierNACL (subnet-level, stateless): block known-bad CIDRs, restrict inter-subnet flows at the network layerSecurity Group (instance-level, stateful): allow only from specific SG IDs — never from broad CIDR ranges for internal traffic
Three-tier subnet isolation ensures that a compromise in the public tier cannot directly reach databases in the isolated tier.

A well-designed VPC is not a single network with firewall rules bolted on — it is a collection of isolated network segments, each containing only the resources appropriate to its trust level, with explicit and auditable rules governing every permitted communication path. Getting this right at the start is significantly cheaper than retrofitting it after a breach reveals that your application servers and databases were on the same flat network.

The three-tier subnet model

The foundational pattern for VPC security is three tiers of subnet, differentiated by their internet routing:

Public subnets have a route to an Internet Gateway. Only resources that must accept inbound internet traffic belong here: Application Load Balancers, Network Load Balancers, NAT Gateways, and — if required — bastion hosts. Application servers do not belong in public subnets. An EC2 instance with a public IP and a misconfigured Security Group is reachable from the entire internet; an EC2 instance in a private subnet is not reachable from the internet regardless of Security Group configuration.

Private subnets have no Internet Gateway route. Outbound internet access (for pulling packages, calling external APIs) flows through a NAT Gateway in the public subnet. AWS services — S3, Secrets Manager, SSM, ECR, CloudWatch — are accessed through VPC endpoints, not via the NAT Gateway. Application servers, ECS tasks, Lambda functions in VPC mode, and EKS worker nodes belong here.

Isolated subnets have no internet route in either direction — no NAT Gateway, no Internet Gateway, no route to anything outside the VPC except through VPC endpoints for specific AWS services. Databases (RDS, Aurora, ElastiCache), secrets endpoints, and any internal service that should never initiate or accept external connections belong here. A compromised application server in the private subnet cannot reach the database tier over the internet even if the application server’s Security Group is fully open — because the isolated subnet simply has no route.

Security Groups vs. Network ACLs

These two controls operate at different layers and are not interchangeable.

Security Groups are stateful, instance-level firewalls. A Security Group rule that allows TCP 443 inbound automatically allows the response traffic outbound without an explicit outbound rule. Security Groups are evaluated per Elastic Network Interface and support referencing other Security Groups as sources — which is the correct pattern for internal communication. Rather than allowing 10.0.0.0/16 inbound on port 5432 to a database Security Group, allow the specific application server Security Group ID. This means only traffic from instances in that Security Group reaches the database — not any IP in the VPC CIDR.

Network ACLs are stateless, subnet-level controls. Both inbound and outbound rules must be explicitly defined, and responses use ephemeral ports (1024–65535) that must be allowed in the outbound NACL rules. NACLs are evaluated in rule number order with an explicit deny-all at the end. They are best used as a backstop — blocking known-bad CIDR ranges at the subnet boundary, restricting inter-subnet traffic that Security Groups do not prevent, and providing a second control layer for defense in depth. Do not rely on NACLs as your primary traffic control mechanism; Security Groups, being stateful and resource-specific, are more precise and easier to reason about.

Egress filtering with NAT Gateway and DNS Firewall

Allowing all outbound traffic from private subnets is a common default that enables malware C2 communication, data exfiltration, and dependency confusion attacks. Two controls address this:

Route 53 Resolver DNS Firewall intercepts DNS queries from resources in your VPC and evaluates them against domain lists. AWS maintains managed lists of known-malicious domains (malware, C2, botnet infrastructure) and crypto-mining domains. Block these lists by default and add allow-list rules for domains your workloads legitimately need to reach. DNS Firewall operates before the TCP connection is made — blocking a domain prevents the traffic from ever being initiated.

AWS Network Firewall provides stateful deep-packet inspection for traffic flowing through your VPC. Deploy it in the public subnet (for internet-bound egress from private subnets via NAT Gateway) and configure stateful rules that allow only specific protocols to specific destination CIDRs. Block all outbound traffic except HTTPS to known-good destinations. Network Firewall logs flow data and rule matches to CloudWatch or S3, providing an auditable record of every outbound connection.

VPC Flow Logs for anomaly detection

Enable VPC Flow Logs on all subnets — not just the VPC level — and route them to CloudWatch Logs with a short retention window for alerting and to S3 for long-term storage. The fields most useful for security analysis are srcaddr, dstaddr, dstport, action (ACCEPT/REJECT), and log-status.

Feed Flow Logs into CloudWatch Metric Filters or Amazon Detective to alert on: high volumes of REJECT records from a single source IP (port scanning), unexpected outbound connections from isolated subnet ENIs (impossible if routing is correct, but worth monitoring as a configuration drift signal), and large outbound byte counts to non-AWS IPs from application servers.

When connecting VPCs or exposing services between accounts, the choice of connectivity model affects the security posture:

VPC Peering creates a full mesh routing path between two VPCs. Traffic can flow between any subnet in both VPCs unless Security Groups and NACLs restrict it — and maintaining those restrictions correctly across a large peered network is operationally complex. Peering also does not support transitive routing (A peers with B, B peers with C, but A cannot reach C through B).

AWS PrivateLink exposes a single service endpoint from one VPC to another, without any VPC-level routing path. The consumer VPC creates an interface endpoint and reaches only the specific service — not any other resource in the provider VPC. This is the correct model for service-to-service connectivity: zero implicit access, explicit endpoint-level policy.

Transit Gateway is the right choice for large-scale multi-VPC and multi-account connectivity. Attach all VPCs to a Transit Gateway, define route tables that control which attachments can reach which others, and apply security group-equivalent controls at the TGW route table level. Used with Network Firewall in an inspection VPC, all inter-VPC traffic can be filtered before it reaches its destination.

Takeaway

VPC security is an architectural decision that is expensive to change after the fact and inexpensive to get right at the start. The three-tier subnet model, Security Group referencing by ID rather than CIDR, DNS Firewall for egress filtering, and PrivateLink for service exposure collectively reduce the blast radius of any single compromised resource to the segment it lives in — making the difference between a contained incident and a full environment compromise.

CloudDefender

Defend your cloud. Continuously.

CloudDefender Suite gives security teams continuous posture management, threat detection, and compliance automation across AWS, Azure, and GCP — with zero false-positive fatigue.

Try CloudDefender →