VPC Security Groups & NACLs

VPC Security Groups (SGs) and Network ACLs (NACLs) are the two packet-filtering primitives that AWS provides inside a VPC. They sit at different boundaries (ENI vs subnet), behave differently (stateful vs stateless), and are used together to form a layered network perimeter. This page covers the differences, common patterns (3-tier app, bastion, zero-trust egress), and the related primitives — VPC endpoints, PrivateLink, and SG references — that complete the picture.


1. Layered Enforcement

A packet from the internet to an EC2 instance traverses (in order) the route table, the subnet's NACL, the ENI's Security Group, and finally the instance's OS firewall. NACL and SG are AWS-managed; both must allow the traffic for it to reach the workload.

┌──────────────────────────────────────────────────────────────────────────────┐
│                          INTERNET / VPC EDGE                                 │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────────────────┐            │
│  │ Internet GW  │  │  NAT GW /    │  │  VPC Endpoint            │            │
│  │   (IGW)      │  │   Egress     │  │  Gateway / Interface     │            │
│  └──────────────┘  └──────────────┘  └──────────────────────────┘            │
└──────────────────────────────────────────────────────────────────────────────┘
                                       │
                                       ▼
┌──────────────────────────────────────────────────────────────────────────────┐
│              SUBNET BOUNDARY: NETWORK ACL (NACL)                             │
│  ┌──────────────────────────────────────────────────────────────┐            │
│  │  Stateless: evaluate inbound and outbound separately         │            │
│  │  Allow + Deny rules, numbered (lowest first), default deny   │            │
│  │  Operates at subnet boundary (one NACL per subnet)           │            │
│  └──────────────────────────────────────────────────────────────┘            │
└──────────────────────────────────────────────────────────────────────────────┘
                                       │
                                       ▼
┌──────────────────────────────────────────────────────────────────────────────┐
│             ENI BOUNDARY: SECURITY GROUP (SG)                                │
│  ┌──────────────────────────────────────────────────────────────┐            │
│  │  Stateful: return traffic auto-allowed                       │            │
│  │  Allow-only rules; references other SGs and prefix lists     │            │
│  │  Up to 5 SGs per ENI; chained (web-sg -> app-sg -> db-sg)    │            │
│  └──────────────────────────────────────────────────────────────┘            │
└──────────────────────────────────────────────────────────────────────────────┘
                                       │
                                       ▼
┌──────────────────────────────────────────────────────────────────────────────┐
│                  EC2 ENI / WORKLOAD                                          │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────────────────┐            │
│  │   EC2 / ECS  │  │   Lambda     │  │  RDS / ElastiCache       │            │
│  │   Instance   │  │   in VPC     │  │  ENI                     │            │
│  └──────────────┘  └──────────────┘  └──────────────────────────┘            │
└──────────────────────────────────────────────────────────────────────────────┘

2. Security Groups (Stateful)

3. Network ACLs (Stateless)

4. Comparison Table

┌────────────────┬────────────────────────────┬────────────────────────────┐
│ Aspect         │ Security Group             │ Network ACL (NACL)         │
├────────────────┼────────────────────────────┼────────────────────────────┤
│ Scope          │ Per ENI                    │ Per Subnet                 │
│ State          │ Stateful                   │ Stateless                  │
│ Rules          │ Allow only                 │ Allow + Deny               │
│ Order          │ All rules eval.            │ Numbered, lowest first     │
│ Default        │ Deny all in/out            │ Default NACL allows all    │
│ Refs           │ SG / Prefix Lists          │ CIDR only                  │
│ Limit          │ 60 rules each way          │ 20 rules each way          │
│ Use Case       │ Per-workload allowlist     │ Subnet block / quarantine  │
└────────────────┴────────────────────────────┴────────────────────────────┘

5. VPC Endpoints & PrivateLink

VPC endpoints let workloads reach AWS services and SaaS providers without traversing the public internet. They eliminate the need for NAT gateways for AWS-service traffic and tighten the network blast radius.

6. SG References & Chaining

The most powerful SG pattern is referencing one SG from another. Instead of pinning rules to CIDRs, you describe relationships between roles:


WebSG:
  Ingress:
    - { Protocol: tcp, Port: 443, Source: 0.0.0.0/0 }
  Egress:
    - { Protocol: tcp, Port: 8080, Destination: !Ref AppSG }   # web -> app

AppSG:
  Ingress:
    - { Protocol: tcp, Port: 8080, Source: !Ref WebSG }        # app accepts from web
  Egress:
    - { Protocol: tcp, Port: 5432, Destination: !Ref DbSG }    # app -> db

DbSG:
  Ingress:
    - { Protocol: tcp, Port: 5432, Source: !Ref AppSG }        # db accepts from app
  Egress: []                                                   # no egress at all

Adding a new app-tier instance simply adds the AppSG tag — the rules already cover it. CIDRs never come into the picture except at the edge (web-tier ingress).

7. Common Patterns


↑ Back to Top