AWS Security Hub · CloudFront
CloudFront.13: Distributions should use origin access control
Written and reviewed by Emnode · Last reviewed
What does AWS Security Hub CloudFront.13 check?
CloudFront.13 checks that a distribution with an S3 origin uses origin access control (OAC). It reports FAILED when the S3 origin has no OAC configured. OAC supersedes the legacy origin access identity (OAI) and is the recommended mechanism for fencing an S3 bucket behind its distribution.
Why does CloudFront.13 matter?
Without OAC the S3 bucket keeps its own URL — a second front door that bypasses CloudFront entirely, and with it your WAF rules, signed URLs, geo-restrictions, and access logging. Anyone who learns the bucket name can pull content directly, skipping every protection you applied at the edge, and direct-to-bucket requests never appear in CloudFront logs, leaving a forensics gap after an incident.
How do I fix CloudFront.13?
- Create an origin access control with `SigningBehavior` set to `always`.
- Attach the OAC to the distribution's S3 origin via the ETag-guarded `update-distribution` flow.
- Lock the bucket policy to grant `s3:GetObject` to the `cloudfront.amazonaws.com` principal, scoped by an `aws:SourceArn` condition naming the distribution ARN; for SSE-KMS buckets add a matching `kms:Decrypt` statement to the key policy.
- Enforce OAC in your distribution IaC so new S3-origin distributions ship compliant.
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.13 a false positive?
OAI distributions still function, so teams assume they're covered — but CloudFront.13 expects modern OAC, and OAI can't sign SSE-KMS reads or all SigV4-required requests, so an OAI-only distribution still fails.
More CloudFront controls
- CloudFront.1 No default root object, exposing the distribution listing
- CloudFront.3 Distributions should require encryption in transit
- CloudFront.5 Distributions should have logging enabled
- CloudFront.6 Distributions should have WAF enabled
- CloudFront.9 Distributions should encrypt traffic to custom origins
- CloudFront.10 No deprecated SSL protocols to custom origins
- CloudFront.12 A distribution points at a non-existent S3 origin (takeover risk)
- CloudFront.15 Distributions should use recommended TLS policy
- CloudFront.16 OAC for Lambda function URL origins
- CloudFront.17 Use trusted key groups for signed URLs/cookies