Non-default network ACL is associated with a subnet
VPC network ACLs that are not associated with any subnet are considered unused. The evaluation focuses on non-default ACLs and identifies those without a current subnet association; the default network ACL is excluded.
Risk
Unused ACLs raise the risk of misassociation, unexpectedly changing subnet filtering. A permissive ACL could expose workloads (confidentiality, integrity), while an overly restrictive one could disrupt traffic (availability). Stale objects also hinder reviews and conceal drift.
Run this check with Prowler
Run in Prowler Cloudprowler aws --checks ec2_networkacl_unusedRecommendation
Remove unused non-default ACLs to minimize drift. Apply least privilege and change control to ACL creation and associations. If retention is necessary, tag owner and purpose, restrict who can associate ACLs, and review regularly as part of defense in depth.
Remediation
CLI
aws ec2 delete-network-acl --network-acl-id <nacl_id>Terraform
# Associate the unused non-default NACL to a subnet so it's in use
resource "aws_network_acl_association" "<example_resource_name>" {
subnet_id = "<example_resource_id>" # Critical: makes the subnet use this NACL
network_acl_id = "<example_resource_id>" # Critical: the unused non-default NACL to associate
}NativeIaC
# Associate the unused non-default NACL to a subnet so it's in use
Resources:
<example_resource_name>:
Type: AWS::EC2::SubnetNetworkAclAssociation
Properties:
SubnetId: <example_resource_id> # Critical: makes the subnet use this NACL
NetworkAclId: <example_resource_id> # Critical: the unused non-default NACL to associateOther
Check Code
from prowler.lib.check.models import Check, Check_Report_AWS
from prowler.providers.aws.services.ec2.ec2_client import ec2_client
class ec2_networkacl_unused(Check):
def execute(self):
findings = []
for arn, network_acl in ec2_client.network_acls.items():
if not network_acl.default:
report = Check_Report_AWS(
metadata=self.metadata(), resource=network_acl
)
if not network_acl.in_use:
report.status = "FAIL"
report.status_extended = f"Network ACL {network_acl.name if network_acl.name else network_acl.id} is not associated with any subnet and is not the default network ACL."
else:
report.status = "PASS"
report.status_extended = f"Network ACL {network_acl.name if network_acl.name else network_acl.id} is associated with a subnet."
findings.append(report)
return findings