Understanding AWS IAM Permissions Boundaries

AWS IAM permissions boundaries

3 min read | by Jordi Prats

AWS Identity and Access Management (IAM) is a critical service for managing access to AWS resources. Among its many features, Permissions Boundaries add an extra layer of control ro ensure that users and roles cannot exceed specific permissions, even if somehow can update their IAM policies.

Permissions boundaries are IAM policies that act as a guardrail for the maximum permissions that an IAM user or role can have. It can be used as a safely net: even if someone assigns excessive permissions to a user or role, the permissions boundary ensures that those permissions won’t take effect beyond what the boundary allows.

When an IAM user or role tries to perform an action, AWS evaluates both the user's or role's IAM policy and the permissions boundary. For the action to succeed, it must be allowed by both the attached policy and the permissions boundary.

To start using permissions boundaries, you need to create a regular IAM policy that defines the maximum allowable permissions and attach it as a boundary to the users or roles that you want to restrict. For example, we can create a policy that we will be used as a boundary that will limit permissions to EC2 instance-related actions:

aws iam create-policy \
    --policy-name ec2-boundary \
    --policy-document '{
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Action": [
                    "ec2:*"
                ],
                "Resource": "*"
            }
        ]
    }'

We can now try creating a role with this boundary attached:

aws iam create-role \
    --role-name demo-restricted-admin \
    --assume-role-policy-document '{
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Principal": {
                    "AWS": "arn:aws:iam::'$(aws sts get-caller-identity --query Account --output text)':root"
                },
                "Action": "sts:AssumeRole"
            }
        ]
    }' \
    --permissions-boundary arn:aws:iam::$(aws sts get-caller-identity --query Account --output text):policy/ec2-boundary

We can now try attaching AdministratorAccess policy to this role and see if it works:

aws iam attach-role-policy \
    --role-name demo-restricted-admin \
    --policy-arn arn:aws:iam::aws:policy/AdministratorAccess

Let's assume the role and check what we can do:

eval $(aws sts assume-role \
    --role-arn $(aws iam get-role --role-name demo-restricted-admin --query 'Role.Arn' --output text) \
    --role-session-name EC2AdminSession \
    --query 'Credentials.[AccessKeyId,SecretAccessKey,SessionToken]' \
    --output text \
        | awk '{print "export AWS_ACCESS_KEY_ID="$1" AWS_SECRET_ACCESS_KEY="$2" AWS_SESSION_TOKEN="$3}')

We'll be able to use the EC2 service since it's allowed by both he permissions boundary and the role policy (AdministratorAccess). For example, we can list the instances:

$ aws ec2 describe-instances --query 'Reservations[*].Instances[*].InstanceId'
[
    [
        "i-03e92e15e15e0e1ed"
    ]
]

But we won't be able to use the S3 service since it's not allowed by the permissions boundary (even though it's allowed by the role policy):

$ aws s3 ls

An error occurred (AccessDenied) when calling the ListBuckets operation: User: arn:aws:sts::123456789876:assumed-role/demo-restricted-admin/EC2AdminSession is not authorized to perform: s3:ListAllMyBuckets because no permissions boundary allows the s3:ListAllMyBuckets action

To go back to the previous session, we can just unset the environment variables:

unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN

Posted on 08/10/2024