Back to Checks
CloudFront distribution uses Origin Access Control (OAC) for all S3 origins
cloudfront_distributions_s3_origin_access_control
Service: cloudfrontSeverity: medium
OfficialBuilt-inVerified
Categories:trust-boundariesinternet-exposed
Resource Type:AwsCloudFrontDistribution
CloudFront distributions with Amazon S3 origins are expected to use Origin Access Control (OAC) on each S3 origin.
The evaluation inspects distributions that include s3_origin_config and identifies S3 origins that lack an associated OAC.
Risk
Without OAC, S3 objects can be reached outside CloudFront, bypassing edge controls and weakening confidentiality and integrity.
- Direct access enables data exfiltration
- Loss of WAF, rate-limiting, and detailed logging; cost abuse
- Limited support for signed writes and SSE-KMS, increasing tampering risk
Run this check with Prowler
Run in Prowler CloudRun
prowler aws --checks cloudfront_distributions_s3_origin_access_controlRecommendation
Enable Origin Access Control for all S3 origins and keep buckets non-public.
Apply least privilege: scope bucket and key permissions to CloudFront and the intended distribution. Ensure origin requests are signed, migrate from legacy OAI, and use defense in depth with WAF and monitoring to protect and observe access.
Remediation
CLI
aws cloudfront create-origin-access-control --origin-access-control-config '{Name":"<example_resource_name>","SigningProtocol":"sigv4","SigningBehavior":"always","OriginAccessControlOriginType":"s3"}' && aws cloudfront get-distribution-config --id <DISTRIBUTION_ID> --output json > current-config.json && echo 'Manually edit current-config.json to add OriginAccessControlId to S3 origins, then run:' && echo 'aws cloudfront update-distribution --id <DISTRIBUTION_ID> --distribution-config file://current-config.json --if-match $(aws cloudfront get-distribution-config --id <DISTRIBUTION_ID> --query "ETag" --output text)'Terraform
# Terraform: attach OAC to S3 origin in a CloudFront distribution
resource "aws_cloudfront_origin_access_control" "oac" {
name = "<example_resource_name>"
origin_access_control_origin_type = "s3"
signing_behavior = "always"
signing_protocol = "sigv4"
}
resource "aws_cloudfront_distribution" "dist" {
enabled = true
origin {
domain_name = "<example_bucket>.s3.amazonaws.com"
origin_id = "s3-<example_resource_id>"
origin_access_control_id = aws_cloudfront_origin_access_control.oac.id # CRITICAL: attaches OAC to the S3 origin to satisfy the check
s3_origin_config {
origin_access_identity = "" # CRITICAL: disable OAI when using OAC
}
}
default_cache_behavior {
target_origin_id = "s3-<example_resource_id>"
viewer_protocol_policy = "redirect-to-https"
cache_policy_id = "658327ea-f89d-4fab-a63d-7e88639e58f6"
}
}NativeIaC
# CloudFormation: attach OAC to S3 origin in a CloudFront distribution
Resources:
ExampleOAC:
Type: AWS::CloudFront::OriginAccessControl
Properties:
OriginAccessControlConfig:
Name: <example_resource_name>
OriginAccessControlOriginType: s3
SigningBehavior: always
SigningProtocol: sigv4
ExampleDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Enabled: true
Origins:
- Id: s3-<example_resource_id>
DomainName: <example_bucket>.s3.amazonaws.com
OriginAccessControlId: !Ref ExampleOAC # CRITICAL: attaches OAC to the S3 origin to satisfy the check
S3OriginConfig:
OriginAccessIdentity: "" # CRITICAL: disable OAI when using OAC
DefaultCacheBehavior:
TargetOriginId: s3-<example_resource_id>
ViewerProtocolPolicy: redirect-to-https
CachePolicyId: 658327ea-f89d-4fab-a63d-7e88639e58f6Other
1In the AWS Console, open CloudFront and go to Security > Origin access > Origin access control (OAC). Click Create control setting, choose Origin type S3, keep Sign requests, and create the OAC.
2Open your CloudFront distribution, go to the Origins tab.
3For each S3 origin: click Edit, select Origin access control settings (recommended), choose the OAC created in step 1, and Save changes.
4Repeat step 3 for all S3 origins in the distribution.
Check Code
from prowler.lib.check.models import Check, Check_Report_AWS
from prowler.providers.aws.services.cloudfront.cloudfront_client import (
cloudfront_client,
)
class cloudfront_distributions_s3_origin_access_control(Check):
def execute(self):
findings = []
for distribution in cloudfront_client.distributions.values():
report = Check_Report_AWS(metadata=self.metadata(), resource=distribution)
if any(origin.s3_origin_config for origin in distribution.origins):
s3_buckets_with_no_oac = []
report.status = "PASS"
report.status_extended = f"CloudFront Distribution {distribution.id} is using origin access control (OAC) for S3 origins."
for origin in distribution.origins:
if (
origin.s3_origin_config != {}
and origin.origin_access_control == ""
):
s3_buckets_with_no_oac.append(origin.id)
if s3_buckets_with_no_oac:
report.status = "FAIL"
report.status_extended = f"CloudFront Distribution {distribution.id} is not using origin access control (OAC) in S3 origins {', '.join(s3_buckets_with_no_oac)}."
findings.append(report)
return findingsReferences
- https://www.trendmicro.com/trendaivisiononecloudriskmanagement/knowledge-base/aws/CloudFront/s3-origin.html
- https://repost.aws/knowledge-center/cloudfront-access-to-amazon-s3
- https://docs.aws.amazon.com/securityhub/latest/userguide/cloudfront-controls.html#cloudfront-13
- https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-s3.html