How AWS WAF Protects Your Application Load Balancer: WebACL Setup with Managed Rule Groups
When SQL injection and cross-site scripting attacks reach your Application Load Balancer, they hit your application tier directly — WAF is the layer that intercepts and blocks them before a single malicious byte reaches your backend. This post walks through attaching an AWS WAF WebACL to an ALB using AWS Managed Rule Groups, covering the architecture, CLI setup, and the operational details that documentation glosses over.
TL;DR: AWS WAF on ALB — Key Facts
| Aspect | Detail |
|---|---|
| WAF scope for ALB | REGIONAL (not CLOUDFRONT) |
| Attachment model | WebACL associated to ALB ARN |
| SQL injection protection | AWSManagedRulesSQLiRuleSet |
| XSS protection | AWSManagedRulesCommonRuleSet (contains XSS rules) |
| Default action | ALLOW (explicit BLOCK rules override) |
| Rule evaluation order | Priority integer — lower number evaluated first |
| Logging destination | CloudWatch Logs, S3, or Kinesis Data Firehose |
How AWS WAF Works with an Application Load Balancer
AWS WAF operates as a regional service that inspects HTTP/HTTPS requests before they are forwarded by the ALB to target groups. The WebACL is the top-level container — it holds rules and rule groups, defines a default action, and gets associated to one or more AWS resources. For ALB, the association is made at the resource level using the ALB's ARN.
Each incoming request is evaluated against rules in priority order. The first matching rule's action (ALLOW, BLOCK, COUNT, CAPTCHA) terminates evaluation. If no rule matches, the WebACL's default action applies. This terminating-match model means rule ordering is not cosmetic — it directly controls which rule wins when multiple rules could match the same request.
AWS Managed Rule Groups are pre-built, AWS-maintained collections of rules. You reference them by name inside your WebACL. AWS updates the rule logic without requiring you to modify your WebACL configuration, though you can pin to a specific static version if you need change control.
- Client Request — HTTP/HTTPS request arrives at the ALB listener.
- WAF Inspection — ALB forwards request metadata to WAF for rule evaluation before routing.
- WebACL Evaluation — Rules are evaluated in priority order. First match terminates evaluation.
- BLOCK path — WAF returns a 403 response directly; request never reaches the target group.
- ALLOW path — Request is forwarded to the target group normally.
- Logging — All evaluated requests (sampled or full) are emitted to the configured log destination.
Step 1: Create the WebACL with REGIONAL Scope
The most common first mistake is creating a WebACL with CLOUDFRONT scope and then trying to attach it to an ALB. WAF enforces a hard boundary — a CLOUDFRONT-scoped WebACL cannot be associated with a regional resource, and the association call will fail with a validation error. ALB requires REGIONAL scope, and the scope is immutable after creation.
aws wafv2 create-web-acl \
--name "alb-protection-webacl" \
--scope REGIONAL \
--region us-east-1 \
--default-action Allow={} \
--visibility-config SampledRequestsEnabled=true,CloudWatchMetricsEnabled=true,MetricName="alb-protection-webacl" \
--rules '[]'
This creates an empty WebACL with a default ALLOW action. The --rules '[]' parameter is required by the CLI even when no rules are defined at creation time. Note the returned Id and LockToken — both are required for subsequent update operations.
Step 2: Add AWS Managed Rule Groups for SQLi and XSS Protection
SQL injection coverage comes from AWSManagedRulesSQLiRuleSet. XSS coverage is included in AWSManagedRulesCommonRuleSet (the Core Rule Set, or CRS), which also covers other OWASP Top 10 categories. Adding both gives you layered protection without writing custom rule logic.
Before updating, retrieve the current LockToken — WAF uses optimistic locking to prevent concurrent modifications from overwriting each other silently.
aws wafv2 get-web-acl \
--name "alb-protection-webacl" \
--scope REGIONAL \
--region us-east-1 \
--id "<your-webacl-id>"
Then update the WebACL with both managed rule groups. Priority 1 is evaluated before priority 2 — place the more specific rule group at the lower priority number if you want it to take precedence.
aws wafv2 update-web-acl \
--name "alb-protection-webacl" \
--scope REGIONAL \
--region us-east-1 \
--id "<your-webacl-id>" \
--lock-token "<current-lock-token>" \
--default-action Allow={} \
--visibility-config SampledRequestsEnabled=true,CloudWatchMetricsEnabled=true,MetricName="alb-protection-webacl" \
--rules '[{"Name":"AWSManagedRulesCommonRuleSet","Priority":1,"Statement":{"ManagedRuleGroupStatement":{"VendorName":"AWS","Name":"AWSManagedRulesCommonRuleSet"}},"OverrideAction":{"None":{}},"VisibilityConfig":{"SampledRequestsEnabled":true,"CloudWatchMetricsEnabled":true,"MetricName":"AWSManagedRulesCommonRuleSet"}},{"Name":"AWSManagedRulesSQLiRuleSet","Priority":2,"Statement":{"ManagedRuleGroupStatement":{"VendorName":"AWS","Name":"AWSManagedRulesSQLiRuleSet"}},"OverrideAction":{"None":{}},"VisibilityConfig":{"SampledRequestsEnabled":true,"CloudWatchMetricsEnabled":true,"MetricName":"AWSManagedRulesSQLiRuleSet"}}]'
The OverrideAction of None means the rule group's own actions (BLOCK, COUNT, etc.) are honored. If you set Count instead, all rules in the group are forced into COUNT mode — useful during initial rollout to observe traffic without blocking.
Think of COUNT mode as a shadow firewall. It evaluates every rule and logs what would have been blocked, but lets traffic through. Run it for 24–48 hours against production traffic before switching to enforcement mode — this is how you catch false positives before they become outages.
Step 3: Associate the WebACL with Your ALB
Association is a separate API call from WebACL creation. The resource ARN must be the full ALB ARN. One WebACL can be associated with multiple ALBs in the same region, but each ALB can only be associated with one WebACL at a time.
aws wafv2 associate-web-acl \
--web-acl-arn "arn:aws:wafv2:us-east-1:123456789012:regional/webacl/alb-protection-webacl/<your-webacl-id>" \
--resource-arn "arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/app/my-alb/<alb-id>" \
--region us-east-1
Verify the association succeeded — the CLI returns no output on success, so an explicit check is necessary:
aws wafv2 get-web-acl-for-resource \
--resource-arn "arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/app/my-alb/<alb-id>" \
--region us-east-1
- WebACL Created — REGIONAL scope, default ALLOW, empty rules.
- Rule Groups Added — CRS (Priority 1) and SQLi rule set (Priority 2) attached with OverrideAction: None.
- WebACL Associated — Linked to the ALB ARN via associate-web-acl.
- COUNT Mode Validation — Optional but recommended: run with OverrideAction: Count to observe before enforcing.
- Enforcement Active — Switch to OverrideAction: None; malicious requests are blocked at the WAF layer.
Step 4: Enable WAF Logging
Without logging, you are operating blind. WAF can emit full request logs to CloudWatch Logs, S3, or Kinesis Data Firehose. The log group or delivery stream name must start with aws-waf-logs- — this prefix is enforced by the service and the configuration will fail without it.
aws wafv2 put-logging-configuration \
--logging-configuration '{"ResourceArn":"arn:aws:wafv2:us-east-1:123456789012:regional/webacl/alb-protection-webacl/<your-webacl-id>","LogDestinationConfigs":["arn:aws:logs:us-east-1:123456789012:log-group:aws-waf-logs-alb-protection"]}' \
--region us-east-1
The CloudWatch log group must exist before this call. Create it first if needed:
aws logs create-log-group \
--log-group-name "aws-waf-logs-alb-protection" \
--region us-east-1
Required IAM Permissions
The principal creating and associating the WebACL needs permissions across both WAF and the ALB resource. Read/List actions on WAF require Resource: "*" — the Service Authorization Reference confirms these actions do not support resource-level restrictions.
🔽 Click to expand — IAM policy for WAF WebACL management
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "WAFWebACLManagement",
"Effect": "Allow",
"Action": [
"wafv2:CreateWebACL",
"wafv2:UpdateWebACL",
"wafv2:DeleteWebACL",
"wafv2:GetWebACL",
"wafv2:ListWebACLs",
"wafv2:AssociateWebACL",
"wafv2:DisassociateWebACL",
"wafv2:GetWebACLForResource",
"wafv2:PutLoggingConfiguration",
"wafv2:ListManagedRuleSets",
"wafv2:DescribeManagedRuleGroup"
],
"Resource": "*"
},
{
"Sid": "ALBDescribe",
"Effect": "Allow",
"Action": [
"elasticloadbalancing:DescribeLoadBalancers"
],
"Resource": "*"
},
{
"Sid": "LogGroupCreation",
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:DescribeLogGroups"
],
"Resource": "arn:aws:logs:us-east-1:123456789012:log-group:aws-waf-logs-*"
}
]
}
Diagnosing False Positives: The Misdiagnosis That Costs Hours
Here is a failure pattern that appears regularly in production: you attach the WebACL, switch from COUNT to enforcement mode, and within minutes your monitoring shows a spike in 403s from legitimate users. The instinct is to check the application — session handling, auth tokens, something changed in the app. Nothing changed in the app.
The actual cause: the AWSManagedRulesCommonRuleSet includes rules that inspect request body content, and certain application payloads — particularly rich text editors, JSON APIs with HTML content, or base64-encoded data — can match XSS signatures. The rule that fires is visible in the WAF logs under the terminatingRuleId field.
Pull the sampled requests to identify which rule is matching:
aws wafv2 get-sampled-requests \
--web-acl-arn "arn:aws:wafv2:us-east-1:123456789012:regional/webacl/alb-protection-webacl/<your-webacl-id>" \
--rule-metric-name "AWSManagedRulesCommonRuleSet" \
--scope REGIONAL \
--region us-east-1 \
--time-window StartTime=<epoch-start>,EndTime=<epoch-end> \
--max-items 100
Once you identify the specific rule ID causing false positives, you can override that individual rule within the managed rule group to COUNT mode while keeping all other rules in BLOCK mode — without disabling the entire rule group. This is done via the RuleActionOverrides parameter in the ManagedRuleGroupStatement.
The insight that saves the most time: WAF log entries include both the terminatingRuleId and the matched field details. Reading the log before touching the WebACL configuration is always faster than iterating on rule changes blind.
Operational Depth: Rule Group Versioning and Update Behavior
By default, AWS Managed Rule Groups use the Default_Version, which AWS updates automatically. This is the correct choice for most workloads — you get new threat coverage without configuration changes. However, there is a behavioral interaction worth understanding: when AWS releases a new version of a managed rule group, the update propagates to your WebACL without a LockToken change on your side. This means a rule group update can change blocking behavior in production without any action on your part.
If your change management process requires explicit approval before rule logic changes, pin to a specific static version using the Version parameter in the ManagedRuleGroupStatement. You can list available versions with:
aws wafv2 list-available-managed-rule-group-versions \
--vendor-name AWS \
--name AWSManagedRulesCommonRuleSet \
--scope REGIONAL \
--region us-east-1
Pinning to a static version means you own the upgrade decision — but you also own the gap in coverage between versions. Neither choice is universally correct; the right answer depends on your change control requirements versus your threat exposure tolerance.
Wrap-Up: AWS WAF on ALB — Next Steps
Attaching AWS WAF to your Application Load Balancer with managed rule groups for SQL injection and XSS protection is a three-step operation: create a REGIONAL WebACL, add the managed rule groups, and associate the WebACL to the ALB ARN. The operational discipline — running COUNT mode before enforcement, enabling logging, and knowing how to read sampled requests — is what separates a WAF that protects from one that either blocks legitimate traffic or provides false confidence.
From here, consider adding AWS WAF Bot Control for automated bot mitigation, and review the AWS WAF Security Automations solution for automated IP reputation blocking based on threat intelligence feeds. Both extend the baseline protection established in this post.
Glossary
| Term | Definition |
|---|---|
| WebACL | Top-level AWS WAF container holding rules, rule groups, and a default action. Associated to AWS resources like ALBs. |
| Managed Rule Group | AWS-maintained collection of WAF rules addressing a specific threat category (e.g., SQLi, XSS, bot traffic). |
| OverrideAction | WebACL-level setting that can force all rules in a rule group into COUNT mode, overriding individual rule actions. |
| LockToken | Optimistic concurrency token required for WebACL update operations. Retrieved via get-web-acl and consumed on each update. |
| terminatingRuleId | Field in WAF log entries identifying which rule matched and terminated evaluation for a given request. |
Related Posts
- 📄 ALB vs NLB: Key Differences Between Application Load Balancer and Network Load Balancer
- 📄 ALB Returning 502 Bad Gateway: Diagnosing Application Response and Protocol Failures
- 📄 Security Group vs Network ACL: Stateful vs Stateless Traffic Filtering in AWS VPC
- 📄 Route 53 Alias vs. CNAME Records: The Definitive Guide for Pointing Domains to an ALB
Comments
Post a Comment