1

The problem

I'm trying to deploy an S3 bucket hosting my static website asset and a cloudfront distribution to access it, but the distribution still return a bare xml file for an 'access denied' error:

<Error>
  <Code>AccessDenied</Code>
  <Message>Access Denied</Message>
  <RequestId>5N0Z412GZ0VGV79E</RequestId>
  <HostId>GkpQbOpKeDiaCdFJM7kDq6ouWL/dvdijNu7NseC7KeIIogNabowVrDcfjPZ0xajKpDTx3SmgoEI=</HostId>
</Error>

As this docs page states in the blue Notice alert, I've not made the bucket a website endpoint, this way I can use an OAC to restrict access to its content.

A strange thing is that checking the distribution origin from the web console I see this blue alert, but the copyable policy is the same I found in the bucket permission at the given link.

enter image description here

I have no error during deploy, so it must be a silly configuration error, but it keeps giving me headaches since a week now and I can't figure out what is wrong.

Bucket and object owners corresponds

Since mi website assets are uploaded to the bucket from a different project/pipeline i followed this guide to check if the bucket and the object owners were different but actually corresponds:

> aws s3api list-buckets --query Owner.ID
"3fdbd1e5cad4dd2bbf4c66a3dbaded6b888fdb67ff6aa6e66203a4107fe17b72"

> aws s3api list-objects --bucket my-test-bucket --prefix index.html { "Contents": [ { "Key": "index.html", "LastModified": "2023-01-20T11:05:38+00:00", "ETag": "&quot;52f2df5ddf8c35391f3f15a7614def58&quot;", "Size": 325, "StorageClass": "STANDARD", "Owner": { "ID": "3fdbd1e5cad4dd2bbf4c66a3dbaded6b888fdb67ff6aa6e66203a4107fe17b72" } } ] }

CloudFormation template

Resources:

