AWS WAF Classic Global Web ACL with Rules
Overview
This check verifies that AWS WAF Classic global 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. 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:GetWebACL",
"waf:UpdateWebACL",
"waf:GetChangeToken",
"waf:ListRules",
"waf:ListRuleGroups",
"waf:ListWebACLs"
],
"Resource": "*"
}
]
}
AWS Console Method
-
Open the AWS WAF Console
-
In the navigation pane, click Switch to AWS WAF Classic
-
In the filter dropdown, select Global (CloudFront) to view global Web ACLs
-
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 list-web-acls
Note the WebACLId of the Web ACL you need to update.
Step 2: List available rules
aws waf list-rules
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 get-change-token
Save the returned ChangeToken value.
Step 4: Add the rule to your Web ACL
aws waf 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"
}
}
]'
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 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 Global Web ACL with SQL Injection Rule
Resources:
SqlInjectionMatchSet:
Type: AWS::WAF::SqlInjectionMatchSet
Properties:
Name: SQLiMatchSet
SqlInjectionMatchTuples:
- FieldToMatch:
Type: QUERY_STRING
TextTransformation: URL_DECODE
- FieldToMatch:
Type: BODY
TextTransformation: URL_DECODE
SqlInjectionRule:
Type: AWS::WAF::Rule
Properties:
Name: SQLiRule
MetricName: SQLiRule
Predicates:
- DataId: !Ref SqlInjectionMatchSet
Negated: false
Type: SqlInjectionMatch
WebACL:
Type: AWS::WAF::WebACL
Properties:
Name: GlobalWebACL
DefaultAction:
Type: BLOCK
MetricName: GlobalWebACLMetric
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-webacl.yaml \
--stack-name waf-classic-webacl \
--region us-east-1
Note: WAF Classic global resources must be created in us-east-1 for CloudFront associations.
Terraform (optional)
Here's a Terraform configuration for an AWS WAF Classic global Web ACL with rules:
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "us-east-1" # WAF Classic global resources require us-east-1
}
# SQL Injection Match Set
resource "aws_waf_sql_injection_match_set" "sql_injection" {
name = "sql-injection-match-set"
sql_injection_match_tuples {
field_to_match {
type = "QUERY_STRING"
}
text_transformation = "URL_DECODE"
}
sql_injection_match_tuples {
field_to_match {
type = "BODY"
}
text_transformation = "URL_DECODE"
}
}
# WAF Rule
resource "aws_waf_rule" "sql_injection_rule" {
name = "sql-injection-rule"
metric_name = "SqlInjectionRule"
predicates {
data_id = aws_waf_sql_injection_match_set.sql_injection.id
negated = false
type = "SqlInjectionMatch"
}
}
# Web ACL with the rule
resource "aws_waf_web_acl" "main" {
name = "global-web-acl"
metric_name = "GlobalWebACL"
default_action {
type = "BLOCK"
}
rules {
action {
type = "BLOCK"
}
priority = 1
rule_id = aws_waf_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_waf_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 Global (CloudFront) filter
- 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 get-web-acl --web-acl-id <YOUR_WEB_ACL_ID>
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 recommended: AWS WAF Classic is a legacy service. Consider migrating to AWS WAFv2 for enhanced features, simplified management, and better pricing.
-
Global scope: This check applies to global (CloudFront) Web ACLs only. Regional Web ACLs for ALB, API Gateway, or other resources are covered by
waf_regional_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.