0
0
AwsHow-ToBeginner · 4 min read

How to Use AWS WAF with CloudFront for Web Security

To use AWS WAF with CloudFront, create a WAF web ACL with your security rules and then associate it with your CloudFront distribution. This setup filters incoming web traffic at the edge, protecting your site from attacks like SQL injection and cross-site scripting.
📐

Syntax

Using AWS WAF with CloudFront involves these main parts:

  • Web ACL: A set of rules that define what traffic to allow, block, or count.
  • Rules: Conditions like IP match, string match, or managed rule groups.
  • Association: Linking the Web ACL to a CloudFront distribution to apply the rules.
terraform
resource "aws_wafv2_web_acl" "example" {
  name        = "example-web-acl"
  scope       = "CLOUDFRONT"
  description = "Protect CloudFront distribution"

  default_action {
    allow {}
  }

  rule {
    name     = "BlockBadBots"
    priority = 1

    statement {
      byte_match_statement {
        search_string = "BadBot"
        field_to_match {
          single_header {
            name = "user-agent"
          }
        }
        positional_constraint = "CONTAINS"
        text_transformations {
          priority = 0
          type     = "NONE"
        }
      }
    }

    action {
      block {}
    }

    visibility_config {
      sampled_requests_enabled = true
      cloudwatch_metrics_enabled = true
      metric_name = "BlockBadBots"
    }
  }

  visibility_config {
    cloudwatch_metrics_enabled = true
    metric_name                = "exampleWebACL"
    sampled_requests_enabled   = true
  }
}

resource "aws_cloudfront_distribution" "example" {
  origin {
    domain_name = "example.com"
    origin_id   = "example-origin"
  }

  enabled             = true
  is_ipv6_enabled     = true
  default_root_object = "index.html"

  default_cache_behavior {
    target_origin_id       = "example-origin"
    viewer_protocol_policy = "redirect-to-https"

    allowed_methods = ["GET", "HEAD"]

    forwarded_values {
      query_string = false
      cookies {
        forward = "none"
      }
    }
  }

  restrictions {
    geo_restriction {
      restriction_type = "none"
    }
  }

  viewer_certificate {
    cloudfront_default_certificate = true
  }

  web_acl_id = aws_wafv2_web_acl.example.arn
}
💻

Example

This example shows how to create a simple AWS WAF web ACL that blocks requests with a "BadBot" user-agent and attach it to a CloudFront distribution using Terraform.

terraform
provider "aws" {
  region = "us-east-1"
}

resource "aws_wafv2_web_acl" "example" {
  name        = "example-web-acl"
  scope       = "CLOUDFRONT"
  description = "Protect CloudFront distribution"

  default_action {
    allow {}
  }

  rule {
    name     = "BlockBadBots"
    priority = 1

    statement {
      byte_match_statement {
        search_string = "BadBot"
        field_to_match {
          single_header {
            name = "user-agent"
          }
        }
        positional_constraint = "CONTAINS"
        text_transformations {
          priority = 0
          type     = "NONE"
        }
      }
    }

    action {
      block {}
    }

    visibility_config {
      sampled_requests_enabled    = true
      cloudwatch_metrics_enabled  = true
      metric_name                 = "BlockBadBots"
    }
  }

  visibility_config {
    cloudwatch_metrics_enabled = true
    metric_name                = "exampleWebACL"
    sampled_requests_enabled   = true
  }
}

resource "aws_cloudfront_distribution" "example" {
  origin {
    domain_name = "example.com"
    origin_id   = "example-origin"
  }

  enabled             = true
  is_ipv6_enabled     = true
  default_root_object = "index.html"

  default_cache_behavior {
    target_origin_id       = "example-origin"
    viewer_protocol_policy = "redirect-to-https"

    allowed_methods = ["GET", "HEAD"]

    forwarded_values {
      query_string = false
      cookies {
        forward = "none"
      }
    }
  }

  restrictions {
    geo_restriction {
      restriction_type = "none"
    }
  }

  viewer_certificate {
    cloudfront_default_certificate = true
  }

  web_acl_id = aws_wafv2_web_acl.example.arn
}
Output
Terraform will create a WAF web ACL named "example-web-acl" with a rule blocking requests containing "BadBot" in the User-Agent header, then create a CloudFront distribution that uses this web ACL to filter incoming traffic.
⚠️

Common Pitfalls

Common mistakes when using WAF with CloudFront include:

  • Not setting the scope to CLOUDFRONT in the WAF Web ACL, which is required for CloudFront.
  • Forgetting to associate the Web ACL ARN with the CloudFront distribution's web_acl_id.
  • Using regional WAF Web ACLs instead of global scope for CloudFront.
  • Not waiting for CloudFront distribution deployment after associating the Web ACL, causing delays in protection.
terraform
/* Wrong: scope set to REGIONAL (for ALB, not CloudFront) */
resource "aws_wafv2_web_acl" "wrong" {
  name  = "wrong-scope"
  scope = "REGIONAL"  # Incorrect for CloudFront
  default_action { allow {} }
  visibility_config {
    cloudwatch_metrics_enabled = true
    metric_name                = "wrongScope"
    sampled_requests_enabled   = true
  }
}

/* Right: scope set to CLOUDFRONT */
resource "aws_wafv2_web_acl" "right" {
  name  = "right-scope"
  scope = "CLOUDFRONT"  # Correct for CloudFront
  default_action { allow {} }
  visibility_config {
    cloudwatch_metrics_enabled = true
    metric_name                = "rightScope"
    sampled_requests_enabled   = true
  }
}
📊

Quick Reference

  • WAF Web ACL scope: Must be CLOUDFRONT for CloudFront distributions.
  • Association: Use the web_acl_id property in CloudFront distribution.
  • Rules: Use managed rule groups or custom rules to filter traffic.
  • Deployment: Changes take time to propagate through CloudFront edge locations.

Key Takeaways

Always set the WAF Web ACL scope to CLOUDFRONT when protecting CloudFront distributions.
Attach the Web ACL to CloudFront using the web_acl_id property in the distribution configuration.
Use rules in the Web ACL to block or allow traffic based on headers, IPs, or managed rule groups.
Wait for CloudFront deployment to complete after associating the Web ACL for protection to be active.
Test your WAF rules carefully to avoid blocking legitimate traffic.