Skip to main content

CloudFront Distribution Uses a Custom SSL/TLS Certificate

Overview

This check verifies that your CloudFront distributions use a custom SSL/TLS certificate instead of the default *.cloudfront.net certificate. When you use your own domain name with CloudFront, you need a custom certificate to enable secure HTTPS connections.

Risk

Using the default CloudFront certificate with your own domain name creates several problems:

  • Broken HTTPS: Browsers will show security warnings because the certificate does not match your domain
  • Lost user trust: Visitors may avoid your site or see errors when connecting
  • Reduced security control: You cannot enforce modern TLS settings or security headers on your domain
  • Compliance gaps: Many security frameworks require proper certificate management

Remediation Steps

Prerequisites

You will need:

  • Access to the AWS Console with permissions to modify CloudFront distributions
  • An SSL/TLS certificate in AWS Certificate Manager (ACM) that covers your domain
  • The certificate must be in the us-east-1 region (required for CloudFront)
How to request an ACM certificate

If you do not have a certificate yet:

  1. Go to the AWS Certificate Manager console in us-east-1
  2. Click Request a certificate
  3. Choose Request a public certificate
  4. Enter your domain name (e.g., www.example.com or *.example.com for wildcard)
  5. Choose DNS validation (recommended) or Email validation
  6. Complete the validation process
  7. Wait for the certificate status to show Issued

AWS Console Method

  1. Open the CloudFront console at https://console.aws.amazon.com/cloudfront/
  2. Select the distribution you want to update
  3. Click the General tab, then click Edit
  4. In the Alternate domain name (CNAME) field, add your custom domain (e.g., www.example.com)
  5. Under Custom SSL certificate, select your ACM certificate from the dropdown
  6. For Security policy, choose TLSv1.2_2021 or newer
  7. Click Save changes
  8. Wait for the distribution status to change from "Deploying" to "Deployed" (this may take several minutes)

Important: After updating CloudFront, update your DNS records to point your domain to the CloudFront distribution domain name.

AWS CLI (optional)

Step 1: Find your distribution ID

aws cloudfront list-distributions \
--query "DistributionList.Items[*].[Id,DomainName,Comment]" \
--output table \
--region us-east-1

Step 2: Get the current configuration

aws cloudfront get-distribution-config \
--id <DISTRIBUTION_ID> \
--region us-east-1 \
--output json > distribution-config.json

Step 3: Extract the ETag and modify the configuration

# Extract the ETag (needed for updates)
ETAG=$(aws cloudfront get-distribution-config \
--id <DISTRIBUTION_ID> \
--query "ETag" \
--output text \
--region us-east-1)

echo "ETag: $ETAG"

Edit distribution-config.json to:

  1. Remove the top-level ETag field
  2. Keep only the DistributionConfig object contents
  3. Add your domain to the Aliases array
  4. Update ViewerCertificate section:
{
"ViewerCertificate": {
"ACMCertificateArn": "arn:aws:acm:us-east-1:123456789012:certificate/abc12345-1234-1234-1234-abc123456789",
"SSLSupportMethod": "sni-only",
"MinimumProtocolVersion": "TLSv1.2_2021",
"CloudFrontDefaultCertificate": false
},
"Aliases": {
"Quantity": 1,
"Items": ["www.example.com"]
}
}

Step 4: Update the distribution

aws cloudfront update-distribution \
--id <DISTRIBUTION_ID> \
--distribution-config file://distribution-config.json \
--if-match "$ETAG" \
--region us-east-1

Step 5: Wait for deployment

aws cloudfront wait distribution-deployed \
--id <DISTRIBUTION_ID> \
--region us-east-1
CloudFormation (optional)
AWSTemplateFormatVersion: '2010-09-09'
Description: CloudFront distribution with custom SSL/TLS certificate

Parameters:
DomainName:
Type: String
Description: Your custom domain name (e.g., www.example.com)
CertificateArn:
Type: String
Description: ARN of ACM certificate in us-east-1
OriginDomainName:
Type: String
Description: Origin domain name (e.g., your S3 bucket or ALB)

Resources:
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Enabled: true
Comment: Distribution with custom SSL certificate
Aliases:
- !Ref DomainName
Origins:
- Id: PrimaryOrigin
DomainName: !Ref OriginDomainName
CustomOriginConfig:
HTTPPort: 80
HTTPSPort: 443
OriginProtocolPolicy: https-only
OriginSSLProtocols:
- TLSv1.2
DefaultCacheBehavior:
TargetOriginId: PrimaryOrigin
ViewerProtocolPolicy: redirect-to-https
AllowedMethods:
- GET
- HEAD
CachedMethods:
- GET
- HEAD
ForwardedValues:
QueryString: false
Cookies:
Forward: none
Compress: true
ViewerCertificate:
AcmCertificateArn: !Ref CertificateArn
SslSupportMethod: sni-only
MinimumProtocolVersion: TLSv1.2_2021
HttpVersion: http2
PriceClass: PriceClass_100

