CloudFront Distribution Has WAF Enabled
Overview
This check verifies that your Amazon CloudFront distributions have AWS WAF (Web Application Firewall) enabled. WAF helps protect your web applications and APIs by filtering and monitoring HTTP/HTTPS requests, blocking common web exploits before they reach your origin servers.
Risk
Without WAF protection on your CloudFront distributions, your web applications are exposed to common web-based attacks:
- SQL injection and cross-site scripting (XSS): Attackers can exploit vulnerabilities to steal data or compromise user sessions
- Bot abuse and credential stuffing: Automated attacks can overwhelm your application or compromise user accounts
- Layer 7 DDoS attacks: Application-layer attacks can exhaust your origin server resources
- OWASP Top 10 vulnerabilities: Common attack patterns that WAF rules are designed to block
Since CloudFront is often the first point of contact for user traffic, enabling WAF at this layer provides early protection before malicious requests reach your infrastructure.
Severity: Medium
Remediation Steps
Prerequisites
- Access to the AWS Console with permissions to modify CloudFront distributions and WAF settings
- An existing WAF web ACL, or permission to create one
Important: WAF scope for CloudFront
Unlike other AWS resources, CloudFront distributions require a global WAF web ACL:
- WAF web ACLs for CloudFront must be created with CLOUDFRONT scope
- These global web ACLs must be created in the us-east-1 region
- Regional web ACLs (used for ALB, API Gateway, etc.) cannot be used with CloudFront
AWS Console Method
Step 1: Create or Identify a WAF Web ACL
If you already have a global WAF web ACL to use, skip to Step 2.
- Sign in to the AWS Console
- Navigate to WAF & Shield (search for it in the search bar)
- In the left sidebar, click Web ACLs
- Ensure your region is set to Global (CloudFront) (not a regional location)
- Click Create web ACL
- Configure the web ACL:
- Name: Enter a descriptive name (e.g.,
cloudfront-waf-acl) - Description: Optional description
- CloudWatch metric name: Auto-populated based on the name
- Resource type: Select Amazon CloudFront distributions
- Name: Enter a descriptive name (e.g.,
- Click Next
- Add rules (recommended starting point):
- Click Add rules > Add managed rule groups
- Expand AWS managed rule groups
- Enable Core rule set (covers common vulnerabilities)
- Enable Known bad inputs (blocks known malicious patterns)
- Click Add rules, then Next
- Set the default action to Allow (rules will block specific threats)
- Click Next through the remaining steps, then Create web ACL
Step 2: Associate the WAF Web ACL with Your CloudFront Distribution
Option A: From the WAF Console
- In the WAF & Shield console, click Web ACLs
- Ensure you are viewing Global (CloudFront) region
- Click on the web ACL you want to attach
- Select the Associated AWS resources tab
- Click Add AWS resources
- Check the box next to your CloudFront distribution(s)
- Click Add
Option B: From the CloudFront Console
- Open the CloudFront console
- Select the distribution you want to protect
- Click the Security tab
- Under AWS WAF, click Enable security protections
- Choose either:
- Use existing web ACL: Select your web ACL from the dropdown
- Enable one-click protection: Let CloudFront create a pre-configured web ACL automatically
- Click Save changes
- Wait for the distribution status to change from "Deploying" to the last modified date
AWS CLI (optional)
Create a Global WAF Web ACL
First, create a web ACL with CloudFront scope (must be in us-east-1):
aws wafv2 create-web-acl \
--name cloudfront-waf-acl \
--scope CLOUDFRONT \
--default-action Allow={} \
--visibility-config SampledRequestsEnabled=true,CloudWatchMetricsEnabled=true,MetricName=cloudfront-waf-acl-metrics \
--rules '[
{
"Name": "AWSManagedRulesCommonRuleSet",
"Priority": 1,
"Statement": {
"ManagedRuleGroupStatement": {
"VendorName": "AWS",
"Name": "AWSManagedRulesCommonRuleSet"
}
},
"OverrideAction": {"None": {}},
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "AWSManagedRulesCommonRuleSetMetric"
}
}
]' \
--region us-east-1
List Available Global Web ACLs
aws wafv2 list-web-acls \
--scope CLOUDFRONT \
--region us-east-1
Example output:
{
"WebACLs": [
{
"Name": "cloudfront-waf-acl",
"Id": "a1b2c3d4-5678-90ab-cdef-EXAMPLE11111",
"ARN": "arn:aws:wafv2:us-east-1:123456789012:global/webacl/cloudfront-waf-acl/a1b2c3d4-5678-90ab-cdef-EXAMPLE11111"
}
]
}
Associate Web ACL with CloudFront Distribution
Unlike other resources, CloudFront does not use associate-web-acl. You must update the distribution configuration:
Step 1: Get the current distribution configuration
aws cloudfront get-distribution-config \
--id E1EXAMPLE12345 \
--region us-east-1 \
--output json > /tmp/dist-config.json
Step 2: Note the ETag value
ETAG=$(jq -r '.ETag' /tmp/dist-config.json)
echo "ETag: $ETAG"
Step 3: Add the WebACLId to the configuration
jq '.DistributionConfig.WebACLId = "arn:aws:wafv2:us-east-1:123456789012:global/webacl/cloudfront-waf-acl/a1b2c3d4-5678-90ab-cdef-EXAMPLE11111" | .DistributionConfig' /tmp/dist-config.json > /tmp/updated-config.json
Step 4: Update the distribution
aws cloudfront update-distribution \
--id E1EXAMPLE12345 \
--if-match "$ETAG" \
--distribution-config file:///tmp/updated-config.json \
--region us-east-1
Replace:
E1EXAMPLE12345with your distribution ID- The web ACL ARN with your actual web ACL ARN
CloudFormation (optional)
CloudFormation Template
This template creates a global WAF web ACL and a CloudFront distribution with WAF enabled.
AWSTemplateFormatVersion: '2010-09-09'
Description: CloudFront distribution with WAF protection
Resources:
CloudFrontWebACL:
Type: AWS::WAFv2::WebACL
Properties:
Name: cloudfront-waf-acl
Description: WAF Web ACL for CloudFront distribution protection
Scope: CLOUDFRONT
DefaultAction:
Allow: {}
VisibilityConfig:
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: true
MetricName: cloudfront-waf-acl-metrics
Rules:
- Name: AWSManagedRulesCommonRuleSet
Priority: 1
OverrideAction:
None: {}
Statement:
ManagedRuleGroupStatement:
VendorName: AWS
Name: AWSManagedRulesCommonRuleSet
VisibilityConfig:
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: true
MetricName: AWSManagedRulesCommonRuleSetMetric
- Name: AWSManagedRulesKnownBadInputsRuleSet
Priority: 2
OverrideAction:
None: {}
Statement:
ManagedRuleGroupStatement:
VendorName: AWS
Name: AWSManagedRulesKnownBadInputsRuleSet
VisibilityConfig:
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: true
MetricName: AWSManagedRulesKnownBadInputsRuleSetMetric
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Enabled: true
Comment: CloudFront distribution with WAF protection
WebACLId: !GetAtt CloudFrontWebACL.Arn
Origins:
- Id: myOrigin
DomainName: my-origin.example.com
CustomOriginConfig:
OriginProtocolPolicy: https-only
DefaultCacheBehavior:
TargetOriginId: myOrigin
ViewerProtocolPolicy: redirect-to-https
CachePolicyId: 658327ea-f89d-4fab-a63d-7e88639e58f6
Outputs:
WebACLArn:
Description: ARN of the created Web ACL
Value: !GetAtt CloudFrontWebACL.Arn
DistributionId:
Description: CloudFront distribution ID
Value: !Ref CloudFrontDistribution
DistributionDomainName:
Description: CloudFront distribution domain name
Value: !GetAtt CloudFrontDistribution.DomainName
Important: For CLOUDFRONT scope, the CloudFormation stack must be deployed in us-east-1:
aws cloudformation create-stack \
--stack-name cloudfront-waf-protection \
--template-body file://cloudfront-waf.yaml \
--region us-east-1
Adding WAF to an Existing Distribution
If you have an existing CloudFront distribution in CloudFormation, add the WebACLId property:
ExistingDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
WebACLId: !GetAtt CloudFrontWebACL.Arn
# ... rest of your existing configuration
Terraform (optional)
Terraform Configuration
# Provider configuration - WAF for CloudFront must be in us-east-1
provider "aws" {
alias = "us_east_1"
region = "us-east-1"
}
variable "web_acl_name" {
description = "Name for the WAF Web ACL"
type = string
default = "cloudfront-waf-acl"
}
# WAF Web ACL with CLOUDFRONT scope
resource "aws_wafv2_web_acl" "cloudfront" {
provider = aws.us_east_1
name = var.web_acl_name
description = "WAF Web ACL for CloudFront distribution protection"
scope = "CLOUDFRONT"
default_action {
allow {}
}
# AWS Managed Rules - Common Rule Set
rule {
name = "AWSManagedRulesCommonRuleSet"
priority = 1
override_action {
none {}
}
statement {
managed_rule_group_statement {
name = "AWSManagedRulesCommonRuleSet"
vendor_name = "AWS"
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "AWSManagedRulesCommonRuleSetMetric"
sampled_requests_enabled = true
}
}
# AWS Managed Rules - Known Bad Inputs
rule {
name = "AWSManagedRulesKnownBadInputsRuleSet"
priority = 2
override_action {
none {}
}
statement {
managed_rule_group_statement {
name = "AWSManagedRulesKnownBadInputsRuleSet"
vendor_name = "AWS"
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "AWSManagedRulesKnownBadInputsRuleSetMetric"
sampled_requests_enabled = true
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "${var.web_acl_name}-metrics"
sampled_requests_enabled = true
}
tags = {
Name = var.web_acl_name
Environment = "production"
ManagedBy = "terraform"
}
}
# CloudFront distribution with WAF enabled
resource "aws_cloudfront_distribution" "example" {
provider = aws.us_east_1
enabled = true
comment = "CloudFront distribution with WAF protection"
web_acl_id = aws_wafv2_web_acl.cloudfront.arn
origin {
domain_name = "my-origin.example.com"
origin_id = "myOrigin"
custom_origin_config {
http_port = 80
https_port = 443
origin_protocol_policy = "https-only"
origin_ssl_protocols = ["TLSv1.2"]
}
}
default_cache_behavior {
allowed_methods = ["GET", "HEAD"]
cached_methods = ["GET", "HEAD"]
target_origin_id = "myOrigin"
viewer_protocol_policy = "redirect-to-https"
forwarded_values {
query_string = false
cookies {
forward = "none"
}
}
}
restrictions {
geo_restriction {
restriction_type = "none"
}
}
viewer_certificate {
cloudfront_default_certificate = true
}
}
# Outputs
output "web_acl_arn" {
description = "ARN of the created Web ACL"
value = aws_wafv2_web_acl.cloudfront.arn
}
output "distribution_id" {
description = "CloudFront distribution ID"
value = aws_cloudfront_distribution.example.id
}
Adding WAF to an Existing Distribution
If you have an existing CloudFront distribution, add the web_acl_id argument:
resource "aws_cloudfront_distribution" "existing" {
# ... existing configuration ...
web_acl_id = aws_wafv2_web_acl.cloudfront.arn
}
Apply the Configuration
terraform init
terraform plan
terraform apply
Verification
After enabling WAF on your CloudFront distribution, verify the association:
- Open the CloudFront console
- Select your distribution
- Click the Security tab
- Under AWS WAF, confirm your web ACL name is displayed
Alternatively, in the WAF & Shield console:
- Ensure you are in the Global (CloudFront) region
- Go to Web ACLs and select your web ACL
- Click the Associated AWS resources tab
- Confirm your CloudFront distribution appears in the list
CLI verification commands
Check if WAF is enabled on a specific distribution:
aws cloudfront get-distribution \
--id E1EXAMPLE12345 \
--region us-east-1 \
--query 'Distribution.DistributionConfig.WebACLId'
Expected output when WAF is enabled:
"arn:aws:wafv2:us-east-1:123456789012:global/webacl/cloudfront-waf-acl/a1b2c3d4-5678-90ab-cdef-EXAMPLE11111"
List resources associated with your global web ACL:
aws wafv2 list-resources-for-web-acl \
--web-acl-arn arn:aws:wafv2:us-east-1:<ACCOUNT_ID>:global/webacl/<WEB_ACL_NAME>/<WEB_ACL_ID> \
--resource-type CLOUDFRONT \
--region us-east-1
Re-run Prowler to confirm the check passes:
prowler aws --check cloudfront_distributions_waf_enabled
Additional Resources
- Use AWS WAF protections - Amazon CloudFront Developer Guide
- Using AWS WAF with Amazon CloudFront - AWS WAF Developer Guide
- AWS Managed Rules for AWS WAF
- AWS WAF Pricing
Notes
-
Global scope required: WAF web ACLs for CloudFront must be created with
CLOUDFRONTscope in theus-east-1region. Regional web ACLs cannot be used with CloudFront distributions. -
One-click protection: The CloudFront console offers "one-click protection" that automatically creates a pre-configured web ACL with AWS-recommended rules. This is a quick way to get started if you do not have specific rule requirements.
-
Rule tuning: Start with managed rules and monitor WAF logs in CloudWatch to identify potential false positives. You can set rules to "count" mode initially to observe their behavior before enabling blocking.
-
Cost considerations: AWS WAF charges based on the number of web ACLs, rules, and requests processed. Review WAF pricing before deployment. Managed rule groups may have additional subscription costs.
-
Update method: Unlike API Gateway and ALB, CloudFront distributions do not use the
wafv2 associate-web-aclAPI. Instead, you must update the distribution configuration with theWebACLIdproperty. -
Propagation time: After associating a WAF web ACL with CloudFront, changes propagate to all edge locations. This typically takes a few minutes to complete.