Skip to content

CloudFront distributions should have geo restriction enabled

Without geo restriction, a CloudFront distribution answers requests from anywhere in the world. Country-level filtering reduces the attack surface for content with regional licensing obligations or regulatory boundaries, and limits exposure to regions with high volumes of malicious traffic.

Geo restriction is not a substitute for WAF or authentication. It is a coarse first filter that stops requests before they reach your origin. For distributions serving sensitive data or applications restricted to specific markets, expect auditors and security teams to ask why it is not configured.

Retrofit consideration

Geo restriction takes effect immediately on a live distribution and will start blocking users in excluded countries without warning. Pull CloudFront access logs first to understand your actual geographic traffic distribution before committing to a whitelist or blacklist.

Implementation

Choose the approach that matches how you manage Terraform.

If you use terraform-aws-modules/cloudfront/aws, set the right module inputs for this control. You can later migrate to the compliance.tf module with minimal changes because it is compatible by design.

module "cloudfront" {
  source  = "terraform-aws-modules/cloudfront/aws"
  version = ">=6.0.0,<7.0.0"

  restrictions = {
    geo_restriction = {
      restriction_type = "whitelist"
    }
  }
}

Use AWS provider resources directly. See docs for the resources involved: aws_cloudfront_distribution.

resource "aws_cloudfront_distribution" "this" {
  default_cache_behavior {
    allowed_methods           = ["GET", "HEAD"]
    cached_methods            = ["GET", "HEAD"]
    field_level_encryption_id = "abc123"

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

    target_origin_id       = "S3Origin"
    viewer_protocol_policy = "redirect-to-https"
  }
  default_root_object = "index.html"
  enabled             = true

  logging_config {
    bucket = "example-bucket-abc123_domain_name"
  }

  origin {
    domain_name = "example.s3.amazonaws.com"
    origin_id   = "S3Origin"
  }

  viewer_certificate {
    acm_certificate_arn      = "arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012"
    minimum_protocol_version = "TLSv1.2_2021"
    ssl_support_method       = "sni-only"
  }

  wait_for_deployment = false
  web_acl_id          = "arn:aws:wafv2:us-east-1:123456789012:regional/webacl/example/12345678-1234-1234-1234-123456789012"

  restrictions {
    geo_restriction {
      locations        = ["US", "CA", "GB"]
      restriction_type = "whitelist"
    }
  }
}

What this control checks

The control checks that the aws_cloudfront_distribution resource has a restrictions block with a geo_restriction sub-block where restriction_type is "whitelist" or "blacklist", not "none". With restriction_type = "whitelist", only countries in the locations list can reach the distribution. With "blacklist", those countries are blocked. A distribution passes when restriction_type is not "none" and locations contains at least one valid ISO 3166-1 alpha-2 code. It fails when restriction_type = "none" or the geo_restriction block is missing entirely.

Common pitfalls

  • restriction_type defaults require explicit setting

    Omitting geo_restriction from the restrictions block results in no filtering, equivalent to restriction_type = "none". Setting restriction_type = "none" explicitly has the same effect and passes terraform plan without complaint while failing this control. Check the value, not just the block's presence.

  • Empty locations list with whitelist blocks all traffic

    A whitelist with an empty locations list blocks every country, taking the distribution offline. CloudFront has no way to distinguish 'whitelist nothing' from 'allow nothing', so it allows nothing. Populate locations with at least one country code before applying.

  • Geo restriction uses IP-based geolocation, not identity

    CloudFront maps the viewer's source IP to a country, so anyone behind a VPN or proxy in an allowed country passes right through. Geo restriction reduces exposure; it doesn't guarantee geographic enforcement. Layer WAF rules or authentication if the boundary needs to be enforced more strictly.

  • Country codes must be uppercase ISO 3166-1 alpha-2

    The locations argument expects uppercase ISO 3166-1 alpha-2 codes: "US", "DE", "JP". Three-letter codes and lowercase formats are rejected at apply time by provider and API validation. Use the two-letter uppercase format to avoid failures during terraform apply.

Audit evidence

An auditor expects Config rule evaluation results or AWS CLI output confirming geo restriction is active on every in-scope distribution. The CloudFront console's Restrictions tab shows the current restriction type and country list per distribution. aws cloudfront get-distribution-config output should show GeoRestriction.RestrictionType as Whitelist or Blacklist with a non-empty Items array of country codes.

For ongoing evidence, CloudFront access logs showing 403 responses from restricted countries demonstrate the control is functioning. Scan reports from Steampipe, Prowler, or Security Hub provide timestamped, per-distribution coverage status across all distributions in scope.

Tool mappings

Use these identifiers to cross-reference this control across tools, reports, and evidence.

  • Compliance.tf Control: cloudfront_distribution_geo_restrictions_enabled

  • Checkov Check: CKV_AWS_374

  • Powerpipe Control: aws_compliance.control.cloudfront_distribution_geo_restrictions_enabled

  • Prowler Check: cloudfront_distributions_geo_restrictions_enabled

Last reviewed: 2026-03-09