Skip to content

CloudFront distributions should have a default root object configured

Without a default root object, requests to the root of your CloudFront distribution (e.g., https://d111111abcdef8.cloudfront.net/) go straight to the origin's root path. Depending on origin configuration, this can return error messages or unintended responses that expose implementation details, S3 bucket structure, or server internals.

Setting default_root_object to something like index.html gives you explicit control over what visitors see at the root path.

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  = "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 default_root_object set to a non-empty string. "index.html" is the typical value, but any valid object key in the origin works. It fails when the argument is omitted or set to "". Note that the argument takes an object name only, not a path with a leading slash. This is a single-line change on the distribution resource with no additional resources required.

Common pitfalls

  • Empty string passes Terraform validation but fails the control

    default_root_object = "" passes Terraform's syntax check but sets no actual default on the distribution. The compliance check fails. Set a real object key.

  • Leading slash in the object name

    Drop the leading slash. CloudFront expects index.html, not /index.html. The API rejects or mishandles the leading slash, and Terraform itself won't catch the format error, so this tends to slip through until deployment.

  • Default root object only applies to the root URL

    default_root_object only affects requests to the distribution root (e.g., https://d111.cloudfront.net/). Subdirectory requests like /blog/ are unaffected. If you need default objects at subdirectory paths, that requires a CloudFront Function or Lambda@Edge, which is outside the scope of this control.

Audit evidence

Auditors expect Config rule results for cloudfront-default-root-object-configured showing all distributions as compliant. aws cloudfront list-distributions output filtered to confirm every distribution's DefaultRootObject field is populated also works. Console screenshots of each distribution's General settings are acceptable for smaller environments. Automated scan reports from Prowler or Security Hub showing this check passing across all accounts are sufficient for larger organizations.

Framework-specific interpretation

NIST Cybersecurity Framework v1.1: PR.AC and PR.DS in the CSF's Protect function both apply here. A distribution without a default root object can leak implementation details or expose origin structure at the root URL. Setting one ensures visitors get a controlled response rather than an error or unintended content that reveals how the backend is organized.

Tool mappings

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

  • Compliance.tf Control: cloudfront_distribution_default_root_object_configured

  • AWS Config Managed Rule: CLOUDFRONT_DEFAULT_ROOT_OBJECT_CONFIGURED

  • Checkov Check: CKV_AWS_305

  • Powerpipe Control: aws_compliance.control.cloudfront_distribution_default_root_object_configured

  • Prowler Check: cloudfront_distributions_default_root_object

  • AWS Security Hub Control: CloudFront.1

Last reviewed: 2026-03-08