How to set a BucketPolicy through cloudformation after April 2023 ACL restriction

798 views Asked by At

I'm following testdrive.io's serverless-fastapi course. It uses cloudformation to setup the bucket and bucket policy. The bucket is created just fine, however there are issues creating the bucket policy. First I had to comment out # AccessControl: PublicRead due to the new policy in April (see post). However, now it is failing due to this error:

API: s3:PutBucketPolicy Access Denied

I'm deploying the serverless.yml file via github and have created a user for github that has the following permissions: AdministratorAccess

This bucket should be open to the public as it will host the files for a front end Vue webframework. How does one create the bucket policy for that?

# serverless.yml 
service: tasks-ui

frameworkVersion: "3"
useDotenv: true

provider:
  name: aws
  region: ${opt:region, 'us-east-2'}
  stage: ${opt:stage, 'development'}

plugins:
  - serverless-s3-sync

custom:
  stage: ${opt:stage, self:provider.stage}
  bucketName: ${self:custom.stage}-tasks-api-mp
  s3Sync:
    # A simple configuration for copying static assets!
    - bucketName: ${self:custom.bucketName}
      localDir: dist

resources:
  Resources:
    TasksAPIBucket:
      Type: AWS::S3::Bucket
      Properties:
        BucketName: ${self:custom.bucketName}
        # AccessControl: PublicRead
        WebsiteConfiguration:
          IndexDocument: index.html
          ErrorDocument: error.html
    TasksAPIBucketPolicy:
      Type: AWS::S3::BucketPolicy
      Properties:
        Bucket: !Ref TasksAPIBucket
        PolicyDocument:
          Version: "2012-10-17"
          Statement:
            - Sid: "PublicReadGetObject"
              Effect: "Allow"
              Principal: "*"
              Action: "s3:GetObject"
              Resource:
                Fn::Join:
                  - ""
                  - - "arn:aws:s3:::"
                    - !Ref TasksAPIBucket
                    - "/*"
  Outputs:
    TasksAPIBucketName:
      Value: !Ref TasksAPIBucket
      Export:
        Name: s3-${self:custom.bucketName}-name
    TasksAPIBucketArn:
      Value: !GetAtt TasksAPIBucket.Arn
      Export:
        Name: s3-${self:custom.bucketName}-arn

2

There are 2 answers

0
John Rotenstein On

Receiving a s3:PutBucketPolicy Access Denied error typically indicates that either:

  • You do not hav permission to set the Bucket Policy, or
  • The bucket has S3 Block Public Access enabled

Your account possibly has Block Public Access enabled by default, so each new bucket receives the setting.

From AWS::S3::Bucket PublicAccessBlockConfiguration - AWS CloudFormation:

  BlockPublicAcls: Boolean
  BlockPublicPolicy: Boolean
  IgnorePublicAcls: Boolean
  RestrictPublicBuckets: Boolean

You want to change the values that refer to Bucket Policies.

0
Brandon Friar On

Here is the serverless.yml file I used and it worked for me

service: tasks-ui

frameworkVersion: '3'
useDotenv: true


provider:
  name: aws
  region: ${opt:region, 'us-west-2'}
  stage: ${opt:stage, 'development'}



plugins:
  - serverless-s3-sync


custom:
  stage: ${opt:stage, self:provider.stage}
  bucketName: ${self:custom.stage}-tasks-api-friar
  s3Sync:
    # A simple configuration for copying static assets
    - bucketName: ${self:custom.bucketName}
      localDir: dist


resources:
  Resources:
    TasksAPIBucket:
      Type: AWS::S3::Bucket
      Properties:
        BucketName: ${self:custom.bucketName}
        #AccessControl: PublicRead
        PublicAccessBlockConfiguration:
          BlockPublicAcls: false
        OwnershipControls:
          Rules:
            - ObjectOwnership: ObjectWriter
        WebsiteConfiguration:
          IndexDocument: index.html
          ErrorDocument: error.html
    TasksAPIBucketPolicy:
      Type: AWS::S3::BucketPolicy
      Properties:
        Bucket: !Ref TasksAPIBucket
        PolicyDocument:
          Version: "2012-10-17"
          Statement:
            - Sid: "PublicReadGetObject"
              Effect: "Allow"
              Principal: "*"
              Action: "s3:GetObject"
              Resource:
                Fn::Join:
                  - ""
                  - - "arn:aws:s3:::"
                    - !Ref TasksAPIBucket
                    - "/*"
  Outputs:
    TasksAPIBucketName:
      Value: !Ref TasksAPIBucket
      Export:
        Name: s3-${self:custom.bucketName}-name
    TasksAPIBucketArn:
      Value: !GetAtt TasksAPIBucket.Arn
      Export:
        Name: s3-${self:custom.bucketName}-arn