Reading30 min read·Module 1High exam weight

Security Groups & Network ACLs

Key concepts

  • Security groups are stateful

  • NACLs are stateless

  • Security groups at instance level

  • NACLs at subnet level

  • Rule evaluation order

Overview

AWS provides two primary mechanisms for controlling network traffic in a VPC: Security Groups and Network Access Control Lists (NACLs). Understanding the differences between them - particularly stateful vs stateless behavior - is critical for both the SAA-C03 exam and building secure architectures.

Security Groups operate at the instance level and are stateful, meaning return traffic is automatically allowed. NACLs operate at the subnet level and are stateless, requiring explicit rules for both inbound and outbound traffic. Together, they implement a defense-in-depth strategy.

The Key Difference

Security Groups = Stateful (return traffic automatically allowed) NACLs = Stateless (must explicitly allow return traffic)

This fundamental difference affects how you write rules and is frequently tested on the exam.

Exam Tip

If a question mentions 'blocking a specific IP address,' think NACLs - Security Groups only have Allow rules. If it mentions 'instance-level' control or 'stateful,' think Security Groups.


Architecture Diagram

Security Groups vs NACLs
Figure 1: Security Groups operate at instance level (stateful), NACLs at subnet level (stateless)

Key Concepts

Security Groups

Security Groups

Security Groups act as virtual firewalls for EC2 instances and other resources.

Key Characteristics:

  • Stateful: Return traffic automatically allowed
  • Instance-level: Applied to ENIs (Elastic Network Interfaces)
  • Allow rules only: Cannot create deny rules
  • All rules evaluated: No rule ordering
  • Default behavior: Deny all inbound, allow all outbound

What Can Use Security Groups:

  • EC2 instances
  • RDS instances
  • Lambda (VPC)
  • ELB/ALB/NLB
  • ElastiCache
  • EFS mount targets
  • VPC endpoints

Network ACLs (NACLs)

Network ACLs

Network ACLs are stateless firewalls that control traffic at the subnet boundary.

Key Characteristics:

  • Stateless: Must allow both inbound AND outbound explicitly
  • Subnet-level: Affects all instances in the subnet
  • Allow AND Deny rules: Can explicitly block traffic
  • Rules processed in order: Lowest number first, first match wins
  • Default behavior: Allow all (default NACL), Deny all (custom NACL)

NACL Rule Components:

  • Rule number (1-32766)
  • Protocol (TCP, UDP, ICMP, all)
  • Port range
  • Source/Destination CIDR
  • Allow or Deny

Stateful vs Stateless Explained

Stateful Behavior

Stateful (Security Groups):

When you allow inbound traffic on port 443:

  • Inbound: HTTPS requests come in ✓
  • Outbound: Responses go out automatically ✓ (no outbound rule needed)

The security group "remembers" the connection and allows the response.

Inbound Rule:  Allow HTTPS (443) from 0.0.0.0/0
Outbound Rule: Not needed for responses to inbound requests

Stateless Behavior

Stateless (NACLs):

When you allow inbound traffic on port 443:

  • Inbound: HTTPS requests come in ✓
  • Outbound: Responses BLOCKED ✗ (unless explicitly allowed)

You MUST create an outbound rule for the response traffic (ephemeral ports).

Inbound Rule:  Allow HTTPS (443) from 0.0.0.0/0
Outbound Rule: Allow TCP 1024-65535 to 0.0.0.0/0 (ephemeral ports for responses)

Comparison Table

Security Groups vs NACLs

FeatureSecurity GroupsNACLs
LevelInstance (ENI)Subnet
StateStatefulStateless
Rule TypesAllow onlyAllow AND Deny
Rule ProcessingAll rules evaluatedRules processed in order
Default InboundDeny allAllow all (default NACL)
Default OutboundAllow allAllow all (default NACL)
Applies ToSpecific resourcesAll resources in subnet
Return TrafficAutomaticMust be explicitly allowed
Use CasePrimary access controlSubnet-level backup/block lists

How It Works

Security Group Rules

TEXTSecurity Group Rules Example
INBOUND RULES:
┌─────────┬──────────┬───────────┬─────────────────────┐
│ Type    │ Protocol │ Port      │ Source              │
├─────────┼──────────┼───────────┼─────────────────────┤
│ HTTPS   │ TCP      │ 443       │ 0.0.0.0/0           │
│ SSH     │ TCP      │ 22        │ 10.0.0.0/8          │
│ Custom  │ TCP      │ 3306      │ sg-app-servers      │
│ All     │ All      │ All       │ sg-self (self-ref)  │
└─────────┴──────────┴───────────┴─────────────────────┘

