AWS WAF Classic Regional Web ACL with Rules
Overview
This check verifies that AWS WAF Classic regional Web ACLs contain at least one rule or rule group. A Web ACL (Web Access Control List) is the core component of AWS WAF that controls which web requests are allowed or blocked.
When a Web ACL has no rules, it relies solely on its default action (allow or block all traffic), providing no meaningful inspection or filtering of HTTP/HTTPS requests.
Note: AWS WAF Classic is the legacy version of AWS WAF. AWS recommends using the newer AWS WAFv2, which offers improved features and a unified API. AWS WAF Classic support will end on September 30, 2025. Consider migrating to WAFv2 as part of your remediation.
Risk
An empty Web ACL creates significant security gaps:
- SQL injection attacks can compromise your database and expose sensitive data
- Cross-site scripting (XSS) can steal user credentials or inject malicious content
- Bot traffic and web scraping can drain resources and impact availability
- Malicious requests may alter system state and data integrity
If the default action is "Allow," all traffic passes through without inspection. If it's "Block," legitimate users may be denied access. Neither scenario provides appropriate security controls.
Remediation Steps
Prerequisites
You need:
- AWS Console access with permissions to modify WAF resources
- An existing rule or rule group to add to your Web ACL (or the ability to create one)
Required IAM permissions
Your IAM user or role needs these permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"waf-regional:GetWebACL",
"waf-regional:UpdateWebACL",
"waf-regional:GetChangeToken",
"waf-regional:ListRules",
"waf-regional:ListRuleGroups",
"waf-regional:ListWebACLs"
],
"Resource": "*"
}
]
}
AWS Console Method
-
Open the AWS WAF Console
-
In the navigation pane, click Switch to AWS WAF Classic
-
In the region dropdown, select the region where your Web ACL exists (e.g., US East (N. Virginia))
-
Click on Web ACLs in the navigation pane
-
Click on the Web ACL name that needs rules added
-
In the Rules tab, click Edit web ACL
-
Under Rules, click Add rules and choose one of:
- Add my own rules and rule groups - to add existing rules you've created
- Add managed rule groups - to add AWS Managed Rules (recommended for quick protection)
-
Select the rules or rule groups you want to add and set the Action for each:
- Block - reject matching requests
- Allow - permit matching requests
- Count - track matching requests without blocking (useful for testing)
-
Set the Priority for each rule (lower numbers are evaluated first)
-
Click Save
AWS CLI (optional)
Step 1: List your Web ACLs
aws waf-regional list-web-acls --region us-east-1
Note the WebACLId of the Web ACL you need to update.
Step 2: List available rules
aws waf-regional list-rules --region us-east-1
Note the RuleId of the rule you want to add. If you need to create a rule first, see the AWS documentation on creating rules.
Step 3: Get a change token
AWS WAF Classic requires a change token for modifications:
aws waf-regional get-change-token --region us-east-1
Save the returned ChangeToken value.
Step 4: Add the rule to your Web ACL
aws waf-regional update-web-acl \
--web-acl-id <YOUR_WEB_ACL_ID> \
--change-token <YOUR_CHANGE_TOKEN> \
--updates '[
{
"Action": "INSERT",
"ActivatedRule": {
"Priority": 1,
"RuleId": "<YOUR_RULE_ID>",
"Action": {
"Type": "BLOCK"
},
"Type": "REGULAR"
}
}
]' \
--region us-east-1
Replace the placeholders:
<YOUR_WEB_ACL_ID>- the Web ACL ID from Step 1<YOUR_CHANGE_TOKEN>- the token from Step 3<YOUR_RULE_ID>- the rule ID from Step 2
Action types:
BLOCK- reject matching requestsALLOW- permit matching requestsCOUNT- count but don't block (for testing)
Rule types:
REGULAR- standard ruleRATE_BASED- rate limiting ruleGROUP- rule group
CloudFormation (optional)
AWS WAF Classic Regional resources can be managed via CloudFormation. Here's an example that creates a Web ACL with a SQL injection protection rule:
AWSTemplateFormatVersion: '2010-09-09'
Description: AWS WAF Classic Regional Web ACL with SQL Injection Rule
Resources:
SqlInjectionMatchSet:
Type: AWS::WAFRegional::SqlInjectionMatchSet
Properties:
Name: SQLiMatchSet
SqlInjectionMatchTuples:
- FieldToMatch:
Type: QUERY_STRING
TextTransformation: URL_DECODE
- FieldToMatch:
Type: BODY
TextTransformation: URL_DECODE
SqlInjectionRule:
Type: AWS::WAFRegional::Rule
Properties:
Name: SQLiRule
MetricName: SQLiRule
Predicates:
- DataId: !Ref SqlInjectionMatchSet
Negated: false
Type: SqlInjectionMatch
WebACL:
Type: AWS::WAFRegional::WebACL
Properties:
Name: RegionalWebACL
DefaultAction:
Type: BLOCK
MetricName: RegionalWebACLMetric
Rules:
- Action:
Type: BLOCK
Priority: 1
RuleId: !Ref SqlInjectionRule
Outputs:
WebACLId:
Description: The ID of the Web ACL
Value: !Ref WebACL
Deploy the template:
aws cloudformation deploy \
--template-file waf-regional-webacl.yaml \
--stack-name waf-classic-regional-webacl \
--region us-east-1
Terraform (optional)
Here's a Terraform configuration for an AWS WAF Classic regional Web ACL with rules:
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "us-east-1"
}
# SQL Injection Match Set
resource "aws_wafregional_sql_injection_match_set" "sql_injection" {
name = "sql-injection-match-set"
sql_injection_match_tuple {
field_to_match {
type = "QUERY_STRING"
}
text_transformation = "URL_DECODE"
}
sql_injection_match_tuple {
field_to_match {
type = "BODY"
}
text_transformation = "URL_DECODE"
}
}
# WAF Rule
resource "aws_wafregional_rule" "sql_injection_rule" {
name = "sql-injection-rule"
metric_name = "SqlInjectionRule"
predicate {
data_id = aws_wafregional_sql_injection_match_set.sql_injection.id
negated = false
type = "SqlInjectionMatch"
}
}
# Web ACL with the rule
resource "aws_wafregional_web_acl" "main" {
name = "regional-web-acl"
metric_name = "RegionalWebACL"
default_action {
type = "BLOCK"
}
rule {
action {
type = "BLOCK"
}
priority = 1
rule_id = aws_wafregional_rule.sql_injection_rule.id
type = "REGULAR"
}
tags = {
Environment = "production"
ManagedBy = "terraform"
}
}
output "web_acl_id" {
description = "The ID of the Web ACL"
value = aws_wafregional_web_acl.main.id
}
Apply the configuration:
terraform init
terraform plan
terraform apply
Verification
After adding rules to your Web ACL, verify the changes:
- Return to the AWS WAF Classic Console
- Select the appropriate region
- Click Web ACLs
- Click on your Web ACL
- Confirm the Rules tab shows at least one rule or rule group
CLI verification
# Get the Web ACL details
aws waf-regional get-web-acl \
--web-acl-id <YOUR_WEB_ACL_ID> \
--region us-east-1
The response should include a Rules array with at least one entry:
{
"WebACL": {
"WebACLId": "example-id",
"Name": "MyWebACL",
"Rules": [
{
"Priority": 1,
"RuleId": "rule-id-here",
"Action": {
"Type": "BLOCK"
},
"Type": "REGULAR"
}
],
"DefaultAction": {
"Type": "BLOCK"
}
}
}
Additional Resources
- AWS WAF Classic Developer Guide
- Creating and Configuring a Web ACL
- AWS WAF Classic Rules
- Migrating from AWS WAF Classic to AWS WAFv2
- AWS Managed Rules for AWS WAF
Notes
-
Migration strongly recommended: AWS WAF Classic support ends September 30, 2025. Plan your migration to AWS WAFv2 for enhanced features, simplified management, and better pricing.
-
Regional scope: This check applies to regional Web ACLs that protect Application Load Balancers (ALBs) and API Gateway APIs. For global Web ACLs used with CloudFront, see
waf_global_webacl_with_rules. -
Rule evaluation order: Rules are evaluated by priority (lowest number first). When a rule matches, its action is taken immediately, and remaining rules are not evaluated.
-
Testing with Count: Before setting rules to Block, consider using the Count action first. This lets you monitor what would be blocked without affecting traffic, helping you avoid blocking legitimate users.
-
Logging: Enable WAF logging to monitor rule matches and troubleshoot issues. Logs can be sent to CloudWatch Logs, S3, or Kinesis Data Firehose.
-
Association required: After creating a Web ACL, you must associate it with an ALB or API Gateway for it to take effect. Use
associate-web-aclvia CLI or the Console.