Skip to main content
emnode / learn
Compliance Medium severity

AWS Security Hub · CloudFront

CloudFront.3: Distributions should require encryption in transit

Written and reviewed by Emnode · Last reviewed

What does AWS Security Hub CloudFront.3 check?

CloudFront.3 checks that a distribution requires encryption in transit from viewers. It reports FAILED when `ViewerProtocolPolicy` is set to `allow-all` on the default cache behaviour or any path-pattern behaviour. The two passing values are `redirect-to-https` and `https-only`.

Why does CloudFront.3 matter?

With `allow-all`, any request that arrives over plain HTTP travels in clear text between the viewer and the edge. Anyone on the network path — hostile Wi-Fi, a compromised router, a sniffing ISP — can read or rewrite cookies, query parameters, tokens, and response bodies. It also maps directly to PCI DSS 4.2.1 and a long list of NIST data-in-transit controls, so an open finding is a citable audit gap.

How do I fix CloudFront.3?

  1. Enumerate every cache behaviour, not just the default — one stray `allow-all` path pattern fails the whole distribution.
  2. Choose `redirect-to-https` for browser-served paths and `https-only` for API/machine-to-machine paths where no client should ever speak HTTP.
  3. Apply the change via the read-modify-write `update-distribution` flow with `--if-match <ETag>`, then wait for the edge redeploy.
  4. Keep the `cloudfront-viewer-policy-https` Config rule enabled and bake a non-`allow-all` default into IaC so new behaviours can't reopen it.

Remediation script · bash

# 1. Lock an S3 origin: only THIS distribution may read the bucket.
cat > bucket-policy.json <<'JSON'
{
  "Version": "2012-10-17",
  "Statement": [{
    "Sid": "AllowCloudFrontServicePrincipalReadOnly",
    "Effect": "Allow",
    "Principal": { "Service": "cloudfront.amazonaws.com" },
    "Action": "s3:GetObject",
    "Resource": "arn:aws:s3:::my-downloads-bucket/*",
    "Condition": { "StringEquals": {
      "AWS:SourceArn": "arn:aws:cloudfront::111122223333:distribution/E2QWRUHAPOMQZL"
    } }
  }]
}
JSON
aws s3api put-bucket-policy --bucket my-downloads-bucket --policy file://bucket-policy.json

# 2. Raise the minimum TLS version (the field is nested in ViewerCertificate, so send the whole config back).
aws cloudfront get-distribution-config --id E2QWRUHAPOMQZL > dist.json
ETAG=$(python3 -c "import json;print(json.load(open('dist.json'))['ETag'])")
# ... edit dist.json: ViewerCertificate.MinimumProtocolVersion = TLSv1.2_2021, ViewerProtocolPolicy = redirect-to-https ...
aws cloudfront update-distribution --id E2QWRUHAPOMQZL \
  --distribution-config file://distribution-config.json --if-match "$ETAG"

# 3. Confirm the second door is shut: a raw S3 GET should now return 403.
curl -s -o /dev/null -w '%{http_code}\n' https://my-downloads-bucket.s3.amazonaws.com/file.pdf

Full walkthrough (console steps, edge cases and verification) in the lesson Protect CloudFront distributions and origins.

Is CloudFront.3 a false positive?

A distribution whose default behaviour is already `redirect-to-https` can still fail because the control inspects every path-pattern behaviour — a forgotten legacy `/api/*` left on `allow-all` keeps it FAILED.

Part of the learning path Lock down access