OUTBOUND RULES:
┌─────────┬──────────┬───────────┬─────────────────────┐
│ Type    │ Protocol │ Port      │ Destination         │
├─────────┼──────────┼───────────┼─────────────────────┤
│ All     │ All      │ All       │ 0.0.0.0/0           │
└─────────┴──────────┴───────────┴─────────────────────┘

Note: Outbound "allow all" is the default. Responses to inbound
requests work automatically due to stateful behavior.

NACL Rules

TEXTNACL Rules Example
INBOUND RULES:
┌────────┬─────────┬──────────┬───────────┬───────────────┬────────┐
│ Rule # │ Type    │ Protocol │ Port      │ Source        │ Action │
├────────┼─────────┼──────────┼───────────┼───────────────┼────────┤
│ 100    │ HTTPS   │ TCP      │ 443       │ 0.0.0.0/0     │ ALLOW  │
│ 110    │ HTTP    │ TCP      │ 80        │ 0.0.0.0/0     │ ALLOW  │
│ 120    │ SSH     │ TCP      │ 22        │ 10.0.0.0/8    │ ALLOW  │
│ 130    │ Custom  │ TCP      │ 1024-65535│ 0.0.0.0/0     │ ALLOW  │
│ *      │ All     │ All      │ All       │ 0.0.0.0/0     │ DENY   │
└────────┴─────────┴──────────┴───────────┴───────────────┴────────┘

OUTBOUND RULES:
┌────────┬─────────┬──────────┬───────────┬───────────────┬────────┐
│ Rule # │ Type    │ Protocol │ Port      │ Destination   │ Action │
├────────┼─────────┼──────────┼───────────┼───────────────┼────────┤
│ 100    │ HTTPS   │ TCP      │ 443       │ 0.0.0.0/0     │ ALLOW  │
│ 110    │ HTTP    │ TCP      │ 80        │ 0.0.0.0/0     │ ALLOW  │
│ 120    │ Custom  │ TCP      │ 1024-65535│ 0.0.0.0/0     │ ALLOW  │
│ *      │ All     │ All      │ All       │ 0.0.0.0/0     │ DENY   │
└────────┴─────────┴──────────┴───────────┴───────────────┴────────┘

Note: Rule 130 inbound allows ephemeral ports for responses.
Rule 120 outbound allows ephemeral ports for responses to outbound requests.
Rule * is the default deny (always last, cannot be deleted).

Ephemeral Ports

Ephemeral Ports

Ephemeral ports (1024-65535) are temporary ports used for the return traffic of a connection.

When a client connects to your server on port 443:

  • Client uses ephemeral port (e.g., 52436) as source
  • Server responds to that ephemeral port
  • NACL must allow outbound traffic to ephemeral ports for responses

Different OS ranges:

  • Linux: 32768-60999
  • Windows: 49152-65535
  • Safe range: 1024-65535 (covers all)

For NACLs, always include ephemeral port rules!

Creating Security Groups (CLI)

SHCreate and Configure Security Group
# Create security group
aws ec2 create-security-group \
  --group-name WebServer-SG \
  --description "Security group for web servers" \
  --vpc-id vpc-xxx

# Add inbound rule for HTTPS
aws ec2 authorize-security-group-ingress \
  --group-id sg-xxx \
  --protocol tcp \
  --port 443 \
  --cidr 0.0.0.0/0

# Add inbound rule referencing another security group
aws ec2 authorize-security-group-ingress \
  --group-id sg-database \
  --protocol tcp \
  --port 3306 \
  --source-group sg-app-servers

# Revoke a rule
aws ec2 revoke-security-group-ingress \
  --group-id sg-xxx \
  --protocol tcp \
  --port 22 \
  --cidr 0.0.0.0/0

Creating NACLs (CLI)

SHCreate and Configure NACL
# Create NACL
aws ec2 create-network-acl \
  --vpc-id vpc-xxx

# Add inbound allow rule
aws ec2 create-network-acl-entry \
  --network-acl-id acl-xxx \
  --rule-number 100 \
  --protocol tcp \
  --port-range From=443,To=443 \
  --cidr-block 0.0.0.0/0 \
  --rule-action allow \
  --ingress

