VPC segmentation
Identity-referenced SGs, private subnets, blast radius.
The network is your second containment layer after identity: even if a credential leaks, tight segmentation decides whether an attacker reaches one service or the whole estate. The goal is default-closed — nothing reachable until you deliberately open the smallest path.
Security groups by reference, private by default
Security groups are stateful allowlists attached to an ENI; return traffic is automatic. Reference them by group ID rather than CIDR so tiers allow each other by identity — the DB SG allows the app SG, the app SG allows the load-balancer SG, and nothing allows 0.0.0.0/0 except the edge. Then scaling never widens the surface and there is no IP list to maintain. Network ACLs are the stateless, subnet-level complement, evaluating numbered rules in both directions.
# DB allows Postgres ONLY from the app SG — no CIDRs, no public path.resource "aws_security_group_rule" "db_from_app" {type = "ingress"from_port = 5432 to_port = 5432 protocol = "tcp"security_group_id = aws_security_group.db.idsource_security_group_id = aws_security_group.app.id # identity, not IP}# The DB lives in a private subnet with no route to an internet gateway.
Subnet tiers and blast radius
Put internet-facing load balancers in public subnets and everything else — app tiers, databases, caches — in private subnets with no route to an internet gateway. Multi-account structure (a VPC per environment, prod isolated from staging) bounds a compromise to one account. The default VPC ships public subnets and permissive defaults precisely so "hello world" works; build production VPCs deliberately and leave the default one unused.