10

I am unable to get an upload working with Paperclip using an S3 IAM policy. I'm even having issues with direct jQuery uploads (no Paperclip). My scenario is as follows, I have an application that will have many sites. Each site will have it's own bucket and should only be able to access their own bucket, nobody else's. The IAM Example Policies documentation explains exactly what I want to do under "Example: Allow each IAM user access to a folder in a bucket". I have an IAM group set up for the application and have one user per site within the group. These IAM users belong to the group. The policy on the group is as follows:

{
   "Version":"2012-10-17",
   "Statement":[{
         "Effect":"Allow",
         "Action":[
            "s3:PutObject",
            "s3:GetObject",
            "s3:GetObjectVersion",
            "s3:DeleteObject",
            "s3:DeleteObjectVersion"
         ],
         "Resource":"arn:aws:s3:::my-app/${aws:username}/*"
      }
   ]
}

Here is my CORS configuration on the bucket, for dev of course, it will get locked down later:

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
    <CORSRule>
        <AllowedOrigin>*</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <AllowedMethod>POST</AllowedMethod>
        <AllowedMethod>PUT</AllowedMethod>
        <AllowedHeader>*</AllowedHeader>
    </CORSRule>
</CORSConfiguration>

Here are my Paperclip settings:

has_attached_file :background_image,
                  storage: :s3,
                  s3_credentials: {
                    access_key_id: "xxx",
                    secret_access_key: "xxx"
                  },
                  bucket: "my-app",
                  s3_permissions: "public-read",
                  path: "/background_images/:id/:filename"

I was previously working with policies directly on the bucket, which did work but wasn't as flexible as I need it to be when I move into a production environment with many "sites". As far as I can tell I've followed the documentation exactly yet anything I do results in 'Access Denied'. At this point I'm not even sure if my issue is with my IAM policy or my Paperclip configuration.

edit: clarification.

edit 2: FINAL SOLUTION

Here is my final IAM policy based on this article:

{
 "Version":"2012-10-17",
 "Statement": [
   {
     "Sid": "AllowUserToSeeBucketListInTheConsole",
     "Action": ["s3:ListAllMyBuckets", "s3:GetBucketLocation"],
     "Effect": "Allow",
     "Resource": ["arn:aws:s3:::*"]
   },
  {
     "Sid": "AllowRootAndHomeListingOfCompanyBucket",
     "Action": ["s3:ListBucket"],
     "Effect": "Allow",
     "Resource": ["arn:aws:s3:::my-app"],
     "Condition":{"StringEquals":{"s3:prefix":["","home/"],"s3:delimiter":["/"]}}
    },
   {
     "Sid": "AllowListingOfUserFolder",
     "Action": ["s3:ListBucket"],
     "Effect": "Allow",
     "Resource": ["arn:aws:s3:::estimator-app"],
     "Condition":{"StringLike":{"s3:prefix":["home/${aws:username}/*"]}}
   },
   {
     "Sid": "AllowAllS3ActionsInUserFolder",
     "Effect": "Allow",
     "Action": ["s3:*"],
     "Resource": ["arn:aws:s3:::my-app/home/${aws:username}/*"]
   }
 ]
}

And my updated Paperclip settings:

has_attached_file :background_image,
                    storage: :s3,
                    s3_credentials: {
                      access_key_id: "xxx",
                      secret_access_key: "xxx"
                    },
                    bucket: "estimator-app",
                    s3_permissions: "public-read",
                    path: "/home/my_s3_username/background_images/:id/:filename"

It was important to include the username in the Paperclip path. I was assuming Amazon would infer that from the credentials but that's not the case.

Ryan Arneson
  • 1,293
  • 3
  • 14
  • 25

1 Answers1

18

Because you're trying to set permissions on the objects you upload, you also need to give your IAM users the s3:PutObjectAcl permission.

dcro
  • 12,054
  • 4
  • 62
  • 73
  • I did update permissions to "Action": "s3:*" just to test out. It works if I also update to "Resource":"arn:aws:s3:::my-app/*". The minute I put ${aws:username} in I get Access Denied again. Thanks for the tip though, I'll be sure to put that in the permissions. edit: Actually it appears if my Resource is anything but the root of the bucket I'm unable to upload. – Ryan Arneson Oct 04 '13 at 15:29
  • Your IAM user policy seems correct because you're already using the correct `Version` in the policy. How is your user actually named and what's the S3 path you're trying to upload to? (`${aws:username}` translates to the [friendly name](http://docs.aws.amazon.com/IAM/latest/UserGuide/Using_Identifiers.html#Identifiers_FriendlyNames) for that user). From your example the path seems to be `background_images` but is your IAM user also called `background_images`? – dcro Oct 04 '13 at 15:37
  • The user is localhost-estimator-app and the group is estimator-app. I wonder how much of [this article](http://blogs.aws.amazon.com/security/post/Tx1P2T3LFXXCNB5/Writing-IAM-policies-Grant-access-to-user-specific-folders-in-an-Amazon-S3-bucke) applies to my situation. – Ryan Arneson Oct 04 '13 at 15:54
  • Ok so I think my problem is I wasn't including the username in my Paperclip path. I was assuming Amazon would infer the username from the security credentials. Doesn't appear to be the case. – Ryan Arneson Oct 04 '13 at 18:32
  • Marking this as the correct answer because you steered me in the right direction with the username issue. – Ryan Arneson Oct 04 '13 at 19:07
  • 1
    @dcro Just came across this, but adding `s3:PutObjectAcl` fixed my permission issue. Why do we need this permission (the Acl)? – Tyler DeWitt Nov 17 '15 at 01:23
  • 1
    @TylerDeWitt If you try to set any ACLs on the uploaded object (e.g. `s3_permissions: "public-read"` in the original example), you also need to have permissions to set those ACLs, thus the need to have the `s3:PutObjectAcl` permission. – dcro Nov 17 '15 at 08:12
  • @dcro - perfect, that is exactly what was happening. Thanks for the explanation – Tyler DeWitt Nov 17 '15 at 15:28