Skip to content

CloudFront distributions should use custom SSL/TLS certificates

The default CloudFront certificate only covers *.cloudfront.net. Serving content on a custom domain like cdn.example.com with the default certificate means browsers reject the connection or users must click through a domain mismatch warning, which trains them to ignore TLS errors. Custom certificates from ACM or IAM prove domain ownership and let clients validate the exact hostname they requested.

Beyond user trust, many compliance programs require publicly facing endpoints to present certificates matching their DNS names. Using the default certificate tells an auditor that TLS configuration was never touched after initial provisioning.

Retrofit consideration

Switching from the default certificate to a custom ACM certificate requires a validated ACM certificate in us-east-1 and may trigger a CloudFront distribution redeployment that takes 10-20 minutes to propagate.

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  = "nistcsf.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

In the aws_cloudfront_distribution resource, the viewer_certificate block controls which certificate the distribution presents. It fails when cloudfront_default_certificate is true or no custom certificate is specified. To pass, set acm_certificate_arn to an ACM certificate ARN provisioned in us-east-1, along with ssl_support_method (typically "sni-only") and minimum_protocol_version (e.g., "TLSv1.2_2021"). You can also use iam_certificate_id for IAM-stored certificates, though ACM is the preferred path. The control passes when acm_certificate_arn or iam_certificate_id is present and cloudfront_default_certificate is absent or false.

Common pitfalls

  • ACM certificate must be in us-east-1

    CloudFront requires ACM certificates in us-east-1, regardless of where your Terraform provider is configured. Referencing an acm_certificate_arn from any other region causes CloudFront to reject the configuration outright. Use a provider alias for us-east-1 when creating the aws_acm_certificate resource.

  • Missing aliases causes custom domain/certificate issues

    Get the aliases block wrong and your certificate mismatch will show up in production. The aliases argument must list every custom domain CloudFront serves, and those names must be covered by the attached certificate. An empty aliases list means CloudFront falls back to its default domain; a hostname configured as an alias but not covered by the cert throws hostname/certificate errors for clients.

  • viewer_certificate left on default certificate

    Searching your codebase for cloudfront_default_certificate = true takes about thirty seconds and will surface every non-compliant distribution. Older configurations often set this as a placeholder during initial setup and never revisit it.

  • ssl_support_method required with custom certificates

    ssl_support_method is required whenever you specify acm_certificate_arn. Omit it and Terraform throws a validation error before any plan runs. Set it to "sni-only" unless you specifically need dedicated IP custom SSL, which adds a per-distribution monthly charge.

Audit evidence

Auditors look for Config rule evaluation results showing each CloudFront distribution as COMPLIANT. Console evidence is the distribution's General settings page listing a custom SSL certificate ARN under "Custom SSL certificate" rather than "Default CloudFront certificate (*.cloudfront.net)". The aws cloudfront get-distribution-config API output should show ViewerCertificate.ACMCertificateArn or ViewerCertificate.IAMCertificateId populated and CloudFrontDefaultCertificate set to false.

Supporting evidence includes the ACM certificate details confirming the certificate covers the distribution's alternate domain names (CNAMEs) and that the certificate status is ISSUED, not EXPIRED or PENDING_VALIDATION.

Framework-specific interpretation

PCI DSS v4.0: Requirement 4.2.1 mandates strong cryptography when transmitting cardholder data over public networks. For a CDN serving payment-adjacent content, a custom certificate tied to the organization's domain is what satisfies the verifiable identity piece of that requirement, and what a QSA will ask to see documented.

NIST Cybersecurity Framework v2.0: PR.DS covers protection of data in transit. A CloudFront distribution using the default certificate can't prove it owns the domain serving your content, which is exactly the scenario PR.DS controls are designed to prevent. Custom ACM or IAM certificates give clients something verifiable to validate against.

Tool mappings

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

  • Compliance.tf Control: cloudfront_distribution_use_custom_ssl_certificate

  • AWS Config Managed Rule: CLOUDFRONT_CUSTOM_SSL_CERTIFICATE

  • Checkov Check: CKV2_AWS_42

  • Powerpipe Control: aws_compliance.control.cloudfront_distribution_use_custom_ssl_certificate

  • Prowler Check: cloudfront_distributions_custom_ssl_certificate

  • AWS Security Hub Control: CloudFront.7

  • KICS Query: 3a1e94df-6847-4c0e-a3b6-6c6af4e128ef

Last reviewed: 2026-03-09