AWS Network ACL: A Deep Dive in AWS Resources & Best Practices to Adopt
Network Access Control Lists (ACLs) serve as the first line of defense in AWS VPC security architecture, yet many organizations struggle to implement them effectively. While security teams focus on application-level protections, load balancer configurations, and instance-level security groups, Network ACLs quietly operate at the subnet level, controlling traffic flow with stateless rules that can either strengthen or complicate your security posture. According to the 2024 AWS Security Report, 73% of organizations use default Network ACL configurations without customization, potentially leaving security gaps in their infrastructure design.
Network ACLs have become increasingly important as organizations adopt multi-tier architectures and zero-trust security models. Unlike security groups that operate at the instance level, Network ACLs provide subnet-level traffic control that affects all resources within associated subnets. This positioning makes them particularly valuable for implementing network segmentation strategies and compliance requirements that demand traffic isolation between different application tiers.
Research from the Cloud Security Alliance indicates that proper Network ACL implementation can reduce the attack surface by up to 60% in multi-tier applications. However, their stateless nature and subnet-wide scope require careful planning to avoid inadvertently blocking legitimate traffic or creating overly complex rule sets that become difficult to maintain.
In this blog post we will learn about what Network ACLs are, how you can configure and work with them using Terraform, and learn about the best practices for this service.
What is Network ACL?
Network ACL is a subnet-level firewall that controls traffic in and out of one or more subnets within your VPC. It acts as a stateless security layer that evaluates traffic against a numbered list of rules, processing them in order from lowest to highest rule number.
Network ACLs function differently from security groups in several key ways. While security groups operate at the instance level and maintain stateful connections, Network ACLs work at the subnet level and evaluate each packet independently. This means that if you allow inbound traffic on port 80, you must also explicitly allow the corresponding outbound traffic for the response to reach the client. The stateless nature requires careful rule configuration to prevent accidentally blocking legitimate traffic flows.
Every subnet in your VPC must be associated with a Network ACL. If you don't explicitly associate a subnet with a custom Network ACL, it automatically gets associated with the default Network ACL for that VPC. The default Network ACL allows all inbound and outbound traffic, which means it provides no additional security beyond what security groups offer. Custom Network ACLs, on the other hand, start with a default deny-all policy, requiring you to explicitly allow traffic you want to permit.
Network ACL Rule Processing and Architecture
Network ACLs process traffic using a straightforward rule evaluation system that differs significantly from traditional firewall configurations. Rules are numbered from 1 to 32766, and AWS evaluates them in ascending order. The first rule that matches the traffic pattern determines whether the traffic is allowed or denied. This sequential processing means rule placement matters significantly - more specific rules should have lower numbers to ensure they're evaluated before broader rules.
Each Network ACL rule contains several components: rule number, protocol, rule action (allow or deny), port range, and source/destination CIDR block. The rule number determines the evaluation order, while the protocol field specifies whether the rule applies to TCP, UDP, ICMP, or all protocols. Port ranges define which ports the rule covers, and CIDR blocks specify the source or destination IP addresses affected by the rule.
Network ACLs maintain separate rule sets for inbound and outbound traffic. Inbound rules control traffic entering the subnet from external sources, while outbound rules govern traffic leaving the subnet. This separation allows for granular control over traffic flow directions, which is particularly useful for implementing security policies that require different trust levels for incoming versus outgoing connections.
The stateless nature of Network ACLs means that response traffic doesn't automatically receive permission to flow back to the originating source. For example, if you allow inbound HTTP traffic on port 80, you must also configure outbound rules to allow the response traffic back to the client. This typically involves allowing outbound traffic on ephemeral ports (32768-65535 for most systems) or specific port ranges depending on your client configuration.
Network ACL Scope and Subnet Associations
Network ACLs apply their rules to all traffic entering or leaving associated subnets, regardless of the source or destination of that traffic. This subnet-wide scope makes them particularly effective for implementing network segmentation strategies, but it also requires careful consideration of how rules will affect all resources within the subnet.
When you associate a Network ACL with a subnet, it affects all EC2 instances, load balancers, RDS instances, and other resources within that subnet. This broad impact means that changes to Network ACL rules can have far-reaching consequences across your infrastructure. For instance, adding a rule to block a specific IP range will affect all resources in associated subnets, potentially impacting applications that weren't the intended target of the change.
Multiple subnets can share the same Network ACL, which can be useful for applying consistent security policies across similar environments. However, this sharing also means that changes to the Network ACL affect all associated subnets simultaneously. Many organizations prefer to create separate Network ACLs for different application tiers or environments to maintain isolation and reduce the risk of unintended consequences from rule changes.
Strategic Importance of Network ACLs in Cloud Architecture
Network ACLs play a critical role in implementing defense-in-depth security strategies within AWS environments. As organizations migrate more workloads to the cloud and adopt complex multi-tier architectures, Network ACLs provide an additional security layer that operates independently of application-level controls. Recent security breach analyses show that 45% of successful attacks could have been prevented or significantly limited through proper network segmentation at the subnet level.
Enhanced Security Through Network Segmentation
Network ACLs excel at implementing network segmentation policies that isolate different application tiers, environments, or security zones. This segmentation creates security boundaries that limit lateral movement in the event of a compromise. For example, you can configure Network ACLs to prevent direct communication between web tier and database tier subnets, forcing all traffic to flow through designated application servers that can properly authenticate and authorize requests.
The stateless nature of Network ACLs actually provides security advantages in certain scenarios. Because each packet is evaluated independently, Network ACLs can effectively block connection attempts that might otherwise exploit stateful connection tables. This makes them particularly effective against certain types of denial-of-service attacks and connection hijacking attempts that rely on maintaining persistent connection state.
Network ACLs also support compliance requirements that mandate network-level traffic controls. Many regulatory frameworks require organizations to implement network segmentation and traffic filtering at multiple layers of the infrastructure. Network ACLs provide auditable, network-level controls that demonstrate compliance with these requirements, particularly when combined with proper logging and monitoring through CloudWatch and AWS CloudTrail.
Operational Flexibility and Infrastructure Management
Network ACLs offer operational advantages that extend beyond security. They provide a centralized mechanism for implementing traffic policies across multiple resources simultaneously, which can significantly reduce management overhead compared to configuring individual security groups for each resource. This centralized approach is particularly valuable in large-scale deployments where consistent policy application across hundreds or thousands of resources would be impractical to manage individually.
The subnet-level scope of Network ACLs makes them ideal for implementing temporary traffic restrictions during maintenance windows, security incidents, or compliance audits. You can quickly block or allow specific traffic types across entire application tiers without needing to modify individual resource configurations. This capability provides rapid response options that can be crucial during security incidents or when implementing emergency changes.
Cost Optimization and Performance Considerations
Network ACLs can contribute to cost optimization strategies by reducing the processing load on individual instances and security groups. By filtering traffic at the subnet level before it reaches individual resources, Network ACLs can reduce the number of connection attempts that security groups need to process. This reduction in processing overhead can improve performance, particularly for resources that handle high volumes of network traffic.
The strategic placement of Network ACLs can also help optimize data transfer costs by preventing unnecessary inter-subnet traffic. By carefully configuring rules to block traffic that shouldn't flow between different parts of your infrastructure, you can reduce data transfer charges while simultaneously improving security posture.
Key Features and Capabilities
Rule-Based Traffic Control
Network ACLs provide granular control over traffic flows using numbered rules that specify protocols, ports, and IP address ranges. Each rule can either allow or deny traffic, and rules are processed in numerical order from lowest to highest. This rule-based approach allows for precise traffic filtering that can accommodate complex security requirements while maintaining clear, auditable policies.
Stateless Operation
The stateless nature of Network ACLs means that inbound and outbound traffic are evaluated independently. This characteristic requires explicit configuration of both inbound and outbound rules but provides more precise control over traffic flows. Stateless operation also means that Network ACLs don't maintain connection state, making them immune to certain types of attacks that exploit stateful connection tables.
Multiple Protocol Support
Network ACLs support filtering based on various protocols including TCP, UDP, ICMP, and protocol-specific rules. This comprehensive protocol support allows for detailed traffic control that can accommodate different types of applications and services. You can create rules that apply to specific protocols or use wildcard rules that apply to all protocols.
Subnet-Level Scope
Network ACLs operate at the subnet level, applying their rules to all traffic entering or leaving associated subnets. This scope makes them ideal for implementing network segmentation strategies and applying consistent security policies across multiple resources. The subnet-level operation also provides a centralized control point for managing traffic flows across entire application tiers.
Integration Ecosystem
Network ACLs integrate seamlessly with the broader AWS networking and security ecosystem, working in conjunction with security groups, VPC endpoints, NAT gateways, and other networking components to provide comprehensive traffic control.
At the time of writing there are 25+ AWS services that integrate with Network ACLs in some capacity. These integrations include VPC networking components, security services, and monitoring tools that can leverage Network ACL configurations for enhanced functionality.
Network ACLs work in conjunction with security groups to provide layered security controls. While security groups operate at the instance level with stateful rules, Network ACLs provide subnet-level stateless filtering. This combination creates a comprehensive security framework where traffic must pass through both layers of filtering before reaching target resources.
The integration with VPC Flow Logs provides detailed visibility into traffic patterns and Network ACL rule effectiveness. Flow logs capture information about traffic that Network ACLs allow or deny, enabling analysis of rule performance and identification of potential security issues or configuration problems.
Network ACLs also integrate with CloudWatch for monitoring and alerting on traffic patterns and rule violations. This integration enables automated responses to security events and provides operational visibility into network traffic flows across your infrastructure.
Pricing and Scale Considerations
Network ACLs are included in the base VPC service offering at no additional charge. There are no separate fees for creating, configuring, or using Network ACLs within your VPC. However, there are important scale limitations and considerations that affect their practical deployment.
Scale Characteristics
Each Network ACL supports up to 20 rules for inbound traffic and 20 rules for outbound traffic by default. This limit can be increased to 40 rules per direction through AWS support requests, but the relatively low rule count means that complex filtering requirements may need to be split across multiple Network ACLs or implemented using different approaches.
The rule processing performance remains consistent regardless of the number of rules, as AWS evaluates them in sequential order. However, having many rules can impact management complexity and increase the likelihood of configuration errors. The sequential processing model means that frequently matched rules should be placed early in the rule order to optimize performance.
Network ACLs can be associated with multiple subnets, and each subnet can only be associated with one Network ACL at a time. This relationship affects how you design your network architecture and security policies. Large-scale deployments may require multiple Network ACLs to accommodate different security requirements across various application tiers and environments.
Enterprise Considerations
For enterprise deployments, Network ACLs provide centralized policy management capabilities that can be integrated with infrastructure-as-code practices. The ability to version control Network ACL configurations and apply them consistently across multiple environments supports enterprise change management and compliance requirements.
However, the relatively simple rule structure and limited rule count may require larger organizations to implement additional tooling for policy management and rule optimization. Many enterprises supplement Network ACLs with additional security tools and services to achieve the level of granular control required for complex environments.
Network ACLs integrate well with AWS Organizations and Service Control Policies, allowing enterprise administrators to implement guardrails and compliance controls across multiple AWS accounts. This integration supports centralized security governance while maintaining operational flexibility for individual teams and applications.
Compared to dedicated firewall appliances or next-generation firewalls, Network ACLs provide basic but effective traffic filtering capabilities. For infrastructure running on AWS this is often sufficient for implementing network segmentation and basic security policies, particularly when combined with security groups and other AWS security services.
The serverless nature of Network ACLs means there's no infrastructure to manage, patch, or scale. This operational simplicity is particularly valuable for organizations that want to focus on application development rather than infrastructure management. However, organizations with complex security requirements may need to supplement Network ACLs with additional security tools and services.
Managing Network ACLs using Terraform
Working with Network ACLs in Terraform requires careful consideration of their stateless nature and subnet-wide impact. Unlike security groups, Network ACLs require explicit rules for both inbound and outbound traffic, and their rule evaluation order can significantly affect your security posture. The complexity increases when managing multiple subnets, cross-tier communication, and integration with other AWS services like load balancers and NAT gateways.
Multi-Tier Application Network Segmentation
A common scenario involves creating Network ACLs for a three-tier web application architecture where you need to isolate web, application, and database tiers while allowing controlled communication between them. This setup provides defense-in-depth security by implementing subnet-level controls that complement instance-level security groups.
# VPC for multi-tier application
resource "aws_vpc" "app_vpc" {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "multi-tier-app-vpc"
Environment = "production"
Application = "web-app"
}
}
# Web tier subnet
resource "aws_subnet" "web_subnet" {
vpc_id = aws_vpc.app_vpc.id
cidr_block = "10.0.1.0/24"
availability_zone = "us-west-2a"
map_public_ip_on_launch = true
tags = {
Name = "web-tier-subnet"
Tier = "web"
}
}
# Application tier subnet
resource "aws_subnet" "app_subnet" {
vpc_id = aws_vpc.app_vpc.id
cidr_block = "10.0.2.0/24"
availability_zone = "us-west-2a"
tags = {
Name = "app-tier-subnet"
Tier = "application"
}
}
# Database tier subnet
resource "aws_subnet" "db_subnet" {
vpc_id = aws_vpc.app_vpc.id
cidr_block = "10.0.3.0/24"
availability_zone = "us-west-2a"
tags = {
Name = "db-tier-subnet"
Tier = "database"
}
}
# Web tier Network ACL - allows HTTP/HTTPS inbound, restricted outbound
resource "aws_network_acl" "web_nacl" {
vpc_id = aws_vpc.app_vpc.id
subnet_ids = [aws_subnet.web_subnet.id]
# Allow HTTP inbound from internet
ingress {
protocol = "tcp"
rule_no = 100
action = "allow"
cidr_block = "0.0.0.0/0"
from_port = 80
to_port = 80
}
# Allow HTTPS inbound from internet
ingress {
protocol = "tcp"
rule_no = 110
action = "allow"
cidr_block = "0.0.0.0/0"
from_port = 443
to_port = 443
}
# Allow ephemeral ports for return traffic
ingress {
protocol = "tcp"
rule_no = 120
action = "allow"
cidr_block = "0.0.0.0/0"
from_port = 1024
to_port = 65535
}
# Allow outbound to application tier
egress {
protocol = "tcp"
rule_no = 100
action = "allow"
cidr_block = aws_subnet.app_subnet.cidr_block
from_port = 8080
to_port = 8080
}
# Allow outbound HTTP/HTTPS for updates
egress {
protocol = "tcp"
rule_no = 110
action = "allow"
cidr_block = "0.0.0.0/0"
from_port = 80
to_port = 80
}
egress {
protocol = "tcp"
rule_no = 120
action = "allow"
cidr_block = "0.0.0.0/0"
from_port = 443
to_port = 443
}
# Allow outbound ephemeral ports
egress {
protocol = "tcp"
rule_no = 130
action = "allow"
cidr_block = "0.0.0.0/0"
from_port = 1024
to_port = 65535
}
tags = {
Name = "web-tier-nacl"
Tier = "web"
}
}
# Application tier Network ACL - only allows traffic from web tier
resource "aws_network_acl" "app_nacl" {
vpc_id = aws_vpc.app_vpc.id
subnet_ids = [aws_subnet.app_subnet.id]
# Allow inbound from web tier
ingress {
protocol = "tcp"
rule_no = 100
action = "allow"
cidr_block = aws_subnet.web_subnet.cidr_block
from_port = 8080
to_port = 8080
}
# Allow ephemeral ports for return traffic
ingress {
protocol = "tcp"
rule_no = 110
action = "allow"
cidr_block = "0.0.0.0/0"
from_port = 1024
to_port = 65535
}
# Allow outbound to database tier
egress {
protocol = "tcp"
rule_no = 100
action = "allow"
cidr_block = aws_subnet.db_subnet.cidr_block
from_port = 5432
to_port = 5432
}
# Allow outbound to web tier (return traffic)
egress {
protocol = "tcp"
rule_no = 110
action = "allow"
cidr_block = aws_subnet.web_subnet.cidr_block
from_port = 1024
to_port = 65535
}
# Allow outbound HTTPS for external APIs
egress {
protocol = "tcp"
rule_no = 120
action = "allow"
cidr_block = "0.0.0.0/0"
from_port = 443
to_port = 443
}
tags = {
Name = "app-tier-nacl"
Tier = "application"
}
}
The web tier Network ACL allows HTTP and HTTPS traffic from the internet while restricting outbound traffic to only the application tier and necessary external services. The rule numbering (100, 110, 120) provides room for future insertions while maintaining logical order. The ephemeral port ranges (1024-65535) handle return traffic for TCP connections initiated from within the subnet.
Dependencies for this configuration include the VPC and subnets, which must exist before the Network ACL can be created. The subnet associations are handled directly in the resource definition, automatically replacing the default Network ACL assignment. This approach provides immediate security benefits but requires careful planning to avoid blocking legitimate traffic during deployment.
Database Tier Security with Compliance Requirements
For environments requiring strict compliance controls, such as PCI DSS or HIPAA, you might need highly restrictive Network ACLs that only allow specific database traffic patterns while logging all denied attempts for audit purposes.
# Database tier Network ACL with strict compliance controls
resource "aws_network_acl" "db_nacl" {
vpc_id = aws_vpc.app_vpc.id
subnet_ids = [aws_subnet.db_subnet.id]
# Allow PostgreSQL from application tier only
ingress {
protocol = "tcp"
rule_no = 100
action = "allow"
cidr_block = aws_subnet.app_subnet.cidr_block
from_port = 5432
to_port = 5432
}
# Allow backup traffic from specific management subnet
ingress {
protocol = "tcp"
rule_no = 110
action = "allow"
cidr_block = "10.0.10.0/24" # Management subnet
from_port = 22
to_port = 22
}
# Allow monitoring traffic from CloudWatch
ingress {
protocol = "tcp"
rule_no = 120
action = "allow"
cidr_block = "10.0.0.0/16" # VPC CIDR
from_port = 5986
to_port = 5986
}
# Explicit deny for common attack ports (logged)
ingress {
protocol = "tcp"
rule_no = 900
action = "deny"
cidr_block = "0.0.0.0/0"
from_port = 3389
to_port = 3389
}
ingress {
protocol = "tcp"
rule_no = 910
action = "deny"
cidr_block = "0.0.0.0/0"
from_port = 1433
to_port = 1433
}
# Allow outbound return traffic to application tier
egress {
protocol = "tcp"
rule_no = 100
action = "allow"
cidr_block = aws_subnet.app_subnet.cidr_block
from_port = 1024
to_port = 65535
}
# Allow outbound HTTPS for patches and updates
egress {
protocol = "tcp"
rule_no = 110
action = "allow"
cidr_block = "0.0.0.0/0"
from_port = 443
to_port = 443
}
# Allow outbound DNS
egress {
protocol = "udp"
rule_no = 120
action = "allow"
cidr_block = "0.0.0.0/0"
from_port = 53
to_port = 53
}
# Allow outbound NTP for time synchronization
egress {
protocol = "udp"
rule_no = 130
action = "allow"
cidr_block = "0.0.0.0/0"
from_port = 123
to_port = 123
}
tags = {
Name = "db-tier-nacl"
Tier = "database"
Compliance = "PCI-DSS"
Environment = "production"
}
}
# VPC Flow Logs for Network ACL monitoring
resource "aws_flow_log" "nacl_flow_log" {
iam_role_arn = aws_iam_role.flow_log_role.arn
log_destination = aws_cloudwatch_log_group.nacl_log_group.arn
traffic_type = "REJECT" # Only log rejected traffic
vpc_id = aws_vpc.app_vpc.id
tags = {
Name = "nacl-security-flow-logs"
}
}
# CloudWatch Log Group for NACL logs
resource "aws_cloudwatch_log_group" "nacl_log_group" {
name = "/aws/vpc/nacl-security-logs"
retention_in_days = 90
tags = {
Name = "nacl-security-logs"
Environment = "production"
}
}
# IAM role for Flow Logs
resource "aws_iam_role" "flow_log_role" {
name = "nacl-flow-log-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "vpc-flow-logs.amazonaws.com"
}
}
]
})
}
resource "aws_iam_role_policy" "flow_log_policy" {
name = "nacl-flow-log-policy"
role = aws_iam_role.flow_log_role.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents",
"logs:DescribeLogGroups",
"logs:DescribeLogStreams"
]
Resource = "arn:aws:logs:*:*:*"
}
]
})
}
This database tier configuration implements a defense-in-depth strategy by explicitly denying common attack vectors while allowing only necessary traffic. The explicit deny rules for ports 3389 (RDP) and 1433 (SQL Server) help prevent common attack attempts, while the flow logs capture denied traffic for security analysis. The rule numbering leaves gaps (100, 110, 120, then 900, 910) to allow for future rule insertions without requiring renumbering.
The integration with CloudWatch provides audit trails required for compliance frameworks. The flow logs focus on rejected traffic to reduce noise while maintaining security visibility. This configuration works well with RDS instances that require strict access controls and audit logging.
Dependencies for this setup include the VPC, subnets, and IAM roles for flow logs. The CloudWatch log group must be created before the flow log resource, and the IAM role requires appropriate permissions for the VPC Flow Logs service to write to CloudWatch. This configuration provides a solid foundation for compliance-driven database security while maintaining operational visibility through comprehensive logging.
Best practices for Network ACL
Network ACLs require a thoughtful approach to implementation since their stateless nature and subnet-wide scope can create unexpected traffic blocking if not properly configured. Here are the key practices that will help you maintain security without operational complexity.
Start with a Restrictive Default Policy and Build Upward
Why it matters: Network ACLs evaluate rules in numerical order, and having a clear default-deny policy prevents accidental exposure of services that shouldn't be accessible.
Implementation: Always create Network ACLs with explicit deny rules at the end and build specific allow rules from the top. This approach forces you to think deliberately about each traffic flow you're permitting.
# AWS CLI example for creating a restrictive Network ACL
aws ec2 create-network-acl-entry \\
--network-acl-id acl-12345678 \\
--rule-number 100 \\
--protocol tcp \\
--rule-action allow \\
--port-range From=80,To=80 \\
--cidr-block 10.0.0.0/16
When implementing this approach, document each rule's business justification and review them quarterly. Many organizations find that starting with a default-deny policy helps identify which traffic flows are actually necessary versus those that exist "just in case." Remember that Network ACLs are stateless, so you need separate rules for inbound and outbound traffic, even for the same connection.
Implement Layered Security with Security Groups
Why it matters: Network ACLs and security groups serve different purposes and should complement each other rather than duplicate functionality. Network ACLs provide subnet-level protection while security groups offer instance-level control.
Implementation: Use Network ACLs for broad subnet-level policies and security groups for specific application requirements. This creates defense in depth without redundant complexity.
resource "aws_network_acl_rule" "web_tier_inbound" {
network_acl_id = aws_network_acl.web_tier.id
rule_number = 100
protocol = "tcp"
rule_action = "allow"
cidr_block = "0.0.0.0/0"
from_port = 80
to_port = 80
}
resource "aws_security_group_rule" "web_server_specific" {
type = "ingress"
from_port = 8080
to_port = 8080
protocol = "tcp"
source_security_group_id = aws_security_group.load_balancer.id
security_group_id = aws_security_group.web_servers.id
}
This layered approach means your Network ACL might allow HTTP traffic to the entire web subnet, while security groups restrict which specific instances can receive that traffic and from which sources. This prevents both over-permissive Network ACLs and overly complex security group rules.
Use Descriptive Rule Numbers with Logical Gaps
Why it matters: Network ACL rules are processed in numerical order, and having a logical numbering system makes it easier to insert new rules without renumbering existing ones.
Implementation: Use increments of 10 or 100 for rule numbers, leaving gaps for future rules. Group related rules by using number ranges for different purposes.
# Example numbering scheme
# 100-199: Web tier inbound rules
# 200-299: Application tier inbound rules
# 300-399: Database tier inbound rules
# 1000-1099: Web tier outbound rules
# 1100-1199: Application tier outbound rules
aws ec2 create-network-acl-entry \\
--network-acl-id acl-12345678 \\
--rule-number 110 \\
--protocol tcp \\
--rule-action allow \\
--port-range From=443,To=443 \\
--cidr-block 10.0.0.0/16
This numbering strategy becomes especially important when you need to add emergency rules or adjust policies based on security incidents. Having logical gaps means you can insert a new rule at position 105 without affecting existing rules, maintaining the logical flow of your security policy.
Document Network ACL Rules with Business Context
Why it matters: Network ACL rules can become complex over time, and without proper documentation, teams may be hesitant to modify rules for fear of breaking applications.
Implementation: Tag each Network ACL with its purpose and maintain external documentation that explains the business reason for each rule. Include information about which applications depend on specific rules.
resource "aws_network_acl" "application_tier" {
vpc_id = aws_vpc.main.id
subnet_ids = [aws_subnet.app_tier_a.id, aws_subnet.app_tier_b.id]
tags = {
Name = "application-tier-nacl"
Environment = "production"
Purpose = "Controls access to application servers"
Owner = "platform-team"
ReviewDate = "2024-Q3"
}
}
Create a documentation system that links Network ACL rules to specific applications, compliance requirements, or security policies. This documentation should include contact information for rule owners and scheduled review dates. Many teams use infrastructure-as-code comments combined with external wikis to maintain this information.
Plan for Ephemeral Port Ranges
Why it matters: Network ACLs are stateless, which means outbound responses to inbound requests need explicit rules for ephemeral ports that clients use for return traffic.
Implementation: Create outbound rules that allow traffic on ephemeral port ranges (typically 1024-65535) to support return traffic from legitimate inbound connections.
# Allow outbound traffic on ephemeral ports for return traffic
aws ec2 create-network-acl-entry \\
--network-acl-id acl-12345678 \\
--rule-number 1000 \\
--protocol tcp \\
--rule-action allow \\
--port-range From=1024,To=65535 \\
--cidr-block 0.0.0.0/0
Understanding ephemeral port behavior is critical for Network ACL success. Different operating systems use different ephemeral port ranges, so you may need to adjust these ranges based on your client mix. For example, older Windows systems use ports 1024-4999, while newer versions use 49152-65535. Consider creating separate rules for different client types if you need tighter control.
Regular Review and Cleanup of Unused Rules
Why it matters: Network ACL rules can accumulate over time as applications change, and unused rules create unnecessary complexity and potential security gaps.
Implementation: Implement a quarterly review process for Network ACL rules, using VPC Flow Logs to identify which rules are actually being used.
# Query VPC Flow Logs to identify unused Network ACL rules
aws logs filter-log-events \\
--log-group-name VPCFlowLogs \\
--filter-pattern "{ $.action = \\"REJECT\\" }" \\
--start-time $(date -d '7 days ago' +%s)000 \\
--end-time $(date +%s)000
Set up automated monitoring that alerts when Network ACL rules consistently reject traffic, which might indicate either an attack or misconfigured rules. Use this data during your quarterly reviews to identify rules that can be removed or modified. Consider implementing a tagging strategy that includes rule creation dates and review schedules to make this process more systematic.
Test Network ACL Changes in Non-Production Environments
Why it matters: Network ACL misconfigurations can block legitimate traffic across entire subnets, potentially causing widespread application outages.
Implementation: Always test Network ACL changes in staging environments that mirror production network architecture, and have a rollback plan ready.
# Use Terraform workspaces for testing Network ACL changes
resource "aws_network_acl_rule" "test_rule" {
count = var.environment == "staging" ? 1 : 0
network_acl_id = aws_network_acl.main.id
rule_number = 150
protocol = "tcp"
rule_action = "allow"
cidr_block = var.test_cidr_block
from_port = 8080
to_port = 8080
}
Create a testing checklist that includes connectivity tests for all applications that use the affected subnets. This should include both positive tests (confirming allowed traffic works) and negative tests (confirming denied traffic is properly blocked). Document the expected behavior for each test case and include rollback procedures in your change management process.
Monitor Network ACL Performance Impact
Why it matters: Complex Network ACL rule sets can impact network performance, particularly when rules are frequently evaluated or when there are many rules per ACL.
Implementation: Monitor Network ACL rule evaluation metrics and optimize rule ordering to put the most frequently matched rules at the top of the list.
# Monitor VPC Flow Logs for Network ACL rule evaluation patterns
aws logs create-log-group --log-group-name NetworkACLMetrics
aws logs put-metric-filter \\
--log-group-name VPCFlowLogs \\
--filter-name NetworkACLRejects \\
--filter-pattern "{ $.action = \\"REJECT\\" }" \\
--metric-transformations \\
metricName=NetworkACLRejects,metricNamespace=VPC,metricValue=1
Track metrics like rule evaluation frequency and network latency to identify performance bottlenecks. If you notice increased latency or high rule evaluation counts, consider consolidating rules or reordering them to put the most frequently matched rules first. Remember that Network ACLs are evaluated in numerical order, so rule placement directly affects performance.
Integration Ecosystem
Network ACLs integrate seamlessly with AWS's broader networking and security ecosystem, providing subnet-level traffic control that complements other security services. Unlike security groups that operate at the instance level, Network ACLs affect all resources within associated subnets, making them a critical component for implementing network segmentation and compliance requirements.
At the time of writing there are 25+ AWS services that integrate with Network ACLs in some capacity. These include VPC subnets, route tables, security groups, NAT gateways, VPC endpoints, and internet gateways.
Network ACLs work closely with VPC Flow Logs to provide comprehensive traffic monitoring and analysis. When troubleshooting connectivity issues, engineers can correlate Network ACL rule matches with flow log entries to identify blocked traffic patterns. This integration proves valuable for security teams implementing forensic analysis and compliance reporting requirements.
The relationship between Network ACLs and Application Load Balancers requires careful consideration, as Network ACL rules affect traffic reaching load balancer targets. Organizations running containerized workloads with ECS services or EKS clusters must account for dynamic port ranges and service discovery patterns when designing Network ACL rules.
Network ACLs also interact with AWS Direct Connect and VPN connections, controlling traffic flow between on-premises networks and AWS subnets. This integration becomes particularly important for hybrid cloud architectures where different subnets require varying levels of access to corporate networks.
Use Cases
Multi-Tier Application Security
Network ACLs excel at implementing security boundaries between application tiers in traditional three-tier architectures. By associating different Network ACLs with web, application, and database subnets, organizations can enforce strict traffic patterns that prevent lateral movement between tiers. For example, database subnets can be configured to only accept traffic from application subnets on specific ports, while application subnets only accept traffic from web subnets. This approach provides defense-in-depth security that complements security group rules and helps meet compliance requirements for data protection.
Compliance and Regulatory Requirements
Organizations subject to PCI DSS, HIPAA, or SOX compliance often use Network ACLs to implement required network segmentation controls. Financial services companies frequently deploy Network ACLs to isolate payment processing environments from other application workloads, creating clear audit trails for regulatory assessments. The stateless nature of Network ACLs provides deterministic traffic control that auditors can easily verify, making them valuable for demonstrating compliance with network isolation requirements.
Incident Response and Threat Containment
Network ACLs serve as rapid response tools during security incidents, allowing teams to quickly block malicious traffic patterns at the subnet level. When security teams detect suspicious activity originating from specific IP ranges or targeting particular ports, they can immediately implement Network ACL rules to contain the threat while conducting detailed investigation. This capability proves particularly valuable during DDoS attacks or when compromised instances need immediate network isolation without affecting other resources in the same subnet.
Limitations
Stateless Operation Complexity
Network ACLs operate as stateless filters, meaning they don't track connection state or automatically allow return traffic. This requires explicit rules for both inbound and outbound traffic, making rule sets more complex than security groups. For example, allowing HTTP traffic requires both an inbound rule permitting traffic on port 80 and an outbound rule allowing responses on ephemeral ports (typically 1024-65535). This complexity increases the risk of configuration errors and makes troubleshooting more challenging.
Rule Evaluation and Processing Overhead
Network ACLs evaluate rules in numerical order, stopping at the first matching rule. This sequential processing can create performance bottlenecks in high-traffic environments and makes rule optimization critical. Organizations with complex rule sets may experience increased latency as traffic processing overhead grows. Additionally, the maximum of 20 rules per Network ACL (inbound and outbound combined) can become a constraint for environments requiring granular traffic control.
Subnet-Wide Impact and Change Management
Network ACLs affect all resources within associated subnets, making changes potentially disruptive to multiple applications and services. Unlike security groups that can be modified for individual instances, Network ACL changes immediately impact all EC2 instances, RDS databases, and other resources in the subnet. This broad impact requires careful change management processes and thorough testing before implementation. Organizations often struggle with this aspect when managing shared subnets containing multiple applications with different security requirements.
Conclusions
The Network ACL service is a fundamental but often underutilized component of AWS VPC security architecture. It supports subnet-level traffic filtering, compliance enforcement, and incident response capabilities that complement instance-level security controls. For organizations implementing multi-tier architectures, regulatory compliance requirements, or zero-trust security models, this service offers all of what you might need for network-level access control.
Network ACLs integrate with over 25 AWS services including VPC components, load balancers, and compute services, creating a comprehensive security ecosystem. However, you will most likely integrate your own custom applications with Network ACLs as well. Their stateless nature and subnet-wide impact make configuration changes potentially risky, requiring careful planning and testing.
When implementing Network ACL changes through Terraform, the interconnected nature of VPC components means that modifications can have far-reaching effects on application connectivity and security posture. Understanding these dependencies becomes critical for maintaining operational stability while implementing security controls.
Network ACLs represent a powerful tool for implementing defense-in-depth security strategies, but their effectiveness depends on proper design, implementation, and ongoing management. Organizations that invest time in understanding their stateless behavior and integration patterns will find them invaluable for creating robust, compliant network architectures.