AWS Security Groups and NACLs: Deep Dive and Practical Implementation
This chapter explores the core security mechanisms within an AWS Virtual Private Cloud (VPC): Security Groups and Network Access Control Lists (NACLs). We will examine how these two layers function as the final lines of defense for your cloud applications, analyze their operational differences, and walk through a practical, step-by-step implementation of a custom VPC hosting a Python-based web application.
1. The Paradigm of Shared Security in AWS
When organizations transition workloads from on-premises data centers to the public cloud, security is invariably their primary concern. AWS addresses this concern through the Shared Responsibility Model.
AWS guarantees the physical security of the data centers, virtualization hypervisors, and underlying hardware. However, configuring the network access controls, firewalls, and application-level security is the sole responsibility of the customer (specifically DevOps engineers, cloud administrators, and security teams).
VPC security features—specifically Security Groups and NACLs—serve as the last point of security before external user traffic reaches your running application. If these components are misconfigured, even the most robust application architecture remains vulnerable to exploitation.
2. VPC IP Addressing and Subnetting Foundations
Before securing a network, you must define its boundaries. When creating a VPC, you specify an IP address range using Classless Inter-Domain Routing (CIDR) notation. This range determines the maximum capacity of your virtual network.
CIDR Math and Sizing
The suffix (the subnet mask) determines the number of available IP addresses. The formula to calculate the total number of IP addresses in a CIDR block is:
Where is the CIDR prefix.
- Large VPC Block (
/16):
*Example:* `10.1.0.0/16` provides $65,536$ unique IP addresses, allowing you to run thousands of application components.
- Small Subnet Block (
/24):
*Example:* `10.1.0.0/24` provides $256$ unique IP addresses.
Note: AWS reserves IP addresses within every subnet for internal networking purposes (such as the VPC router, DNS, and broadcast). Therefore, the actual usable IPs in a
/24subnet is .
3. The Multi-Layered Security Architecture: NACLs vs. Security Groups
AWS implements security in depth by placing firewalls at different layers of your virtual network.
Real-Life Analogy: The Secure Gated Community
Think of your VPC as a highly secure gated community:
- The Subnet (NACL): This is the main security gate at the entrance of the neighborhood. The guards check every incoming vehicle against a strict list of allowed and banned visitors. If you are on the blacklist, you are turned away at the gate before you can even see a house.
- The Instance (Security Group): This is the digital lock on an individual house's front door. Even if a visitor successfully passes through the neighborhood gate, they cannot enter a specific house unless they have the explicit key or permission for that specific door.
Traffic Flow Architecture
When an external user attempts to access an application running on an EC2 instance, the request must traverse these layers sequentially:
4. Deep Dive: Security Groups (Instance-Level Protection)
A Security Group acts as a virtual firewall for your EC2 instances to control inbound and outbound traffic.
Core Characteristics of Security Groups
- Applied at the Instance Level: You associate security groups with individual Elastic Network Interfaces (ENIs) of EC2 instances, not the subnet itself.
- Permit-Only Rules: You can only specify Allow rules. You cannot explicitly write a rule to "Deny" a specific IP address or port. If traffic is not explicitly allowed by a rule, it is implicitly denied.
- Stateful Evaluation: Security groups are stateful. If you send an inbound request to an EC2 instance, the return traffic is automatically allowed to flow back out, regardless of any outbound rules. Conversely, if the instance initiates an outbound request, the response is allowed back in automatically.
- Default Behavior:
- Inbound: By default, all incoming traffic is blocked.
- Outbound: By default, all outgoing traffic is allowed (with one notable exception).
The Port 25 Outbound Restriction
AWS blocks outbound traffic on Port 25 (SMTP) by default across all EC2 instances. This is a proactive security measure to prevent compromised instances from being used as spam-mailing engines, which would degrade the reputation of AWS IP address ranges. To send outbound mail on Port 25, you must submit a formal request to AWS Support to lift the restriction.
5. Deep Dive: Network Access Control Lists (Subnet-Level Protection)
A Network ACL (NACL) is an optional layer of security for your VPC that acts as a firewall for controlling traffic in and out of one or more subnets.
Core Characteristics of NACLs
- Applied at the Subnet Level: Any rule configured in a NACL automatically applies to all instances residing within that subnet. This makes NACLs highly effective for broad, automated security policies.
- Allow and Deny Rules: Unlike Security Groups, NACLs support both explicit Allow and explicit Deny rules. This allows you to block specific malicious IP addresses or ranges (e.g., blacklisting a known attacker's IP).
- Stateless Evaluation: NACLs are stateless. This means that inbound and outbound traffic must be explicitly allowed independently. If you allow inbound traffic on Port 80, you must also configure an outbound rule to allow the ephemeral response ports back to the client.
- Rule Priority (Sequential Evaluation): NACL rules are processed in numerical order, starting with the lowest rule number. As soon as a rule matches the traffic profile, it is applied, and evaluation stops.
NACL Rule Processing Mechanics
Consider the following inbound NACL configuration:
- Scenario: A request from IP
192.168.1.50arrives on Port 8000. - Evaluation: AWS checks Rule 100 first. Since Rule 100 allows all IPs on Port 8000, the request is immediately allowed. Rule 110 is never evaluated, and the malicious request reaches the subnet.
- Correction: To block
192.168.1.50while allowing everyone else, the Deny rule must have a lower rule number than the Allow rule (e.g., Rule 50 Deny, Rule 100 Allow).
6. Tabular Comparison: Security Groups vs. NACLs
7. Step-by-Step Practical Setup: Creating a Custom VPC
To understand how these layers interact, we will build a custom VPC, deploy an EC2 instance, run a Python web server, and manipulate both Security Groups and NACLs to observe traffic behavior.
Step 1: Navigate to the VPC Dashboard
- Log in to your AWS Management Console.
- In the search bar, type VPC and select the VPC service.
- Click the Create VPC button.
Step 2: Configure VPC Settings using "VPC and More"
AWS provides a wizard called VPC and more that automatically provisions subnets, route tables, and gateways.
- Resources to create: Select VPC and more.
- Name tag auto-generation: Enter
demo-vpc. - IPv4 CIDR block: Keep the default
10.0.0.0/16(allocating IP addresses). - Number of Availability Zones (AZs): Select
1(for demo purposes, to minimize resource usage). - Number of Public Subnets: Select
1. - Number of Private Subnets: Select
1. - VPC Endpoints: Select None (to avoid unnecessary S3 Gateway endpoint charges during this lab).
Click Create VPC. AWS will provision the VPC, subnets, route tables, and attach an Internet Gateway (IGW) automatically.
8. Deploying the Application: Launching EC2 and Running Python HTTP Server
Now, we will deploy an EC2 instance inside our newly created public subnet.
Step 1: Launch the EC2 Instance
- Navigate to the EC2 Dashboard and click Launch Instance.
- Name:
demo-instance. - OS Image: Select Ubuntu (Latest LTS).
- Instance Type:
t2.micro(Free Tier eligible). - Key Pair: Select an existing
.pemkey pair or create a new one (e.g.,AWS-login). - Network Settings (Click Edit):
- VPC: Select your custom
demo-vpc. - Subnet: Select the Public Subnet (e.g.,
demo-subnet-public1-us-east-1a). - Auto-assign public IP: Select Enable (critical for accessing the instance over the internet).
- Firewall (Security Groups): Select Create security group.
- Security Group Name:
demo-sg. - Inbound Rules: By default, AWS adds an SSH rule (Port 22) from
0.0.0.0/0. Leave this as is.
- Security Group Name:
- VPC: Select your custom
- Click Launch Instance.
Step 2: Connect to the Instance and Start the Application
Once the instance state is "Running", copy its Public IP address. Open your terminal and run:
# Connect to the EC2 instance via SSH
ssh -i "AWS-login.pem" ubuntu@<YOUR_EC2_PUBLIC_IP>
# Update the local package index
sudo apt update -y
# Verify Python 3 is installed
python3 --version
Now, start a lightweight, built-in Python HTTP server on port 8000:
# Start the Python HTTP server
python3 -m http.server 8000
The terminal will display:
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
9. Testing the Flow: Debugging Security Group Rules
With the Python server running on Port 8000, let's attempt to access it from a web browser.
Test 1: Initial Connection Attempt
Open your browser and navigate to:
http://<YOUR_EC2_PUBLIC_IP>:8000
- Result: The page hangs and eventually times out with a "Connection Timed Out" error.
- Why? The Security Group (
demo-sg) only has an inbound rule allowing Port 22 (SSH). It is implicitly denying all traffic on Port 8000.
Test 2: Allow Port 8000 in the Security Group
- Go to the EC2 Instance Details page.
- Click on the Security tab and select your security group
demo-sg. - Click Edit inbound rules.
- Click Add rule:
- Type: Custom TCP.
- Port Range:
8000. - Source:
Anywhere-IPv4(0.0.0.0/0).
- Click Save rules.
Refresh your browser. The page will load instantly, displaying a directory listing of your Ubuntu home directory. Your terminal will log a successful 200 OK response:
1.2.3.4 - - [01/Jan/2026 12:00:00] "GET / HTTP/1.1" 200 -
10. Overriding Security Groups: Implementing NACL Deny Rules
Now, let's simulate an organizational security policy where a DevOps engineer must block access to Port 8000 at the network level, overriding any developer-configured Security Group rules.
Step 1: Locate the Subnet's NACL
- Go to the VPC Dashboard.
- Click on Subnets and select your public subnet.
- Click on the Network ACL tab and click the NACL ID (e.g.,
acl-xxxxxx).
Step 2: Add a Deny Rule in the NACL
Currently, the inbound rules allow all traffic:
Let's add a rule to block Port 8000:
- Click Edit inbound rules.
- Click Add new rule:
- Rule Number:
90(Must be lower than 100 to take precedence). - Type: Custom TCP.
- Port Range:
8000. - Source:
0.0.0.0/0. - Allow/Deny: Select DENY.
- Rule Number:
- Click Save changes.
Step 3: Verify the Block
Attempt to access http://<YOUR_EC2_PUBLIC_IP>:8000 in your browser again.
- Result: The connection is immediately blocked, and the browser times out.
- Analysis: Even though the Security Group still explicitly allows Port 8000, the NACL intercepts and drops the packets at the subnet boundary before they can reach the EC2 instance.
11. Understanding NACL Rule Priority (The Order of Evaluation)
To demonstrate how NACL rule ordering works, we will manipulate the rule numbers and observe the changes in traffic flow.
Scenario A: Deny Rule Evaluated First (Traffic Blocked)
We configure the rules as follows:
- Rule 90: Deny Port 8000.
- Rule 100: Allow All Traffic.
Evaluation Flow:
Scenario B: Allow Rule Evaluated First (Traffic Allowed)
Let's change the priority order so the Allow rule is evaluated first:
- Go to Edit inbound rules in your NACL.
- Change the Rule Number of the Deny rule from
90to110. - Keep the Allow rule (
Rule 100: Allow All Traffic) as is. - Click Save changes.
The rules are now ordered as:
- Rule 100: Allow All Traffic.
- Rule 110: Deny Port 8000.
Evaluation Flow:
Refresh your browser. The application is accessible again. This demonstrates that the lowest rule number always takes precedence, and once a matching rule is found, AWS stops evaluating subsequent rules.
12. Summary and Key Takeaways
- Shared Responsibility: AWS provides the security infrastructure (VPCs, firewalls, routing capabilities), but configuring SGs and NACLs to enforce least privilege is the responsibility of the DevOps/Cloud Engineer.
- Two-Tiered Defense: Security Groups act as stateful firewalls at the instance level, while NACLs act as stateless firewalls at the subnet level.
- Stateful vs. Stateless: Security Groups automatically handle return traffic (stateful). NACLs require explicit rules for both inbound and outbound directions (stateless).
- NACL Priority Ordering: NACL rules are processed sequentially in ascending numerical order. The first rule that matches the traffic profile is applied, and all subsequent rules are ignored.
- Allow vs. Deny: Security Groups only support "Allow" rules. NACLs support both "Allow" and "Deny" rules, making them ideal for blocking specific malicious IP addresses or ranges.
- Automation at Scale: Applying a NACL rule to a subnet secures all instances within that subnet instantly, eliminating the need to manually update individual Security Groups across hundreds of instances.