Security Group vs Network ACL: Which AWS Firewall to Use?
Definition
AWS provides two native firewalls inside a VPC:
- Security Group (SG) — a stateful firewall that applies at the Elastic Network Interface (ENI) level. Allow-only rules, default deny inbound, default allow outbound. Can reference other SG IDs, prefix lists, or CIDRs as sources.
- Network ACL (NACL) — a stateless firewall that applies at the subnet level. Supports both allow and deny rules, evaluated in numerical order (first match wins). Only references CIDRs.
They are not alternatives — they are layered. AWS's defense-in-depth model uses SGs as the primary allowlist at each instance and NACLs as an optional broad-deny layer at each subnet boundary. Every VPC has both.
How Each Works
Security Group (stateful, instance-level)
SGs are attached to ENIs. When a packet arrives at or leaves an ENI, AWS evaluates all SGs attached to that ENI. If any rule in any SG allows the traffic, it passes. Because SGs are stateful, the return packet is automatically allowed — you never configure ephemeral ports manually. SG rules can reference:
- CIDR blocks (
10.0.0.0/16,0.0.0.0/0) - Other SG IDs (
sg-xxxx) — dynamically resolves to all ENIs with that SG attached - AWS-managed prefix lists (e.g., S3, CloudFront) or customer-managed prefix lists
Default behavior: new custom SGs deny all inbound and allow all outbound. The VPC's default SG allows all intra-SG traffic (useful for quick testing).
Network ACL (stateless, subnet-level)
NACLs are associated with subnets (one NACL per subnet, but one NACL can cover many subnets). When a packet crosses a subnet boundary, AWS walks the NACL's rules in ascending number order and acts on the first match (allow or deny). An implicit * rule denies unmatched traffic.
Because NACLs are stateless, you must configure both directions — including the ephemeral return-port range (1024–65535 on Linux, 49152–65535 on Windows). NACL rules accept CIDRs only — no SG ID references.
Side-by-Side Comparison
| Feature | Security Group (SG) | Network ACL (NACL) | | --- | --- | --- | | Scope | Elastic Network Interface (ENI) | Subnet | | State | Stateful (return traffic automatic) | Stateless (must allow both directions) | | Rule types | Allow only | Allow and Deny | | Rule evaluation | All rules evaluated; any allow permits | Rules in numerical order; first match wins | | Source/Destination | CIDRs, SG IDs, prefix lists | CIDRs only | | Default (custom) | Deny inbound, allow outbound | Deny all inbound + outbound | | Default (AWS default) | Allow intra-SG, allow outbound | Allow all inbound + outbound | | Rule limits | 60 inbound + 60 outbound per SG; 5 SGs per ENI | 20 inbound + 20 outbound per NACL (raisable) | | Rule order | N/A (no ordering) | Explicit — lowest number first | | Applies to | Instances, ELB, RDS, Lambda-in-VPC, etc. | All traffic entering/leaving the subnet | | Price | Free | Free | | Change latency | Immediate | Immediate | | Use case | Primary allowlist | Broad deny, defense-in-depth |
Common Exam / Interview Scenarios
Scenario 1 — "My EC2 instance can't reach the internet."
Check, in order:
- Subnet route table has
0.0.0.0/0→ IGW (for public) or NAT GW (for private). - Subnet NACL allows outbound 443 to
0.0.0.0/0and inbound 1024–65535 from0.0.0.0/0(return ephemeral). Stateless! - Instance SG allows outbound 443 to
0.0.0.0/0(default does). - Instance has a public IP (for IGW path) or NAT has one.
Scenario 2 — "Block a malicious IP from reaching any workload."
Use a NACL deny rule (low number so it's evaluated first) on the relevant subnet(s). SGs can't do this because they are allow-only.
Scenario 3 — "Let only the app tier reach the DB tier."
Use SG-to-SG reference: DB SG allows 5432 from sg-app-tier. As the app tier scales in and out, the DB SG automatically picks up the new ENIs — no CIDR drift. NACLs cannot express this.
Scenario 4 — "PCI rule: no outbound traffic to the internet from the DB subnet."
Put a NACL deny on the DB subnet for outbound 0.0.0.0/0, but allow the VPC's internal CIDR. This enforces the invariant at the subnet boundary, independent of any individual instance's SG.
Defense-in-Depth Pattern
The canonical AWS architecture layers firewalls as follows:
- AWS WAF at CloudFront / ALB / API Gateway — HTTP-layer protection (SQLi, XSS, rate limits, managed rules).
- AWS Shield — DDoS at the edge (Standard is free; Advanced is paid).
- Network ACL at subnet boundary — broad deny rules, blocklists, compliance invariants.
- Security Group at ENI — fine-grained allowlist for each workload.
- Host-based firewall (iptables / Windows Firewall) — defense-in-depth for OS-level rules.
- AWS Network Firewall (optional) — deep packet inspection, IDS/IPS across a VPC.
For most workloads, SG + NACL is the baseline.
Pros and Cons Summary
Security Groups
- Pros: Stateful, supports SG-to-SG references, simple mental model, free.
- Cons: No deny rules, no hostname matching, 60-rule limit per direction.
Network ACLs
- Pros: Supports deny, subnet-level (broad impact), free.
- Cons: Stateless (ephemeral-port management is error-prone), CIDR-only, first-match-wins can bite, 20-rule default.
Pricing Model
Both SGs and NACLs are free with no rule, evaluation, or attachment charges. You pay only for the underlying VPC resources and data transfer. Because both are free and evaluated in-line, there is no reason to avoid them for cost reasons — the real cost is operational complexity.
Alternatives for Advanced Cases
- AWS Network Firewall — stateful, VPC-wide, Suricata-compatible signatures. Paid. Use for deep packet inspection, IDS/IPS, or centralized traffic inspection via Transit Gateway.
- AWS WAF — HTTP-layer (Layer 7) protection at ALB, CloudFront, API Gateway, App Runner.
- Third-party NGFW / IDS appliances — via Gateway Load Balancer (GWLB) for traffic steering.
- AWS Firewall Manager — central policy management for SGs, NACLs, WAF, Network Firewall, Shield across an AWS Organization.
Exam Relevance
- Solutions Architect Associate (SAA-C03) — extremely common topic. Typical question shapes:
- "You want to block a specific malicious IP — which service?" → NACL (SGs can't deny).
- "Traffic is flowing one way but not back — most likely cause?" → NACL stateless (missing ephemeral return rule).
- "App tier needs to talk to DB tier; how should you source the rule?" → SG-to-SG reference.
- Security Specialty (SCS-C02) — deep: defense-in-depth design, automated blocklist updates via Lambda + NACL, centralized policy via AWS Firewall Manager, audit with Config rules.
- Advanced Networking Specialty (ANS-C01) — stateful vs stateless implications across ELB, NAT Gateway, and Transit Gateway; SG for NLB (2023+).
- SysOps Administrator (SOA-C02) — troubleshooting asymmetric traffic caused by NACLs, effective-rules analysis via Reachability Analyzer and VPC Flow Logs.
Classic trap pairs: "stateful vs stateless", "allow-only vs allow+deny", "ENI vs subnet", "SG ID reference vs CIDR-only". Memorize them as a set.
Frequently Asked Questions
Q: If Security Groups are sufficient, why would I ever use NACLs?
A: NACLs give you capabilities that SGs can't: deny rules (to block specific CIDRs or threat-intel IPs), a subnet-level enforcement point (one change protects every instance in the subnet), and defense-in-depth safety. If a developer accidentally opens port 22 to the world on an SG, a NACL deny can still block that traffic at the subnet boundary. Use SGs for your day-to-day allowlist, NACLs for broad invariants and blocklists.
Q: Why do NACLs require allowing ephemeral ports but Security Groups don't?
A: Security Groups are stateful — AWS tracks the connection state (client IP, port, server IP, port) and automatically allows return packets through the same SG that permitted the initial packet. NACLs are stateless — they evaluate each packet independently, so you must explicitly allow outbound return traffic on the ephemeral port range (1024–65535 on Linux, 49152–65535 on Windows, 1024–65535 for ELB and NAT Gateway). Forgetting this is one of the top sources of "mysterious hangs" in AWS networking.
Q: Can I reference a Security Group from a NACL?
A: No. NACL rules accept CIDR blocks only. Only Security Groups can reference other SG IDs or prefix lists as sources. If you want dynamic "allow from this tier" semantics, you must use SG-to-SG references. When you need a subnet-level rule that tracks a dynamic set of instances, the usual solution is to assign those instances a well-known CIDR (via specific subnets) and NACL-allow that CIDR, then use SGs for the fine-grained logic inside.
This article reflects AWS features as of 2026. AWS services evolve rapidly — always verify against the official VPC Security documentation before making production decisions.