BucketPolicy: Type: 'AWS::S3::BucketPolicy' DependsOn: - AppBucket - CloudFrontDistribution Properties: Bucket: !Ref AppBucket PolicyDocument: Id: MyPolicy Version: '2012-10-17' Statement: Sid: PolicyForCloudFrontPrivateContent Action: s3:GetObject Effect: Allow Principal: Service: cloudfront.amazonaws.com Condition: StringEquals: AWS:SourceArn: !Sub arn:aws:cloudfront::${AWS::AccountId}:distribution/${CloudFrontDistribution} Resource: !Sub arn:aws:s3:::${AppBucket}/*

CloudFrontDistribution: Type: AWS::CloudFront::Distribution DependsOn: - AppBucket - DefaultCachePolicy - DistributionOAC Properties: DistributionConfig: Enabled: true Origins: - Id: AppBucket DomainName: !GetAtt AppBucket.DomainName OriginPath: /* S3OriginConfig: {} OriginAccessControlId: !Ref DistributionOAC DefaultRootObject: index.html DefaultCacheBehavior: ViewerProtocolPolicy: redirect-to-https TargetOriginId: AppBucket CachePolicyId: !Ref DefaultCachePolicy

DistributionOAC: Type: AWS::CloudFront::OriginAccessControl Properties: OriginAccessControlConfig: Name: ExampleOAC OriginAccessControlOriginType: s3 SigningBehavior: always SigningProtocol: sigv4

AppBucket: Type: 'AWS::S3::Bucket' Properties: BucketName: 'test-spa-stack-bucket-app' PublicAccessBlockConfiguration: BlockPublicAcls : false BlockPublicPolicy : false IgnorePublicAcls : false RestrictPublicBuckets : false

DefaultCachePolicy: Type: AWS::CloudFront::CachePolicy Properties: CachePolicyConfig: Name: test-cache-policy DefaultTTL: 10 MaxTTL: 10 MinTTL: 1 ParametersInCacheKeyAndForwardedToOrigin: CookiesConfig: CookieBehavior: none EnableAcceptEncodingBrotli: true EnableAcceptEncodingGzip: true HeadersConfig: HeaderBehavior: none QueryStringsConfig: QueryStringBehavior: none

fudo
  • 141
  • I haven't done this from a launch template yet, but from the GUI you can check that the S3 Bucket Policy (on the bucket) allows access for the CloudFront Access Origin. It should be the policy you get by "copying the policy" in the blue box. Without this CloudFront cannot access the contents of your S3 bucket. If you are using the current defaults for S3, the bucket is private and CloudFront cannot read from it, hence the 403 response you are seeing. – Tim P Jan 26 '23 at 03:30
  • I just tried it, I copied the policy from the distribution origin page and copied in the bucket settings, but it still not working. I can't understand if i wrongly set some other configuration, but checking at any online docs it looks correct to me. – fudo Jan 26 '23 at 14:07
  • An S3 403 response can also be returned when the object does not actually exist. Are you sure the content you are trying to access is actually in S3 and is in the path you are using. If you specified a prefix in the Origin, that will be added to the S3 request. – Tim P Jan 27 '23 at 14:15
  • Yes, i'm sure the object exists – fudo Jan 27 '23 at 15:35

2 Answers2

0

I had the same error. In my case I had set the default root object on the Distribution (General > Settings) to /index.html and I also set the origin path (Origins > my s3 origin) to /index.html. I only needed to set the object as index.html on the Distribution for it to start responding as expected.

This helped me discover the problem.

-1

Ok, I found a YT video that worked from cloud console, then I replicated it via CloudFormation stack template.

I think that my problem could be caused from either of these configurations:

  • bucket encription: I read somewhere (sorry I can't find the exact page) that CloudFront distribution cannot (directly) read bucket objects if encripted with anything different from SSE-S3, and since I omitted that configuration it probably did fallback on a non-compatible configuration
  • objects ownership: here too I forgot to add the cuket owner enforced policy
  • distribution accepted http version: here I accepted v.2

working template

Resources:
  BucketPolicy:
    Type: 'AWS::S3::BucketPolicy'
    DependsOn:
      - AppBucket
      - CloudFrontDistribution
    Properties:
      Bucket: !Ref AppBucket
      PolicyDocument:
        Id: PolicyForCloudFrontPrivateContent
        Version: '2008-10-17'
        Statement:
          Sid: AllowCloudFrontServicePrincipal
          Action: s3:GetObject
          Effect: Allow
          Principal:
            Service: cloudfront.amazonaws.com
          Condition:
            StringEquals:
              AWS:SourceArn: !Sub arn:aws:cloudfront::${AWS::AccountId}:distribution/${CloudFrontDistribution}
          Resource: !Sub arn:aws:s3:::${AppBucket}/*

CloudFrontDistribution: Type: AWS::CloudFront::Distribution DependsOn: - AppBucket - DistributionOAC - LogsBucket Properties: DistributionConfig: Enabled: true HttpVersion: http2 Origins: - Id: AppBucket DomainName: !GetAtt AppBucket.DomainName S3OriginConfig: {} OriginAccessControlId: !Ref DistributionOAC DefaultRootObject: index.html DefaultCacheBehavior: Compress: true ViewerProtocolPolicy: allow-all TargetOriginId: AppBucket CachePolicyId: 658327ea-f89d-4fab-a63d-7e88639e58f6 # default CachingOptimized Logging: Bucket: !GetAtt LogsBucket.DomainName IncludeCookies: true Prefix: distribution/

AppBucket: Type: 'AWS::S3::Bucket' DependsOn: - LogsBucket Properties: BucketName: 'test-spa-stack-bucket-app' OwnershipControls: Rules: - ObjectOwnership: BucketOwnerEnforced PublicAccessBlockConfiguration: BlockPublicAcls : true BlockPublicPolicy : true IgnorePublicAcls : true RestrictPublicBuckets : true BucketEncryption: ServerSideEncryptionConfiguration: - ServerSideEncryptionByDefault: SSEAlgorithm: AES256 LoggingConfiguration: DestinationBucketName: !Ref LogsBucket LogFilePrefix: app/

DistributionOAC: Type: AWS::CloudFront::OriginAccessControl Properties: OriginAccessControlConfig: Name: test-spa-distribution-oac OriginAccessControlOriginType: s3 SigningBehavior: always SigningProtocol: sigv4

LogsBucket: Type: 'AWS::S3::Bucket' Properties: BucketName: 'test-spa-stack-bucket-logs' PublicAccessBlockConfiguration: BlockPublicAcls : true BlockPublicPolicy : true IgnorePublicAcls : true RestrictPublicBuckets : true AccessControl: LogDeliveryWrite VersioningConfiguration: Status: Enabled BucketEncryption: ServerSideEncryptionConfiguration: - ServerSideEncryptionByDefault: SSEAlgorithm: 'AES256'

fudo
  • 141