CloudFront distributions should use the recommended TLS security policy
CloudFront distributions that allow TLS 1.0 or 1.1 expose traffic to known protocol weaknesses including BEAST, POODLE, and downgrade attacks. Both versions were formally deprecated by RFC 8996 in March 2021, and major browsers have dropped support for them. Setting TLSv1.2_2021 as the minimum restricts connections to TLS 1.2 with strong ciphers, eliminating CBC-mode cipher suites that have been repeatedly targeted.
Running an older policy also creates friction during audits and penetration tests, where anything below TLS 1.2 gets flagged as a finding regardless of compensating controls. Enforcing the policy at the distribution level avoids that overhead entirely.
Retrofit consideration
Changing the minimum TLS policy can break clients that don't support TLS 1.2, including very old Android devices and custom HTTP libraries compiled against outdated OpenSSL versions. Check CloudFront access logs for TLS version distribution before switching.
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"
viewer_certificate = {
minimum_protocol_version = "TLSv1.2_2021"
}
}
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"
}
}
wait_for_deployment = false
web_acl_id = "arn:aws:wafv2:us-east-1:123456789012:regional/webacl/example/12345678-1234-1234-1234-123456789012"
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"
}
}
What this control checks
In the aws_cloudfront_distribution resource, viewer_certificate must set minimum_protocol_version to "TLSv1.2_2021" or a newer policy. "TLSv1.2_2019" is older and fails this control because it still permits weaker cipher suites. When cloudfront_default_certificate is true (the *.cloudfront.net domain), AWS manages the TLS policy and minimum_protocol_version is silently ignored, which may still cause a failure depending on the evaluator. For a reliable pass, use a custom ACM certificate: set acm_certificate_arn, ssl_support_method = "sni-only", and minimum_protocol_version = "TLSv1.2_2021". Any of the following values fail: "TLSv1", "TLSv1_2016", "TLSv1.1_2016", "TLSv1.2_2018", or an omitted minimum_protocol_version.
Common pitfalls
Default certificate ignores minimum_protocol_version
Using
cloudfront_default_certificate = truehands TLS policy control to AWS, sominimum_protocol_versionis silently ignored. Distributions using the shared*.cloudfront.netcertificate may still fail this control. Switch to a custom ACM certificate withacm_certificate_arnto explicitly own the policy setting.Confusing policy name ordering
All policies named
TLSv1.2_*require TLS 1.2, but they differ on cipher suites.TLSv1.2_2018andTLSv1.2_2019both still permit CBC ciphers.TLSv1.2_2021is the first in the series to remove them entirely. The year suffix matters.Legacy vip ssl_support_method requires dedicated IP
The
"vip"value forssl_support_methodprovisions a dedicated IP address for SSL and incurs extra CloudFront charges, but has no effect on which TLS version is negotiated. It's a common mistake when first adding a custom certificate: old Terraform snippets often specify"vip"without flagging the cost implication. Use"sni-only"unless you have a specific reason not to.Terraform default value may not match recommended policy
Omit
minimum_protocol_versionand behavior falls back to AWS defaults, which vary by certificate mode and may not satisfy this control. Always set it explicitly in theviewer_certificateblock.
Audit evidence
Auditors expect Config rule evaluation results showing each distribution as COMPLIANT, or Security Hub findings with status PASSED for the relevant CloudFront controls. The CloudFront console Security Policy column should list TLSv1.2_2021 or later for every distribution. The CLI command aws cloudfront get-distribution-config --id <ID> returns ViewerCertificate.MinimumProtocolVersion for point-in-time verification. Historical compliance comes from Config timeline snapshots or periodic Security Hub exports stored in S3.
Related controls
Tool mappings
Use these identifiers to cross-reference this control across tools, reports, and evidence.
Compliance.tf Control:
cloudfront_distribution_uses_recommended_tls_security_policyAWS Config Managed Rules:
CLOUDFRONT_SECURITY_POLICY_CHECK,CLOUDFRONT_SSL_POLICY_CHECKCheckov Check:
CKV_AWS_174Powerpipe Control:
aws_compliance.control.cloudfront_distribution_uses_recommended_tls_security_policyAWS Security Hub Control:
CloudFront.15KICS Queries:
00e5e55e-c2ff-46b3-a757-a7a1cd802456,3a1e94df-6847-4c0e-a3b6-6c6af4e128efTrivy Check:
AWS-0013
Last reviewed: 2026-03-09