Outputs:
DistributionId:
Description: CloudFront Distribution ID
Value: !Ref CloudFrontDistribution
DistributionDomainName:
Description: CloudFront Distribution Domain Name
Value: !GetAtt CloudFrontDistribution.DomainName

Deploy with:

aws cloudformation deploy \
--template-file template.yaml \
--stack-name cloudfront-custom-ssl \
--parameter-overrides \
DomainName=www.example.com \
CertificateArn=arn:aws:acm:us-east-1:123456789012:certificate/abc12345 \
OriginDomainName=my-bucket.s3.amazonaws.com \
--region us-east-1
Terraform (optional)
# CloudFront distribution with custom SSL/TLS certificate

variable "domain_name" {
description = "Your custom domain name (e.g., www.example.com)"
type = string
}

variable "certificate_arn" {
description = "ARN of ACM certificate in us-east-1"
type = string
}

variable "origin_domain_name" {
description = "Origin domain name (e.g., S3 bucket or ALB)"
type = string
}

resource "aws_cloudfront_distribution" "main" {
enabled = true
comment = "Distribution with custom SSL certificate"
aliases = [var.domain_name]
http_version = "http2"
price_class = "PriceClass_100"

origin {
domain_name = var.origin_domain_name
origin_id = "primary-origin"

custom_origin_config {
http_port = 80
https_port = 443
origin_protocol_policy = "https-only"
origin_ssl_protocols = ["TLSv1.2"]
}
}

default_cache_behavior {
target_origin_id = "primary-origin"
viewer_protocol_policy = "redirect-to-https"
allowed_methods = ["GET", "HEAD"]
cached_methods = ["GET", "HEAD"]
compress = true

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

viewer_certificate {
acm_certificate_arn = var.certificate_arn
ssl_support_method = "sni-only"
minimum_protocol_version = "TLSv1.2_2021"
}

restrictions {
geo_restriction {
restriction_type = "none"
}
}
}

output "distribution_id" {
description = "CloudFront Distribution ID"
value = aws_cloudfront_distribution.main.id
}

output "distribution_domain_name" {
description = "CloudFront Distribution Domain Name"
value = aws_cloudfront_distribution.main.domain_name
}

Apply with:

terraform apply \
-var="domain_name=www.example.com" \
-var="certificate_arn=arn:aws:acm:us-east-1:123456789012:certificate/abc12345" \
-var="origin_domain_name=my-bucket.s3.amazonaws.com"

Verification

After making changes, verify the fix:

  1. In the CloudFront console, select your distribution
  2. Check that:
    • Your domain appears under Alternate domain names (CNAMEs)
    • SSL certificate shows your custom certificate (not "Default CloudFront certificate")
    • Security policy shows TLSv1.2_2021 or newer
  3. Test your domain in a browser using https://your-domain.com and verify no certificate warnings appear
CLI verification commands
# Check distribution SSL configuration
aws cloudfront get-distribution \
--id <DISTRIBUTION_ID> \
--query "Distribution.DistributionConfig.ViewerCertificate" \
--output yaml \
--region us-east-1

# Expected output should show:
# ACMCertificateArn: arn:aws:acm:us-east-1:...
# CloudFrontDefaultCertificate: false
# MinimumProtocolVersion: TLSv1.2_2021
# SSLSupportMethod: sni-only

# Test SSL certificate from command line
openssl s_client -connect your-domain.com:443 -servername your-domain.com < /dev/null 2>/dev/null | openssl x509 -noout -subject -dates

Additional Resources

Notes

  • Certificate region: ACM certificates for CloudFront must be in the us-east-1 region, even if your other resources are in different regions
  • DNS configuration: After enabling a custom certificate, you must configure DNS (Route 53 or your DNS provider) to point your domain to the CloudFront distribution
  • SNI requirement: The sni-only SSL support method is recommended and has no additional cost. The alternative vip method requires dedicated IP addresses and incurs extra charges
  • Certificate renewal: ACM certificates automatically renew if DNS validation is configured correctly
  • Propagation time: CloudFront configuration changes typically take 5-15 minutes to deploy globally