4
votes

In Chapter 11.4.4 'Image upload in production' of Michael Hartl' Rails Tutorial it is suggested to use Amazon Web Services S3 as a cloud storage service. In a note at the bottom of the page, the author himself defines this section of the book as "challenging" and also suggests that it "can be skipped without loss of continuity".

Indeed one of the most challenging parts of this section is to find a suitable IAM policy that can be attached to the IAM user at AWS in order to grant to the IAM user read and write permissions on the S3 bucket.

I found that this at Stackoverflow is a common issue: see for instance 'Trying to set up Amazon's S3 bucket: 403 Forbidden error & setting permissions'.

In effect, Amazon Web Services's solution for applications that need read and write permissions on a single S3 bucket does not work, and the user who tries to upload images receives a 403 forbidden status from the AWS server at Heroku.

The predefined 'AmazonS3FullAccess' policy works indeed, however it should not be considered as a definitive solution, because granting too many permissions to the IAM user, and therefore to the application, is not required and also, I suppose, can be a security bug.

What then is the correct IAM policy?

1

1 Answers

9
votes

If the 'AmazonS3FullAccess' policy works, there should definitely be some action in it that is essential for the working of the application.

Apart from the ListBucket, PutObject, GetObject and DeleteObject actions whose presence seems logical, I found that PutObjectAcl is also necessary.

From the AWS's Access Control List (ACL) Overview:

"Amazon S3 Access Control Lists (ACLs) enable you to manage access to buckets and objects. Each bucket and object has an ACL attached to it as a subresource. It defines which AWS accounts or groups are granted access and the type of access. When a request is received against a resource, Amazon S3 checks the corresponding ACL to verify the requester has the necessary access permissions. When you create a bucket or an object, Amazon S3 creates a default ACL that grants the resource owner full control over the resource"

Moreover, from the documentation on 'PutObjectAcl':

"This implementation of the PUT operation uses the acl subresource to set the access control list (ACL) permissions for an object that already exists in a bucket... The ACL of an object is set at the object version level. By default, PUT sets the ACL of the current version of an object."

I could not find explanations in my request of support from the Amazon forums on why PutObjectAcl is necessary, but from my understanding probably the operation of creating the ACL of an object is made the first time the object is uploaded in the bucket and should be explicitly requested by the application (or IAM user) that makes the upload. You can find a copy of my policy in the above Amazon Forums discussion and below:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "s3:ListBucket"
      ],
      "Effect": "Allow",
      "Resource": "arn:aws:s3:::<bucket-name>"
    },
    {
      "Action": [
        "s3:DeleteObject",
        "s3:GetObject",
        "s3:PutObject",
        "s3:PutObjectAcl"
      ],
      "Effect": "Allow",
      "Resource": "arn:aws:s3:::<bucket-name>/*"
    }
  ]
}

Consider also Heroku's suggestions on the choice of your bucket name: avoid for instance punctuations.