# Add inbound deny rule (block specific IP)
aws ec2 create-network-acl-entry \
  --network-acl-id acl-xxx \
  --rule-number 50 \
  --protocol tcp \
  --port-range From=0,To=65535 \
  --cidr-block 1.2.3.4/32 \
  --rule-action deny \
  --ingress

# Add outbound rule for ephemeral ports
aws ec2 create-network-acl-entry \
  --network-acl-id acl-xxx \
  --rule-number 100 \
  --protocol tcp \
  --port-range From=1024,To=65535 \
  --cidr-block 0.0.0.0/0 \
  --rule-action allow \
  --egress

# Associate NACL with subnet
aws ec2 replace-network-acl-association \
  --association-id aclassoc-xxx \
  --network-acl-id acl-xxx

Use Cases

Use Case 1: Web Application Security

Scenario: Three-tier web application with ALB, app servers, and database.

Security Group Chaining
Figure 2: Security Group references create a chain of trust between tiers

Security Groups:

  • ALB-SG: Inbound 443 from 0.0.0.0/0
  • App-SG: Inbound 8080 from ALB-SG only
  • DB-SG: Inbound 3306 from App-SG only

NACLs:

  • Default allow (rely on security groups for primary control)

Use Case 2: Block Known Malicious IPs

Scenario: Need to block traffic from known bad actors.

NACL IP Blocking
Figure 3: NACLs can explicitly deny traffic - Security Groups cannot

Solution: Use NACLs with deny rules

  • Rule 10: DENY all traffic from 1.2.3.4/32
  • Rule 20: DENY all traffic from 5.6.7.0/24
  • Rule 100+: Allow legitimate traffic

Security groups cannot do this (no deny rules).

Use Case 3: Restrict SSH Access

Scenario: SSH should only be accessible from corporate network.

Security Group:

  • Inbound: SSH (22) from 10.0.0.0/8 (corporate CIDR)

NACL (additional layer):

  • Rule 90: DENY SSH (22) from 0.0.0.0/0
  • Rule 100: ALLOW SSH (22) from 10.0.0.0/8

Use Case 4: Self-Referencing Security Group

Scenario: Allow all instances in an Auto Scaling group to communicate with each other.

Security Group:

Inbound: All traffic from sg-self (reference same SG)

This allows any instance with this SG to talk to any other instance with the same SG.


Best Practices

Security Group Best Practices
  1. Start with Least Privilege - Begin with no inbound rules, add as needed
  2. Use Security Group References - Reference other SGs instead of CIDR when possible
  3. One Purpose per SG - Create separate SGs for web, app, database tiers
  4. Avoid 0.0.0.0/0 - Be specific about sources when possible
  5. Name and Tag Descriptively - Easy to understand purpose
  6. Review Regularly - Remove unused rules
  7. Use for Primary Control - More flexible than NACLs
NACL Best Practices
  1. Use as Secondary Control - Primary control should be Security Groups
  2. Leave Gaps in Rule Numbers - Use 100, 110, 120... to allow insertions
  3. Always Include Ephemeral Ports - Required for stateless responses
  4. Lower Numbers for Denies - Process deny rules before allow rules
  5. Document Rule Purpose - NACLs don't have descriptions
  6. Use for Subnet-Wide Blocks - Blocking bad IPs, compliance requirements
  7. Default NACL is Permissive - Create custom NACLs for production

Common Exam Scenarios

Exam Scenarios

ScenarioSolutionWhy
Block specific IP from accessing EC2NACL deny ruleSecurity Groups only have allow rules
Allow app servers to access RDSSecurity Group referencing app SGInstance-level, stateful, SG-to-SG reference
Allow HTTPS but connection times outCheck NACL outbound ephemeral portsStateless - needs explicit outbound rule
Allow instances in same tier to communicateSelf-referencing Security GroupSG can reference itself
Web traffic allowed but SSH blocked for subnetNACL with allow HTTP/HTTPS, deny SSHSubnet-level control with deny capability
Need to allow return trafficSecurity Group: automatic; NACL: explicit ruleStateful vs stateless behavior
Multiple security groups on instanceAll rules combined (union)All SG rules are evaluated together
Rule order mattersNACL only (lowest number first)SGs evaluate all rules; NACLs are ordered

