ChrisH ChrisH - 1 year ago 52
Node.js Question

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.

Answer Source

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.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download