Skip to main content

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

  1. Open the AWS WAF Console

  2. In the navigation pane, click Switch to AWS WAF Classic

  3. In the region dropdown, select the region where your Web ACL exists (e.g., US East (N. Virginia))

  4. Click on Web ACLs in the navigation pane

  5. Click on the Web ACL name that needs rules added

  6. In the Rules tab, click Edit web ACL

  7. 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)
  8. 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)
  9. Set the Priority for each rule (lower numbers are evaluated first)

  10. 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 requests
  • ALLOW - permit matching requests
  • COUNT - count but don't block (for testing)

Rule types:

  • REGULAR - standard rule
  • RATE_BASED - rate limiting rule
  • GROUP - 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:

  1. Return to the AWS WAF Classic Console
  2. Select the appropriate region
  3. Click Web ACLs
  4. Click on your Web ACL
  5. 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

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-acl via CLI or the Console.