Search code examples
amazon-web-servicesamazon-s3permissionspublicbucket

How to securely configure s3 for website access


I want to setup an s3 bucket securely but provide public access to website assets such as images, pdfs, documents, etc. There doesn't seem to be an easy way to do this.

I have tried setting up a new bucket which has Block Public Access enabled. I assume this is the best way to secure the bucket but can't enable viewing/downloading of files in this bucket.

I expect to be able to view/download website files from a browser but always get an Access Denied error.


Solution

  • All content in Amazon S3 buckets are private by default.

    If you wish to provide public access to content, this can be done in several ways:

    • At the Bucket level by providing a Bucket Policy: This is ideal for providing access to a whole bucket, or a portion of a bucket.
    • At the Object level by using an Access Control List (ACL): This allows fine-grained control on an object-by-object basis.
    • Selectively, by creating a pre-signed URL: This allows your application to determine whether a particular application user should be permitted access

    All three methods allow an object in Amazon S3 to be accessed via a URL. This is totally separate to making API calls to Amazon S3 using AWS credentials, which would allow control at the user-level.

    Based on your description, it would appear that a Bucket Policy would best meet your needs, such as:

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

    This is saying: Allow anyone to get an object from my-bucket

    Note that the policy specifies which calls are permitted, so it can allow upload, download, delete, etc. In the above example, it is only allowing GetObject, which means objects can be accessed/downloaded but not uploaded, deleted, etc.

    The /* in the Resource allows further control by specifying a path within the bucket, so it would be possible to grant access only to a portion of the bucket.

    When using a Bucket Policy, it is also necessary to deactivate Block Public Access settings to allow the Bucket Policy to be used. This is an extra layer of protection that ensures buckets are not accidentally made publicly accessible.

    If, on the other hand, your actual goal is to keep content private but selectively make it available to application users, then you could use a pre-signed URL. An example is a photo website where people are permitted to view their private photos, but the photos are not publicly accessible.

    This would be handled by having users authenticate to the application. Then, when they wish to access a photo, the application would determine whether they are permitted to see the photo. If so, the application would generate a pre-signed URL that grants temporary access to an object. Once the expiry time is passed, the link will no longer work.