Klaas
Klaas

Reputation: 133

How to create a bucket with Public Read Access?

I´d like to enable Public Read-Access on all items in my Bucket that are in the "public" folder in the serverless.yml file.

Currently this is definition code i use to declare my bucket. Its a bit of copy and paste from one of the serverless-stack examples.

Resources:
  AttachmentsBucket:
    Type: AWS::S3::Bucket
    Properties:
      AccessControl: PublicRead
      # Set the CORS policy
      BucketName: range-picker-bucket-${self:custom.stage}
      CorsConfiguration:
        CorsRules:
          -
            AllowedOrigins:
              - '*'
            AllowedHeaders:
              - '*'
            AllowedMethods:
              - GET
              - PUT
              - POST
              - DELETE
              - HEAD
            MaxAge: 3000

# Print out the name of the bucket that is created
Outputs:
  AttachmentsBucketName:
    Value:
      Ref: AttachmentsBucket

Now when i try to use a url for a file, it returns access denied. I manually have to set the public read permission for every file by hand in the aws-s3 web interface.

What am i doing wrong?

Upvotes: 13

Views: 5756

Answers (4)

ChrisRich
ChrisRich

Reputation: 8716

This approach worked for me:

 Resources:
    StaticAssetsBucket:
      Type: AWS::S3::Bucket
      Properties:
        BucketName: ${sls:stage}.${self:service}.static-assets
        AccessControl: PublicRead
    PublicBucketPolicy:
      Type: AWS::S3::BucketPolicy
      Properties:
        Bucket: !Ref StaticAssetsBucket
        PolicyDocument:
          Version: "2012-10-17"
          Statement:
            - Effect: Allow
              Action:
                - "s3:GetObject"
              Resource:
                - !Sub "${StaticAssetsBucket.Arn}/*"
              Principal: "*"

Upvotes: 0

Max Ivanov
Max Ivanov

Reputation: 6561

Accepted answer didn't work for me. CloudFormation failed to update the resource with the error:

Action does not apply to any resource(s) in statement (Service: Amazon S3; Status Code: 400; Error Code: MalformedPolicy; Request ID: <...>; S3 Extended Request ID: <...>; Proxy: null)

It appears the wildcard was missing in the resource definition. Full snippet that worked for me:

PublicBucket:
  Type: AWS::S3::Bucket
  Properties:
    BucketName: 'public-bucket-name'

PublicBucketPolicy:
  Type: AWS::S3::BucketPolicy
  Properties:
    Bucket: !Ref PublicBucket
    PolicyDocument:
      Version: '2012-10-17'
      Statement:
        - Effect: Allow
          Action:
            - 's3:GetObject'
          Resource:
            - !Join ['/', [!GetAtt [PublicBucket, Arn], '*']]
          Principal: '*'

Upvotes: 7

CSSian
CSSian

Reputation: 1661

As the others have said, you need to implement a Bucket Policy such as this one:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicReadForGetBucketObjects",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::{NAME_OF_YOUR_BUCKET_HERE}/*"
        }
    ]
} 

This can be done in the AWS console by selecting the Bucket, then Permissions, then Bucket Policy. Looks like @Milan C. is indicating how to declare this in a serverless.yml file.

Upvotes: 1

Milan Cermak
Milan Cermak

Reputation: 8064

Instead of using CorsConfiguration on the bucket, you need to attach a bucket policy to it. Try the following:

Resources:
  AttachmentsBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: range-picker-bucket-${self:custom.stage}

  AttachmentsBucketAllowPublicReadPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref AttachmentsBucket
      PolicyDocument:
        Version: "2012-10-17"
        Statement: 
          - Effect: Allow
            Action: 
              - "s3:GetObject"
            Resource: 
              - !Join ['/', [!Ref AttachmentsBucket, 'public']]
            Principal: "*"

Upvotes: 12

Related Questions