Table of Contents
Arjun, a new Cloud Security Engineer, just joined a fast-growing fintech startup. His job? To secure their AWS infrastructure.
One morning, Arjun’s manager dropped a bomb.
“We’re going live with our EC2-powered web app next week. Set up the VPC-level security. I want airtight protection — no open doors!”
Arjun smiled. “Time to meet the real gatekeepers of the AWS network – Security Groups and NACLs.”
Let’s walk through his journey — and while we’re at it, let’s understand how these two security layers actually work.
🛡️ Scene 1: The Two Types of Guards
Imagine your EC2 instance is a VIP in a secure mansion.
- Security Group (SG) is the personal bodyguard at the VIP’s door.
- NACL (Network Access Control List) is the fence guard who controls traffic entering the mansion itself (the subnet).
🧠 Quick Definitions:
Feature | Security Group | NACL |
Level | EC2 Instance | Subnet |
Rules | Allow only | Allow & Deny |
Stateful? | ✅ Yes | ❌ No |
Applies to | Only attached resources | All resources in subnet |
Rule Evaluation | All rules evaluated | First match wins (rule order matters) |
🧭 Scene 2: The Incoming Guest
Arjun sets up a custom VPC, deploys a web server EC2 in a public subnet, and waits.
A user sends a request to the server.
🛣️ Traffic path:
- 🚧 Hits the NACL first (like a checkpoint at the mansion gate).
- ✅ If allowed → reaches the subnet.
- 🕵️ Then hits the Security Group attached to EC2 (like the bodyguard at the door).
- ✅ If allowed → request reaches the server.
Now comes the twist.
✅ Security Group is Stateful
This means: If incoming traffic is allowed, the outgoing response is auto-allowed — no need to add extra outbound rules.
Arjun smiled, “Cool! I don’t have to worry about the response — SG remembers the incoming request!”
❌ NACL is Stateless
This means: For the response to leave, outbound rules in the NACL must also allow it. NACL doesn’t “remember” the initial request.
“Ah! NACL is like that guard who needs a fresh permission every time — even for return traffic.”
🌍 Scene 3: The Outgoing Request
Now, the EC2 instance tries to connect to www.google.com
.
Here’s how Arjun explains the flow:
- ✅ Security Group checks outbound rule – “Can this EC2 go out to the internet?”
- ✅ If allowed → NACL outbound rule is checked – “Can the subnet allow this?”
- 🌐 Request hits Google.
- ✅ NACL inbound rule – Must allow the response back in.
- ✅ Security Group inbound rule is not checked again because it’s stateful and remembers.
Boom. Request goes out and comes back successfully.
🔥 Scene 4: The Hidden Gate — Ephemeral Ports and NACL Confusion
During a VPC traffic inspection, Arjun hit a strange issue. His web server in the private subnet could send traffic to the RDS database, but responses weren’t coming back.
He checked the Security Group — ✅ all good.
He checked the NACL — ❌ something was off.
🧩 What’s Going On?
The traffic to the database on port 3306
(MySQL) was working fine. But the return traffic from RDS to the EC2 instance was getting blocked by the Network ACL.
That’s when it clicked:
“Oh! The response from the DB is coming back to a random high-numbered port on the EC2 instance. I forgot to allow that!”
🧠 What Are Ephemeral Ports?
Ephemeral ports are temporary, short-lived ports automatically assigned by a client’s operating system when it initiates a connection to a server.
They are used for outbound communication, and the server replies to that specific ephemeral port, not to a fixed one.
📌 Here’s What Happens Under the Hood:
- The client (EC2 web server) initiates a connection to a server (RDS).
- It randomly picks an ephemeral port, say
TCP 50123
, to open the connection. - The server (RDS) responds to this port
50123
. - If your NACL doesn’t allow inbound traffic to that port, the response will be blocked.
Ephemeral ports are client-side ports. You never define them manually, but your firewall (or NACL) must allow them for the return traffic to work.
🎯 Why Do We Need to Allow Ephemeral Ports in NACL?
Because NACLs are stateless.
Unlike Security Groups, which remember the connection and allow return traffic automatically, NACLs treat each direction (inbound/outbound) as separate rules.
So, you must:
- Allow outbound traffic from client to server (e.g., port 3306).
- AND allow inbound traffic from server to ephemeral ports (e.g., 49152–65535).
🔎 OS-Specific Ephemeral Port Ranges
Operating System | Default Ephemeral Port Range |
Linux | 32768–60999 (can be changed) |
Windows | 49152–65535 |
macOS | 49152–65535 |
🧱 Scene 5 (Deep Dive): Default vs Custom NACLs – Arjun’s Realization
After setting up a secure EC2 environment, Arjun turned his attention to subnet-level security. His company had multiple subnets:
public-subnet-1a
– for Load Balancersprivate-app-subnet-1a
– for EC2 app serversprivate-db-subnet-1a
– for RDS and backend systems
He ran this command in the console:Copy
aws ec2 describe-network-acls --region ap-south-1
And noticed something odd.
The default NACL was attached to all subnets — and it had these rules:
🟢 Inbound Rules:
Rule # | Protocol | Port Range | Source | Allow/Deny |
100 | ALL | ALL | 0.0.0.0/0 | ALLOW |
🟢 Outbound Rules:
Rule # | Protocol | Port Range | Destination | Allow/Deny |
100 | ALL | ALL | 0.0.0.0/0 | ALLOW |
😲 Why Does AWS Allow Everything by Default?
AWS is developer-friendly by design. The default NACL is:
- Meant for ease of testing.
- Ensures new subnets don’t get accidentally blocked.
- Simplifies setup for beginners using the console.
Arjun realized: “This is great for learning, but a disaster in production!”
❌ The Hidden Risks of Default NACL in Production
Arjun created a checklist of why relying on the default NACL is a security anti-pattern:
Risk | Description |
🔓 Everything Allowed | Every port, every IP, every protocol is open. |
🕳️ No IP filtering | You can’t restrict malicious IP ranges. |
🧱 No granular control | Can’t separate rules by function or environment. |
😵 No visibility | Hard to track what traffic is intended vs attack. |
🧪 Test contamination | Default NACL may allow unintentional traffic during testing. |
🛠️ Arjun’s Plan: Create Custom NACLs for Each Subnet
Why Create Custom NACLs?
Purpose | Custom NACL Strategy |
App Tier | Allow only HTTP/HTTPS from ELB subnet |
DB Tier | Allow MySQL from App subnet only |
Logging Tier | Allow only specific NAT/SSM traffic |
Auditability | Easily trace which rule does what |
Least Privilege | Every subnet gets just enough access |
“Subnet equals a zone. Each zone gets a gatekeeper tailored to its purpose.”
🔢 Rule Numbering – Arjun’s Golden Rules
Unlike Security Groups, NACLs evaluate rules in order, starting from lowest number.
So Arjun used this pattern:
Rule Number | Purpose | Example |
100 | Allow Critical | HTTP/HTTPS, SSH |
200 | Allow App Traffic | RDS, Redis, etc. |
300 | Ephemeral Port Range | Allow return traffic |
400 | Internal Services | NAT, SSM, etc. |
900 | Explicit Deny | Block suspicious CIDRs |
Default | Deny All | Implicit at end |
🧪 Case Study: Blocking a Malicious IP Using NACL
During an internal audit, Arjun discovered brute-force login attempts from 5.188.62.113
.
With Security Groups, he couldn’t explicitly deny this IP.
So, he added a Deny rule in the NACL:Copy
Rule # : 10
Type : ALL
Protocol: ALL
Source : 5.188.62.113/32
Action : DENY
What happened?
- All requests from that IP got dropped.
- Even if SG allowed it, NACL dropped it first (since NACL is evaluated before SG).
He added logging via VPC Flow Logs to monitor similar threats.
🎯 Best Practices for NACLs – Arjun’s Production Checklist
Practice | Description |
✅ Create custom NACLs | One per subnet or environment |
✅ Use allow + deny rules | Control access precisely |
✅ Follow least privilege | Start with deny-all, then allow what’s needed |
✅ Number wisely | Use 100, 200… avoid clutter |
✅ Tag everything | So audits and reviews are easy |
✅ Don’t mix prod & dev in one NACL | Separate environment = separate controls |
✅ Open ephemeral ports | Allow 1024–65535 inbound for responses |
✅ Don’t forget NAT/SSM ports | Allow NAT traffic (like 443, 80 outbound) and SSM (443 to region endpoint) |
🧠 Memory Hook (For AWS SAA Exam):
“SGs are forgiving. NACLs are strict.
SGs remember your previous action. NACLs ask every time.”
🏁 Conclusion: Arjun’s Takeaway
At the end of the week, Arjun had this posted on his Slack channel:
“Default NACLs are for learners.
Custom NACLs are for leaders.
If you’re running prod traffic through an open fence, you’re asking for trouble.”
Read More About AWS VPC
- AWS VPC Explained: Build Your First Private Cloud
- Avoid Mistakes with AWS Reserved IP Addresses
- Secure Your Network with AWS VPC Route Table
- Discover AWS Hyperplane: Smart AWS Traffic Manager
- Why EC2 Instance Connect Fails Despite IP Whitelist
- Why AWS Bastion Host Are Essential for Secure SSH Access?
- 7 Proven Steps to Secure Private EC2 in AWS VPC
- Mastering AWS Security Groups vs NACLs the Right Way