Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

IAM Policy for S3 folder access based on Cognito ID

I have created an IAM policy to allow Cognito users to write to my S3 bucket, but I would like to restrict them to folders based on their Cognito ID. I've followed Amazon's instructions here and created a policy that looks like this:

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

But when I try to upload using the v2 of the AWS iOS SDK I get an access denied error.

If I modify the last path component of the resource to replace ${cognito-identity.amazonaws.com:sub} with the explicit identityId value I am getting from the SDK's AWSCognitoCredentialsProvider it works.

{
    "Effect": "Allow",
    "Action": ["s3:PutObject","s3:GetObject"],
    "Resource": [
        "arn:aws:s3:::mybucket/myappfolder/us-east-1:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx*"
    ]
}

My understanding was that these should equate to the same thing. Am I missing something in my policy, or should I be using a different path in my upload request?

** Update **

I originally had this problem in iOS, so tonight I tried doing the same thing in node.js and the result is identical. Here is the simple code I am using in node:

var s3 = new AWS.S3();

AWS.config.region = 'us-east-1';

AWS.config.credentials = new AWS.CognitoIdentityCredentials(AWSParams);

AWS.config.credentials.get(function (err) {

    if (!err) {

        console.log("Cognito Identity Id: " + AWS.config.credentials.identityId);

        var bucketName = 'ch123_test_bucket';

        var keyName = AWS.config.credentials.identityId + '.txt';

        var params = {Bucket: bucketName, Key: keyName, Body: 'Hello World!'};

        s3.putObject(params, function (err, data) {
            if (err)
                console.log(err)
            else
                console.log("Successfully uploaded data to " + bucketName + "/" + keyName);
        });
}

And I get the same results that I get with iOS: unless I supply an explicit cognito ID in the IAM policy the API responds with 403.

I've stripped my IAM policy down to the very bare minimum. This doesn't work:

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

This does:

{
"Statement": [
  {
    "Effect": "Allow",
    "Action": ["s3:PutObject","s3:GetObject"],
    "Resource": [
        "arn:aws:s3:::ch123_test_bucket/us-east-1:68a5dc49-6cc7-4289-8257-d3d5636f7034*"
    ]
  }
 ]
}

I don't see what I'm missing here...the only documentation I've been able to find always shows the same example Resource value that I've been using.

like image 678
ChrisH Avatar asked Sep 06 '14 17:09

ChrisH


1 Answers

Unfortunately there is currently an issue with the roles generated via the Cognito console in combination with policy variables. Please update your roles' access policy to include the following to ensure policy variables are evaluated correctly:

"Version": "2012-10-17"

2014-09-16 Update: We have updated the Amazon Cognito console to correct this issue for new roles created via the Identity Pool creation wizard. Existing roles will still need to make the modification noted above.

like image 84
Bob Kinney Avatar answered Oct 31 '22 08:10

Bob Kinney