Enable CloudWatch Metrics for AWS WAFv2 Web ACL Rules
Overview
This check verifies that every rule and rule group in your AWS WAFv2 Web ACL has CloudWatch metrics enabled. CloudWatch metrics provide visibility into how your WAF rules are evaluating and handling web traffic.
Risk
Without CloudWatch metrics enabled on your WAF rules:
- You lose visibility into which rules are blocking or allowing traffic
- Attack patterns like SQL injection, cross-site scripting (XSS), and bot activity may go undetected
- Troubleshooting misconfigured rules becomes difficult
- You cannot set up alarms for unusual traffic patterns or rule matches
This gap in monitoring can delay detection of security threats, potentially compromising your application's security.
Remediation Steps
Prerequisites
- AWS Console access with permissions to modify WAFv2 resources
- The Web ACL name or ID you want to update
AWS Console Method
- Sign in to the AWS WAF Console
- In the navigation pane, choose Web ACLs
- Select your Web ACL from the list
- Go to the Rules tab
- For each rule listed:
- Click Edit
- Scroll to the Visibility configuration section
- Enable CloudWatch metrics
- Enter a Metric name (use a descriptive name like the rule name)
- Click Save rule
- Repeat for all rules in the Web ACL
For Rule Groups:
- In the navigation pane, choose Rule groups
- Select the rule group you want to update
- Click Edit
- In the Visibility configuration section, enable CloudWatch metrics
- Enter a Metric name
- Click Save
AWS CLI (optional)
Updating WAFv2 Web ACLs via CLI requires retrieving the current configuration, modifying it, and updating with the new configuration. The update-web-acl command replaces the entire Web ACL specification.
Step 1: List your Web ACLs
# For regional resources (ALB, API Gateway, etc.)
aws wafv2 list-web-acls \
--scope REGIONAL \
--region us-east-1
# For CloudFront distributions
aws wafv2 list-web-acls \
--scope CLOUDFRONT \
--region us-east-1
Step 2: Get the current Web ACL configuration
aws wafv2 get-web-acl \
--name <your-web-acl-name> \
--scope REGIONAL \
--id <your-web-acl-id> \
--region us-east-1
Note the LockToken in the response; you will need it for the update.
Step 3: Update the Web ACL
Modify the JSON to ensure each rule has CloudWatchMetricsEnabled: true in its VisibilityConfig, then update:
aws wafv2 update-web-acl \
--name <your-web-acl-name> \
--scope REGIONAL \
--id <your-web-acl-id> \
--lock-token <lock-token-from-get-web-acl> \
--default-action '{"Allow": {}}' \
--visibility-config '{"CloudWatchMetricsEnabled": true, "MetricName": "my-webacl-metric", "SampledRequestsEnabled": true}' \
--rules '[
{
"Name": "MyRule",
"Priority": 1,
"Statement": {"RateBasedStatement": {"Limit": 2000, "AggregateKeyType": "IP"}},
"Action": {"Block": {}},
"VisibilityConfig": {
"CloudWatchMetricsEnabled": true,
"MetricName": "MyRule-metric",
"SampledRequestsEnabled": true
}
}
]' \
--region us-east-1
Important: The update-web-acl command replaces the entire configuration. Make sure to include all existing rules with their updated visibility configurations.
CloudFormation (optional)
When defining a WAFv2 Web ACL in CloudFormation, ensure CloudWatchMetricsEnabled: true is set in both the Web ACL's VisibilityConfig and each rule's VisibilityConfig.
AWSTemplateFormatVersion: '2010-09-09'
Description: WAFv2 Web ACL with CloudWatch Metrics Enabled
Parameters:
WebACLName:
Type: String
Description: Name for the Web ACL
Default: my-web-acl
Resources:
WebACL:
Type: AWS::WAFv2::WebACL
Properties:
Name: !Ref WebACLName
Scope: REGIONAL
DefaultAction:
Allow: {}
# Web ACL-level visibility config
VisibilityConfig:
CloudWatchMetricsEnabled: true
MetricName: !Sub "${WebACLName}-metric"
SampledRequestsEnabled: true
Rules:
- Name: RateLimitRule
Priority: 1
Statement:
RateBasedStatement:
Limit: 2000
AggregateKeyType: IP
Action:
Block: {}
# Rule-level visibility config
VisibilityConfig:
CloudWatchMetricsEnabled: true
MetricName: RateLimitRule-metric
SampledRequestsEnabled: true
Outputs:
WebACLArn:
Description: ARN of the Web ACL
Value: !GetAtt WebACL.Arn
WebACLId:
Description: ID of the Web ACL
Value: !GetAtt WebACL.Id
Key points:
- Each rule must have its own
VisibilityConfigblock withCloudWatchMetricsEnabled: true - The
MetricNamemust be unique within the Web ACL SampledRequestsEnabledallows you to view sample requests in the AWS console
Terraform (optional)
In Terraform, ensure every visibility_config block has cloudwatch_metrics_enabled = true.
terraform {
required_version = ">= 1.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 5.0"
}
}
}
provider "aws" {
region = "us-east-1"
}
variable "web_acl_name" {
description = "Name for the Web ACL"
type = string
default = "my-web-acl"
}
resource "aws_wafv2_web_acl" "example" {
name = var.web_acl_name
description = "Web ACL with CloudWatch metrics enabled"
scope = "REGIONAL"
default_action {
allow {}
}
# Web ACL-level visibility config with CloudWatch metrics enabled
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "${var.web_acl_name}-metric"
sampled_requests_enabled = true
}
# Example rule with CloudWatch metrics enabled
rule {
name = "RateLimitRule"
priority = 1
action {
block {}
}
statement {
rate_based_statement {
limit = 2000
aggregate_key_type = "IP"
}
}
# Rule-level visibility config - this is the key setting
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "RateLimitRule-metric"
sampled_requests_enabled = true
}
}
}
output "web_acl_arn" {
description = "ARN of the Web ACL"
value = aws_wafv2_web_acl.example.arn
}
output "web_acl_id" {
description = "ID of the Web ACL"
value = aws_wafv2_web_acl.example.id
}
Key points:
- Every
ruleblock must include avisibility_configwithcloudwatch_metrics_enabled = true - The Web ACL itself also needs a top-level
visibility_config - Each
metric_nameshould be unique and descriptive
Verification
After enabling CloudWatch metrics:
- Go to the AWS WAF Console
- Select your Web ACL
- Review each rule and confirm CloudWatch metrics is enabled in the visibility configuration
- Check the CloudWatch metrics tab to see metrics appearing (may take a few minutes)
CLI Verification
aws wafv2 get-web-acl \
--name <your-web-acl-name> \
--scope REGIONAL \
--id <your-web-acl-id> \
--region us-east-1 \
--query 'WebACL.Rules[*].{Name:Name,MetricsEnabled:VisibilityConfig.CloudWatchMetricsEnabled}'
All rules should show MetricsEnabled: true.
To re-run the Prowler check:
prowler aws --checks wafv2_webacl_rule_logging_enabled
Additional Resources
- AWS WAF Developer Guide
- Monitoring with Amazon CloudWatch
- AWS WAFv2 CloudFormation Reference
- Terraform aws_wafv2_web_acl Resource
Notes
- Scope matters: Use
REGIONALfor resources like Application Load Balancers and API Gateway. UseCLOUDFRONTfor CloudFront distributions (and you must use theus-east-1region). - Metric naming: Each metric name must be unique within the Web ACL. Use descriptive names that match your rule names for easier troubleshooting.
- Cost consideration: CloudWatch metrics incur standard CloudWatch pricing. The cost is typically minimal but scales with the number of rules and request volume.
- Propagation time: Changes to WAF configurations may take a few minutes to propagate across all edge locations.