Common Pitfalls

Pitfall 1: Forgetting Ephemeral Ports in NACLs

Mistake: Adding NACL inbound rule for HTTPS but no outbound rule for responses.

Symptom:

  • Connections time out
  • Requests seem to reach server but no response

Why it happens:

  • NACLs are stateless
  • Responses need explicit outbound rule
  • Ephemeral ports (1024-65535) must be allowed

Correct Approach:

  • Always add outbound rule for ephemeral ports
  • Or use default NACL (allows all)
Pitfall 2: Using NACL When Security Group Would Work

Mistake: Creating complex NACL rules when Security Groups would be simpler.

Why it's problematic:

  • NACLs are harder to manage (stateless)
  • Affects entire subnet, not specific resources
  • Rule ordering can be confusing

Correct Approach:

  • Use Security Groups as primary control
  • Use NACLs only for subnet-wide policies or deny rules
  • Keep NACLs simple
Pitfall 3: Expecting NACL Rule Order Like SGs

Mistake: Assuming all NACL rules are evaluated like Security Groups.

Why it causes issues:

  • NACL rules processed in order (lowest first)
  • First match wins, stops processing
  • Rule 100 ALLOW then Rule 200 DENY = ALLOWED

Correct Approach:

  • Put DENY rules with lower numbers than ALLOW
  • Example: Rule 50 DENY bad IP, Rule 100 ALLOW good traffic
Pitfall 4: Using 0.0.0.0/0 Everywhere

Mistake: Allowing all sources (0.0.0.0/0) for convenience.

Why it's dangerous:

  • Exposes resources to entire internet
  • Increases attack surface
  • Violates least privilege

Correct Approach:

  • Be specific about source CIDRs
  • Use Security Group references when possible
  • Only use 0.0.0.0/0 for public-facing services (ALB)

Test Your Knowledge

Q

What is the key difference between Security Groups and NACLs?

ASecurity Groups are faster
BSecurity Groups are stateful, NACLs are stateless
CNACLs can only allow traffic
DSecurity Groups operate at subnet level
Q

A web server's Security Group allows inbound HTTPS (443). The NACL allows inbound 443 but users cannot connect. What is likely missing?

AOutbound rule in Security Group
BInbound rule for port 80
COutbound NACL rule for ephemeral ports
DSecond inbound NACL rule
Q

You need to block a specific IP address from accessing any resource in a subnet. Which should you use?

ASecurity Group deny rule
BNACL deny rule
CRoute table black hole
DIAM policy
Q

An EC2 instance has two Security Groups attached. SG1 allows SSH, SG2 does not mention SSH. Is SSH allowed?

ANo - both SGs must allow
BYes - rules are combined (union)
CDepends on rule order
DOnly if NACL also allows


Quick Reference

Security Group Limits

Security Group Limits

LimitDefault Value
Security groups per VPC2,500
Rules per security group60 inbound + 60 outbound
Security groups per ENI5 (can increase to 16)
Rules evaluated per ENI1,000

NACL Limits

NACL Limits

LimitDefault Value
NACLs per VPC200
Rules per NACL20 inbound + 20 outbound
NACLs per subnet1 (one-to-one)
Subnets per NACLUnlimited

Common Port Numbers

TEXTCommon Ports Reference
HTTP:       80
HTTPS:      443
SSH:        22
RDP:        3389
MySQL:      3306
PostgreSQL: 5432
SQL Server: 1433
Redis:      6379
Memcached:  11211
NFS (EFS):  2049
SMTP:       25 (or 587 for TLS)
DNS:        53 (TCP and UDP)

Ephemeral:  1024-65535 (safe range for all OS)

CLI Commands Reference

SHSecurity Group & NACL CLI Commands
# List security groups
aws ec2 describe-security-groups --filters "Name=vpc-id,Values=vpc-xxx"

# List security group rules
aws ec2 describe-security-group-rules --filters "Name=group-id,Values=sg-xxx"

# List NACLs
aws ec2 describe-network-acls --filters "Name=vpc-id,Values=vpc-xxx"

# Get NACL entries
aws ec2 describe-network-acls --network-acl-ids acl-xxx

# Delete NACL entry
aws ec2 delete-network-acl-entry \
  --network-acl-id acl-xxx \
  --rule-number 100 \
  --ingress

Further Reading

Related services

VPCEC2