Expert agent for AWS WAF v2. Covers WebACLs, rule groups, managed rule groups (AWS + marketplace), rate-based rules, IP sets, regex pattern sets, Bot Control, Fraud Control ATP, and integration with ALB, CloudFront, API Gateway, and AppSync. WHEN: \"AWS WAF\", \"WebACL\", \"AWS managed rules\", \"WAF rule group\", \"Bot Control\", \"ATP\", \"AWS Shield\", \"waf.tf\", \"aws_wafv2\", \"WAF ALB\", \"WAF CloudFront\".
Pro scans all 2 files and shows the line behind each finding
Scanned 9/24/2026
npx -y skills add chrishuffman5/domain-expert --skill aws-waf --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Aws Waf?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/chrishuffman5-aws-waf)More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.
---
name: aws-waf
description: "Expert agent for AWS WAF v2. Covers WebACLs, rule groups, managed rule groups (AWS + marketplace), rate-based rules, IP sets, regex pattern sets, Bot Control, Fraud Control ATP, and integration with ALB, CloudFront, API Gateway, and AppSync. WHEN: \"AWS WAF\", \"WebACL\", \"AWS managed rules\", \"WAF rule group\", \"Bot Control\", \"ATP\", \"AWS Shield\", \"waf.tf\", \"aws_wafv2\", \"WAF ALB\", \"WAF CloudFront\"."
license: MIT
---
# AWS WAF
This skill covers AWS WAF v2 (WAFv2), AWS's managed web application firewall service. It covers WebACL configuration, managed rule groups, custom rules, Bot Control, Fraud Control, and integration with AWS services (ALB, CloudFront, API Gateway, AppSync, Cognito).
## How to Approach Tasks
1. **Identify the protected resource type:**
- **CloudFront distribution** -- Global scope WebACL (us-east-1 region)
- **ALB / API Gateway / AppSync** -- Regional scope WebACL (same region as resource)
- **Cognito User Pool** -- Regional scope
2. **Identify the concern:**
- **Setup** -- Creating and associating WebACL
- **Rule management** -- Managed vs. custom rules, rule priority
- **Bot protection** -- Bot Control managed rule group
- **Fraud prevention** -- Account takeover protection (ATP)
- **Infrastructure as code** -- Terraform, CloudFormation
3. **Consider cost** -- AWS WAF charges per WebACL, per rule group, and per million requests processed.
## AWS WAF Architecture
```
CloudFront / ALB / API Gateway / AppSync / Cognito
↓
WebACL (associated to resource)
├── Rule 1 (Priority 0, highest)
├── Rule 2 (Priority 1)
├── Rule 3 ...
└── Default Action (Allow or Block)
```
**WebACL evaluation:**
Rules are evaluated in priority order (0 = first evaluated, highest priority). The first rule that matches determines the action. If no rule matches, the default action applies.
**Scopes:**
- `CLOUDFRONT` — WebACL must be created in us-east-1, associated to CloudFront distribution
- `REGIONAL` — WebACL in the same region as ALB/API Gateway/AppSync/Cognito
---
## WebACL Creation
### Console
AWS Console → WAF & Shield → Web ACLs → Create web ACL
### Terraform
```hcl
resource "aws_wafv2_web_acl" "main" {
name = "my-app-waf"
scope = "REGIONAL" # or "CLOUDFRONT"
description = "WAF for My Application"
default_action {
allow {} # Allow traffic not matching any rule
# block {} # Alternatively, block by default (allowlist model)
}
# AWS Managed Rules - Common Rule Set
rule {
name = "AWSManagedRulesCommonRuleSet"
priority = 10
override_action {
none {} # Use rule group's configured actions
# count {} # Override to count (monitoring mode)
}
statement {
managed_rule_group_statement {
vendor_name = "AWS"
name = "AWSManagedRulesCommonRuleSet"
# Override specific rules within the group
rule_action_override {
name = "SizeRestrictions_BODY"
action_to_use {
count {} # Monitor, don't block
}
}
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "AWSManagedRulesCommonRuleSet"
sampled_requests_enabled = true
}
}
# Custom rate-based rule
rule {
name = "LoginRateLimit"
priority = 5
action {
block {}
}
statement {
rate_based_statement {
limit = 300 # Requests per 5-minute window (100/min effective)
aggregate_key_type = "IP"
scope_down_statement {
byte_match_statement {
search_string = "/api/auth/login"
field_to_match {
uri_path {}
}
text_transformation {
priority = 0
type = "LOWERCASE"
}
positional_constraint = "STARTS_WITH"
}
}
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "LoginRateLimit"
sampled_requests_enabled = true
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "MyAppWAF"
sampled_requests_enabled = true
}
tags = {
Environment = "production"
Team = "security"
}
}
# Associate with ALB
resource "aws_wafv2_web_acl_association" "alb" {
resource_arn = aws_lb.main.arn
web_acl_arn = aws_wafv2_web_acl.main.arn
}
```
---
## AWS Managed Rule Groups
AWS provides maintained rule groups covering common attack patterns.
### Free Managed Rule Groups (AWS)
| Rule Group | Protects Against | Size |
|---|---|---|
| `AWSManagedRulesCommonRuleSet` | OWASP Top 10, common exploits | 700 WCU |
| `AWSManagedRulesAdminProtectionRuleSet` | Admin interface exploitation | 100 WCU |
| `AWSManagedRulesKnownBadInputsRuleSet` | Log4SHELL, SSRF, malformed bodies | 200 WCU |
| `AWSManagedRulesSQLiRuleSet` | SQL injection (comprehensive) | 200 WCU |
| `AWSManagedRulesLinuxRuleSet` | Linux-specific OS attacks | 200 WCU |
| `AWSManagedRulesUnixRuleSet` | POSIX/Unix-specific attacks | 100 WCU |
| `AWSManagedRulesWindowsRuleSet` | Windows/PowerShell exploits | 200 WCU |
| `AWSManagedRulesPHPRuleSet` | PHP-specific vulnerabilities | 100 WCU |
| `AWSManagedRulesWordPressRuleSet` | WordPress-specific attacks | 100 WCU |
| `AWSManagedRulesAmazonIpReputationList` | AWS-detected malicious IPs | 25 WCU |
| `AWSManagedRulesAnonymousIpList` | Tor, VPNs, proxies | 50 WCU |
**WCU (Web ACL Capacity Units):** Each rule consumes WCU. WebACL default limit: 5,000 WCU.
### Paid Managed Rule Groups
**Bot Control** (additional charges):
- `AWSManagedRulesBotControlRuleSet`
- Classifies bots by type (search engine, scraper, tool, etc.)
- Common mode vs. Targeted mode (uses JavaScript fingerprinting, CAPTCHA)
**Fraud Control - ATP (Account Takeover Prevention)**:
- `AWSManagedRulesATPRuleSet`
- Detects credential stuffing on login pages
- Compares credentials against known-breached credential databases
- Requires JavaScript integration on the login page
**Fraud Control - ACFP (Account Creation Fraud Prevention)**:
- `AWSManagedRulesACFPRuleSet`
- Detects fraudulent account creation
- Identifies fake accounts, referral fraud
### Marketplace Managed Rule Groups
Third-party providers offer specialized rule groups:
- **Fortinet:** FortiWeb managed rules
- **F5:** F5 Rules for AWS WAF
- **Trend Micro:** Cloud One Application Security
- **Cyber Security Cloud:** WafCharm automatic tuning
---
## Rule Components
### Rule Statement Types
Statement types include byte match, geo match, IP set reference, regex pattern set reference, rate-based (with custom aggregation keys), and AND/OR/NOT compound statements. See `references/rule-statements.md` for full Terraform examples of each.
### Rule Actions
| Action | Behavior | Use |
|---|---|---|
| `allow` | Allow request to pass | Explicit allowlisting |
| `block` | Return 403 (or custom response) | Block attacks |
| `count` | Increment counter, allow request | Monitoring mode |
| `captcha` | Present CAPTCHA challenge | Suspected bots |
| `challenge` | Present JS challenge | Suspected bots (less friction) |
**Custom block response:**
```hcl
action {
block {
custom_response {
response_code = 403
custom_response_body_key = "block-response"
}
}
}
custom_response_body {
key = "block-response"
content = "{\"error\": \"Request blocked by security policy\"}"
content_type = "APPLICATION_JSON"
}
```
---
## Bot Control
Bot Control classifies bot traffic into categories and allows action per category.
### Common Mode vs. Targeted Mode
| Mode | Detection Method | Cost |
|---|---|---|
| Common | Rule-based bot signatures | Lower |
| Targeted | JS fingerprinting + CAPTCHA + behavioral | Higher |
### Bot Control Rule Labels
AWS WAF Bot Control adds labels to requests for use in downstream rules:
```
awswaf:managed:aws:bot-control:bot:category:search_engine # Googlebot, Bingbot
awswaf:managed:aws:bot-control:bot:category:content_fetcher # Generic crawlers
awswaf:managed:aws:bot-control:bot:category:http_library # curl, wget, python-requests
awswaf:managed:aws:bot-control:bot:category:link_checker
awswaf:managed:aws:bot-control:bot:category:monitoring
awswaf:managed:aws:bot-control:bot:category:scraper
awswaf:managed:aws:bot-control:bot:category:seo # SEO tools
awswaf:managed:aws:bot-control:signal:automated_browser # Headless Chrome/Puppeteer
awswaf:managed:aws:bot-control:signal:non_browser_user_agent
awswaf:managed:aws:bot-control:targeted:signal:automated_browser
```
**Use labels in custom rules:**
```hcl
# Allow search engine bots, block scrapers
rule {
name = "AllowSearchEngines"
priority = 100
action {
allow {}
}
statement {
label_match_statement {
scope = "LABEL"
key = "awswaf:managed:aws:bot-control:bot:category:search_engine"
}
}
}
```
---
## Logging and Monitoring
### Enable WAF Logging
```hcl
resource "aws_wafv2_web_acl_logging_configuration" "main" {
log_destination_configs = [aws_kinesis_firehose_delivery_stream.waf_logs.arn]
resource_arn = aws_wafv2_web_acl.main.arn
# Redact sensitive fields from logs
redacted_fields {
single_header {
name = "authorization"
}
}
redacted_fields {
single_header {
name = "cookie"
}
}
# Log only requests that match rules (not all traffic)
logging_filter {
default_behavior = "DROP" # DROP or KEEP
filter {
behavior = "KEEP"
condition {
action_condition {
action = "BLOCK"
}
}
requirement = "MEETS_ANY"
}
}
}
```
**Log destinations:** Kinesis Firehose (→ S3/ES/Splunk), CloudWatch Logs, S3.
### CloudWatch Metrics
AWS WAF publishes metrics to CloudWatch per rule:
```
Namespace: AWS/WAFV2
Metrics:
AllowedRequests # Count of allowed requests
BlockedRequests # Count of blocked requests
CountedRequests # Count of counted (monitored) requests
PassedRequests # Count passed to next rule
Dimensions:
WebACL: my-app-waf
Region: us-east-1
Rule: AWSManagedRulesCommonRuleSet
```
**CloudWatch Alarms:**
```hcl
resource "aws_cloudwatch_metric_alarm" "waf_blocks_high" {
alarm_name = "WAF-BlockedRequests-High"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = "2"
metric_name = "BlockedRequests"
namespace = "AWS/WAFV2"
period = "300"
statistic = "Sum"
threshold = "1000"
alarm_description = "WAF blocking high volume of requests"
dimensions = {
WebACL = aws_wafv2_web_acl.main.name
Region = var.aws_region
Rule = "ALL"
}
alarm_actions = [aws_sns_topic.security_alerts.arn]
}
```
---
## Common Patterns
### Allowlist + Managed Rules
Ensure internal and monitoring IPs bypass WAF:
```hcl
# Priority 1: Allow trusted IPs first
rule {
name = "AllowTrustedIPs"
priority = 1
action { allow {} }
statement {
ip_set_reference_statement {
arn = aws_wafv2_ip_set.trusted_ips.arn
}
}
}
# Priority 10: Managed rules (only applies if trusted IP rule didn't match)
rule {
name = "AWSManagedRulesCommonRuleSet"
priority = 10
override_action { none {} }
statement {
managed_rule_group_statement {
vendor_name = "AWS"
name = "AWSManagedRulesCommonRuleSet"
}
}
}
```
### Gradual Deployment (Count → Block)
```hcl
# Step 1: Deploy in count mode (monitoring)
override_action { count {} }
# Step 2: After reviewing logs and tuning, change to:
override_action { none {} } # Use rule group's default actions (block)
```
### Common Troubleshooting
**Rule blocking legitimate traffic:**
- Check WAF logs in CloudWatch or S3 for the terminating rule
- Identify which managed rule within the group triggered: check `terminatingRuleMatchDetails`
- Override the specific sub-rule to count mode within the managed rule group
- Create custom rule with higher priority (lower number) that allows the legitimate traffic pattern
**WAF not blocking known malicious traffic:**
- Verify WebACL is associated with the correct resource ARN
- Check rule priority order — earlier rules may be allowing traffic before later rules evaluate
- Verify scope matches resource type (CLOUDFRONT vs. REGIONAL)
- Check that default action is appropriate (Allow + specific block rules vs. Block + specific allow rules)
**High false positive rate on CommonRuleSet:**
- `SizeRestrictions_BODY` frequently false positives for file upload endpoints — override to count
- `GenericRFI_QueryStringArguments` can trigger on legitimate deep links — tune or exclude
- `CrossSiteScripting_BODY` can trigger on rich text content — exclude specific paths
## Reference Files
Load these for deep knowledge on specific topics:
- `references/rule-statements.md` — Full Terraform examples for each WAF rule statement type: byte match, geo match, IP set reference, regex pattern set reference, rate-based with custom keys, and AND/OR/NOT compound statements.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!