Skip to content

CloudFront distributions access logs should be enabled

CloudFront access logs record every request to your distributions: viewer IP, request URI, edge location, HTTP status, and bytes served. Without them, investigating unauthorized access patterns, detecting content scraping, or tracing the source of anomalous traffic spikes all become significantly harder.

Log data also feeds into cost attribution and performance analysis. If a distribution suddenly drives unexpected data transfer charges, access logs are the fastest way to identify the responsible paths and referrers.

Retrofit consideration

Enabling logging on an existing distribution triggers a configuration update but does not cause downtime. The part that trips people up: the destination S3 bucket must grant the CloudFront log delivery account write access via ACL, and that bucket-side change is easy to miss when retrofitting.

Implementation

Choose the approach that matches how you manage Terraform.

Use the compliance.tf module to enforce this control by default. See get started with compliance.tf.

module "cloudfront" {
  source  = "pcidss.compliance.tf/terraform-aws-modules/cloudfront/aws"
  version = ">=6.0.0,<7.0.0"
}

module "cloudfront" {
  source  = "hipaa.compliance.tf/terraform-aws-modules/cloudfront/aws"
  version = ">=6.0.0,<7.0.0"
}

module "cloudfront" {
  source  = "nistcsf.compliance.tf/terraform-aws-modules/cloudfront/aws"
  version = ">=6.0.0,<7.0.0"
}

module "cloudfront" {
  source  = "cisv80ig1.compliance.tf/terraform-aws-modules/cloudfront/aws"
  version = ">=6.0.0,<7.0.0"
}

module "cloudfront" {
  source  = "acscessentialeight.compliance.tf/terraform-aws-modules/cloudfront/aws"
  version = ">=6.0.0,<7.0.0"
}

module "cloudfront" {
  source  = "hipaasecurity2003.compliance.tf/terraform-aws-modules/cloudfront/aws"
  version = ">=6.0.0,<7.0.0"
}

module "cloudfront" {
  source  = "nistcsfv11.compliance.tf/terraform-aws-modules/cloudfront/aws"
  version = ">=6.0.0,<7.0.0"
}

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"
}

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"
  }

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

  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"
}

What this control checks

The aws_cloudfront_distribution resource must include a logging_config block. Within that block, bucket is required and must reference the domain name of an S3 bucket (e.g., my-logs-bucket.s3.amazonaws.com). The optional include_cookies argument controls whether cookie data appears in logs; prefix sets a key prefix for log objects. A distribution that omits the logging_config block entirely, or sets bucket to an empty string, fails. Any non-empty bucket value pointing to a valid S3 bucket passes.

Common pitfalls

  • S3 bucket ACL requirements for log delivery

    CloudFront standard logging uses the legacy S3 ACL mechanism. The destination bucket must have ACLs enabled (not the default BucketOwnerEnforced setting) and must grant the CloudFront log delivery canonical user permission to write objects and read bucket ACLs. If you use aws_s3_bucket_ownership_controls with object_ownership set to BucketOwnerEnforced, log delivery silently fails and the control may appear compliant even though no logs arrive.

  • Logging bucket configuration mismatches

    Log delivery can silently fail if the destination bucket has restrictive policies or mismatched ACL settings, even when the Terraform config looks correct. The bucket can be in any region, but that doesn't exempt it from the ACL and policy requirements. After enabling logging, verify actual log files are appearing in the bucket before treating the control as satisfied.

  • Confusing standard logging with real-time logging

    CloudFront supports both standard logging (to S3, via logging_config) and real-time logging (to Kinesis Data Streams, via aws_cloudfront_realtime_log_config). This control checks for logging_config specifically. A distribution with only a real-time log config attached does not pass, regardless of how comprehensive that config is.

  • Deprecated inline syntax in older modules

    Some legacy Terraform modules omit the logging_config block entirely or gate it behind a variable that defaults to null. When importing existing distributions into Terraform state, don't assume the module handles logging by default. Confirm the logging_config block is explicit in both state and config.

Audit evidence

Config rule evaluation results showing each distribution as COMPLIANT are the standard starting point, or an equivalent report from a CSPM tool. Supporting evidence should include an S3 bucket listing with actual log files and recent timestamps matching the distribution ID prefix, confirming delivery is working, not just configured. Console screenshots of the distribution's General settings tab with "Standard logging" set to "On" and a valid S3 destination are also accepted. For environments with many distributions, a bulk export from aws cloudfront list-distributions cross-referenced against each distribution's Logging configuration covers the full inventory efficiently.

Framework-specific interpretation

PCI DSS v4.0: CloudFront distributions serving payment pages or APIs are system components under Requirement 10. Every request to those distributions must be logged to support forensic investigation and the daily log review process PCI DSS mandates.

HIPAA Omnibus Rule 2013: 45 CFR 164.312(b) requires audit controls that record and examine activity in systems containing ePHI. For content delivered through CloudFront, access logs are the request-level record of what was served, to whom, and when, which is the evidence that audit control requires.

NIST Cybersecurity Framework v2.0: DE.CM calls for continuous monitoring of your environment for anomalies. CloudFront access logs feed that monitoring directly, giving you traffic patterns and edge behavior for anything served through the distribution.

Tool mappings

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

  • Compliance.tf Control: cloudfront_distribution_logging_enabled

  • AWS Config Managed Rule: CLOUDFRONT_ACCESSLOGS_ENABLED

  • Checkov Check: CKV_AWS_86

  • Powerpipe Control: aws_compliance.control.cloudfront_distribution_logging_enabled

  • Prowler Check: cloudfront_distributions_logging_enabled

  • AWS Security Hub Control: CloudFront.5

  • KICS Query: 94690d79-b3b0-43de-b656-84ebef5753e5

  • Trivy Check: AWS-0010

Last reviewed: 2026-03-08