Server

Security Groups vs Network ACLs

By Prabath Thalangama· October 24, 2026· 4 min read
#aws#vpc#networking

Introduction

AWS gives you two packet filters in a VPC. They operate at different layers and one critical difference — stateful vs stateless — explains most "I opened the port but it still doesn't work" tickets.

The comparison

Security Group Network ACL
Attached to ENI (instance, LB, RDS, etc.) subnet
Stateful? Yes — return traffic auto-allowed No — must allow both directions
Rules allow only allow and deny
Evaluation all rules, any match = allow numbered, first match wins
Default deny all inbound, allow all outbound default NACL allows all; custom denies all
Scope one resource (but reusable) every ENI in the subnet

Stateful (security group)

If you allow inbound TCP 443, the response traffic (from the instance back to the client, on a high source port) is automatically allowed — the SG tracks the connection. You only write the rule for the direction you initiate.

Inbound:  TCP 443 from 0.0.0.0/0
Outbound: (default) all

That's a complete rule set for a web server. Reference other SGs as the source (allow 5432 from sg-app) instead of IP ranges — cleaner and it follows instances as they scale.

Stateless (NACL)

A NACL evaluates each packet independently with no memory of the connection. If you allow inbound 443, the response going back out is checked against the outbound rules — and clients connect from ephemeral ports, so you must allow outbound to the ephemeral range:

Inbound  100  TCP 443            0.0.0.0/0   ALLOW
Inbound  *    ALL                0.0.0.0/0   DENY
Outbound 100  TCP 1024-65535     0.0.0.0/0   ALLOW   <- return traffic!
Outbound *    ALL                0.0.0.0/0   DENY

Forget the outbound ephemeral rule and every connection hangs — the SYN-ACK gets in but the rest of the handshake's return packets are dropped.

Ephemeral port ranges vary by client OS (Linux 32768–60999, Windows 49152–65535, NLB 1024–65535) — allow 1024–65535 to be safe.

When to use NACLs

Security groups handle the vast majority of needs. Reach for NACLs when:

  • You need an explicit deny (block a specific malicious IP range across a whole subnet) — SGs can't deny.
  • Defence in depth — a coarse subnet-level backstop so a misconfigured SG doesn't fully expose a private subnet.
  • Isolating subnets from each other regardless of SG config.

Don't use NACLs for fine-grained per-app rules — the stateless return-traffic management makes them error-prone.

Rule ordering (NACL)

Rules are processed lowest number first; the first match wins and stops evaluation. Leave gaps (100, 200, 300) so you can insert later. The final * rule is an implicit DENY you can't remove.

Verification and troubleshooting

aws ec2 describe-security-groups --group-ids sg-0abc
aws ec2 describe-network-acls --filters Name=association.subnet-id,Values=subnet-0abc

# VPC Flow Logs show ACCEPT/REJECT and which layer
aws ec2 create-flow-logs --resource-type Subnet --resource-ids subnet-0abc ...
  • SG rule added, still can't connect — check the other end's SG (the client/LB), the NACL on both subnets, the route table (is there a path?), and whether the instance OS firewall (ufw/firewalld) is also filtering.
  • Connection hangs (not refused) — asymmetric filtering. Classic NACL missing-ephemeral-outbound. Flow Logs show REJECT on the return packets.
  • Works within the subnet, fails across subnets — NACL between them, or a missing route.
  • RDS/ElastiCache unreachable from the app — the DB's SG must allow inbound from the app's SG on the DB port. Referencing the app SG is the clean way.
  • Intermittent failures under load — NACL connection tracking has limits for some protocols, or you're hitting the SG rule count / referenced-SG limits.
  • Flow Logs show ACCEPT but the app still can't talk — filtering passed; it's the OS firewall, the app not listening on 0.0.0.0, or DNS.
  • Removed a NACL deny rule, still blocked — NACL changes apply to new connections; existing tracked-by-SG connections and caches may persist briefly.
PrabathStuck on something this site can't fix?Reach out to Prabath directly on LinkedIn.