skip to Main Content

I have User with full access to an S3 Bucket my-bucket. I want to assume a role with that user to restrict access to ONLY a specific folder (labeled by the role name) for the duration of that session. There will be multiple roles/folders, so I need to do this programmatically rather than hard coding each.

For example:
test_user assumes role safe_role to access the s3 folder my-bucket/safe_role

I assumed that this would be simple with policy variables, but I’ve been stuck for days just trying to get this set up.

I can successfully create safe_role, attach the policy to safe_role, and assume the role via test_user. With the following policy, I am successfully able to download objects from any folder since it gives complete access to the S3 bucket.

Here is the initial policy that works:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor1",
            "Effect": "Allow",
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::my-bucket/*",
                "arn:aws:s3:::my-bucket"
            ]
        }
    ]
}

Now to restrict access to the safe_role folder I tried (along with a million other things) this:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor1",
            "Effect": "Allow",
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::my-bucket/${aws:username}/*",
                "arn:aws:s3:::my-bucket"
            ]
        }
    ]
}

After assuming the safe_role role, I am unable to download any objects from any folder, including my-bucket/safe_role. I get the following error:

Exception has occurred: ClientError
An error occurred (403) when calling the HeadObject operation: Forbidden

Questions:

  • In this case, should we expect the variable ${aws:username} to become test_user or safe_role?
  • Is there some way to see the policy variable substitution in the console (or any other method) when making test requests?
  • If this isn’t the right variable, what policy variable will give me the role name?

Based on @jarmod comment and AWS docs, it looks like we can’t get variables for roles in the way I thought. Is there some other way to get the same effect? Tags perhaps?

2

Answers


  1. Chosen as BEST ANSWER

    As jarmod points out, we can't use aws:username because it isn't populated for an assumed role. But John correctly notes that we CAN use the aws:userid field for an assumed role. (See IAM policy elements: Variables and tags - AWS Identity and Access Management)

    For an assumed role, the userid takes the following form:

    aws:userid = role-id:caller-specified-role-name
    

    With this knowledge, we can now tag each object in the folder with user = role_name. Once the objects are tagged, we can limit access by attaching the following policy to the role:

    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Sid": "RestrictAccessToFolderRoleName",
                "Effect": "Allow",
                "Action": "s3:*",
                "Resource": [
                    "arn:aws:s3:::my-bucket/*",
                    "arn:aws:s3:::my-bucket"
                ],
                "Condition": {
                    "StringLike": {
                        "aws:userid": "*:${s3:ExistingObjectTag/user}"
                    }
                }
            }
        ]
    }
    

    This condition compares the second part of the userid caller-specified-role-name with the user tag on the object. If the two don't match, then the assumed role will not be able to download the object.

    It should be noted that this role name is "caller specified". This is OK for my application, but may be a security concern in other cases.

    If anyone else has a more secure solution, I would be willing to change the accepted answer!


  2. According to IAM policy elements: Variables and tags – AWS Identity and Access Management, when an IAM Role is assumed:

    • aws:userid = role-id:caller-specified-role-name

    where role-id is the unique id of the role and the caller-specified-role-name is specified by the RoleSessionName parameter passed to the AssumeRole request.

    Therefore, it isn’t as simple as just having the folder named the same as the role. It would need to be named after the role-id and the RoleSessionName.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search