aws-cloudfront-oac-private-reach

A CloudFront distribution configured with OAC or OAI on an S3 origin can reach a private (non-public) S3 bucket on behalf of viewers. The distribution acts as a controlled gateway to otherwise-private data.

derived aws emits PrivateReachability

match (record)

{ "field": "DistributionConfig.Origins.Items", "resource_type": "AWS::CloudFront::Distribution" }

where

origin.OriginAccessControlId is non-empty (OAC) OR origin.S3OriginConfig.OriginAccessIdentity is non-empty (OAI) origin.DomainName matches *.s3.<region>.amazonaws.com or *.s3.amazonaws.com (REST endpoint, not website endpoint) S3 bucket policy grants s3:GetObject to cloudfront.amazonaws.com (OAC) or the OAI CanonicalUser (OAI)

emit

source typeNetwork
target typeData
source<CloudFront distribution node (acting as the reachability actor via OAC/OAI)>
target<S3 bucket node backing the origin>
conditionsresource_policy service_state
state logicACTIVE when OriginAccessControlId or OriginAccessIdentity is set on the origin AND the S3 bucket policy grants the corresponding principal (cloudfront.amazonaws.com with aws:SourceArn == distribution ARN for OAC, or the OAI CanonicalUser for OAI) s3:GetObject. CONDITIONAL(resource_policy) when the OAC/OAI field is set but the S3 bucket policy has not been updated to grant access (CloudFront will receive 403 from S3 in this state). BLOCKED when the S3 bucket explicitly denies cloudfront.amazonaws.com.

Narrative

CloudFront distribution {source.name} is configured with {oac_or_oai} on its S3 origin {target.name}. CloudFront signs requests as cloudfront.amazonaws.com (OAC) or the OAI canonical user and the S3 bucket policy grants access - the distribution can fetch objects from this otherwise-private bucket on behalf of any viewer. If an attacker can modify the distribution's origin config or the bucket policy, private S3 data may be served publicly via the CDN.

Raw rule rules/derived/aws/cloudfront.yaml

id: aws-cloudfront-oac-private-reach
emits: PrivateReachability
description: A CloudFront distribution configured with OAC or OAI on an S3 origin can reach a private
  (non-public) S3 bucket on behalf of viewers. The distribution acts as a controlled gateway to otherwise-private
  data.
applies_to:
- aws
match_record:
  resource_type: AWS::CloudFront::Distribution
  field: DistributionConfig.Origins.Items
where:
- origin.OriginAccessControlId is non-empty (OAC) OR origin.S3OriginConfig.OriginAccessIdentity is non-empty
  (OAI)
- origin.DomainName matches *.s3.<region>.amazonaws.com or *.s3.amazonaws.com (REST endpoint, not website
  endpoint)
- S3 bucket policy grants s3:GetObject to cloudfront.amazonaws.com (OAC) or the OAI CanonicalUser (OAI)
emit:
  source_type: Network
  target_type: Data
  source: <CloudFront distribution node (acting as the reachability actor via OAC/OAI)>
  target: <S3 bucket node backing the origin>
  state: ACTIVE
  permissions: []
  api_source: cloudfront:GetDistributionConfig + s3:GetBucketPolicy
  evidence_field: DistributionConfig.Origins.Items[*].OriginAccessControlId | S3OriginConfig.OriginAccessIdentity
  conditions:
  - resource_policy
  - service_state
  state_logic: ACTIVE when OriginAccessControlId or OriginAccessIdentity is set on the origin AND the
    S3 bucket policy grants the corresponding principal (cloudfront.amazonaws.com with aws:SourceArn ==
    distribution ARN for OAC, or the OAI CanonicalUser for OAI) s3:GetObject. CONDITIONAL(resource_policy)
    when the OAC/OAI field is set but the S3 bucket policy has not been updated to grant access (CloudFront
    will receive 403 from S3 in this state). BLOCKED when the S3 bucket explicitly denies cloudfront.amazonaws.com.
  derived_from:
  - DistributionConfig.Origins.Items[*].OriginAccessControlId | S3OriginConfig.OriginAccessIdentity observation
  false_positive_note: "OAC SCOPE: If the S3 bucket policy grants s3:GetObject to cloudfront.amazonaws.com\
    \ WITHOUT the aws:SourceArn condition scoped to this distribution's ARN, ANY CloudFront distribution\
    \ (including those in other AWS accounts) can access the bucket by configuring this S3 domain as an\
    \ origin. Flag this as a higher-severity misconfiguration (confidence: 0.95 for the PrivateReachability\
    \ edge plus a ContainsSecret note if the bucket contains sensitive data). OAI is deprecated: OAI uses\
    \ a CanonicalUser ID in the bucket policy; the principal is effectively CloudFront-managed. Still\
    \ emit PrivateReachability \u2014 OAI provides the same private-reach capability as OAC. Website endpoints\
    \ (*.s3-website-*.amazonaws.com) do NOT support OAC/OAI; do NOT emit PrivateReachability for those\
    \ origins. The S3 data-plane CanReadData derivation (if private S3 data becomes public via CDN misconfiguration)\
    \ is the responsibility of s3.yaml + network-chains linchpin, not this rule. Emit the FACT here; let\
    \ the linchpin compose the consequence."
  schema_note: 'PrivateReachability.source is declared as [Compute, Messaging] in edges.yaml; CloudFront
    distributions map to PublicEndpoint (Network class). We emit source_type: Network (PublicEndpoint
    is a Network subtype). This is a known schema deviation: the declared source set should be extended
    to include PublicEndpoint, or the distribution''s OAC/OAI MachineIdentity should be the source (losing
    the distribution->s3 edge semantics in favor of oac->s3). Pending schema extension, we use Network
    (consistent with CanNetworkReach.source) as the most accurate available class. Semantically this edge
    means "the distribution''s OAC/OAI signing mechanism can reach the private S3 endpoint."'
  narrative: "CloudFront distribution {source.name} is configured with {oac_or_oai} on its S3 origin {target.name}.\
    \ CloudFront signs requests as cloudfront.amazonaws.com (OAC) or the OAI canonical user and the S3\
    \ bucket policy grants access \u2014 the distribution can fetch objects from this otherwise-private\
    \ bucket on behalf of any viewer. If an attacker can modify the distribution's origin config or the\
    \ bucket policy, private S3 data may be served publicly via the CDN."
move · open · esc close