7

I have an app that users log in with facebook and then can upload images to s3 bucket and view them. I used Cognito service to allow every logged in user to upload and view all files.

I have no idea how to set the correct permissions on the s3 bucket. This is my attempt at it, but I get can't save the policy and get Statement is missing required element - Statement "NO_ID-0" is missing "Principal" element

{
    "Version": "2012-10-17",
    "Id": "Policy1457546546214",
    "Statement": [
        {
            "Sid": "Stmt1475657256771436",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::bucket-name/*"
        },
        {
            "Sid": "Stmt16577654572138125",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:PutObject",
            "Resource": [
                "bucket-name/identity-pool-id*"
            ]
        }
    ]
}

This is the client part, if it helps:

FB.login(function (response) {
    if (response.authResponse) {

      AWS.config.region = 'eu-west-1';
      AWS.config.credentials = new AWS.CognitoIdentityCredentials({
        IdentityPoolId: 'eu-west-1:xxxxxxxxxxx',
        Logins: {
          'graph.facebook.com': response.authResponse.accessToken
        }
      })

      var bucket = new AWS.S3({params: {Bucket: 'name'}})
      var fileChooser = document.getElementById('file-chooser')
      var button = document.getElementById('upload-button')

      button.addEventListener('click', function() {
        var file = fileChooser.files[0]
        var params = {Key: file.name, ContentType: file.type, Body: file}
        bucket.upload(params, function (err, data) {
        ...

Cognito IAM > Roles > Cognito_myappAuth_Role:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "cognito-identity:*"
            ],
            "Effect": "Allow",
            "Resource": [
                "*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:PutObject",
                "s3:PutObjectAcl"
            ],
            "Resource": [
                "arn:aws:s3:::bucket/${cognito-identity.amazonaws.com:sub}/*",
                "arn:aws:s3:::bucket/${cognito-identity.amazonaws.com:sub}"
            ]
        }
    ]
}
John Rotenstein
  • 241,921
  • 22
  • 380
  • 470
ilyo
  • 35,851
  • 46
  • 106
  • 159

1 Answers1

10

Have you checked out this blog post? It has a good example of how to set up a role that allows S3 bucket access for users. Cutting out the list bucket part out, the access policy you would link to your identity pool roles might look something like this:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "s3:GetObject",
        "s3:PutObject"
      ],
      "Effect": "Allow",
      "Resource": ["arn:aws:s3:::mybucket/${cognito-identity.amazonaws.com:sub}/*"]
    }
  ]
}

Edit:

Tl;dr from comments for future readers:

  • Apply the policy to the pool's auth role instead of bucket

  • If the app use case requires a common area, use the bucket root directory, otherwise use a directory for each identity defined in the policy (as described in the blog)

  • The role itself doesn't apply until after the authentication occurs. The policy just defines what the credentials given back will have access to do and to what.

Nazim Kerimbekov
  • 4,712
  • 8
  • 34
  • 58
Jeff Bailey
  • 5,655
  • 1
  • 22
  • 30
  • I just set up an S3 bucket with the access policy described in the blog attached to my identity pool roles and it worked fine. Can you elaborate on what didn't work? Is the error you're seeing still what you have above? – Jeff Bailey Mar 05 '16 at 22:15
  • I added the client part of what I did. When I try to upload I get "Access denied" – ilyo Mar 05 '16 at 22:21
  • This is a bucket policy? Have you tried adding it to the auth role for your identity pool? – Jeff Bailey Mar 05 '16 at 22:25
  • No, to `IAM > Roles > Cognito_myappAuth_Role`? What policy? – ilyo Mar 05 '16 at 22:27
  • It looks like you only want them to be able to after logging in with facebook, so I think that's the way to go. Then under that role, go to permissions, and create an inline policy for this role that gives the permissions you want (perhaps just copy/paste what you have above or from the blog over). This tells Cognito what ability the user has and what scope the credentials they're given have. – Jeff Bailey Mar 05 '16 at 22:37
  • I pasted my attempt in the question, still not working :( – ilyo Mar 05 '16 at 22:41
  • Is the bucket path the same? It looks like you granted access to / where your initial was just . Is your client code trying to access the base bucket, but your role only allowing a subdirectory that doesn't exist? – Jeff Bailey Mar 05 '16 at 22:44
  • Can you elaborate? I want access to the root of the bucket (I made sure the name is correct everywhere) – ilyo Mar 05 '16 at 22:48
  • Absolutely. Try removing ${cognito-identity.amazonaws.com:sub}/* and ${cognito-identity.amazonaws.com:sub} from the Resource section of your policy to give them access to the root of the bucket. That's giving it to a subdirectory prefixed by identity id. – Jeff Bailey Mar 05 '16 at 22:50
  • Yes, but isn't this line used for the Cognito auth? If I remove it, how will I do the identification? – ilyo Mar 05 '16 at 22:55
  • Or maybe I *should* create a subdirectory for the authenticated user's files? – ilyo Mar 05 '16 at 22:56
  • It depends on your app use case. If files shouldn't be totally public, I would recommend a subdirectory. If they should, you could do base. This line isn't for cognito auth, it just allows you to only give an identity id access to their own directory. The policy defines what the user has access to. – Jeff Bailey Mar 05 '16 at 22:58
  • At the point where it kicks in, cognito has already authenticated with the Facebook token. It's just telling cognito what the user can do now that they have. So it's up to you to define that based on what your app needs – Jeff Bailey Mar 05 '16 at 22:59
  • If I understand correctly: once the user is at the gate of the `Cognito_myappAuth_Role` policy, he was *already* authenticated with the facebook id? – ilyo Mar 05 '16 at 23:02
  • Correct. The policy you are defining just scopes the aws credentials he will be given – Jeff Bailey Mar 05 '16 at 23:06
  • Trying to allow POSTs to bucket. `"Principal": "*" is now a required field for bucket policy. – timbo Jun 13 '19 at 00:13