X
Popular Searches

How to Practice Proper IAM User Management with Permission Boundaries

AWS Logo

If you have employees with their own IAM accounts and want to delegate permission management by giving them the permission to make their own IAM roles, you must set it up correctly, or your employees may be able to escalate their privileges.

Full IAM Access Enables Privilege Escalation

If you thought about giving blanket access to the IAM console, that would certainly solve the issue and enable your employees to make new IAM accounts. However, what it also does is enable them to change their own permissions and create new accounts, enabling them to give full privileges.

The process is pretty simple. Say you’re creating a new user account, and naively attach the IAMFullAccess permission:

Creating a new user account with IAMFullAccess permission.

Once that user signs in, they can go to their own IAM page and modify their own permissions, adding AdministratorAccess if they desire. This is a major issue. Don’t do this.

Users can modify their own permissions, adding AdministratorAccess.

Luckily, a few solutions still exist for enabling IAM users to create their own service accounts and roles.

The Solution: Permission Boundaries

The direct solution to this problem is Permission Boundaries. A permission boundary can be applied to any user, and overrides any permissions set by policies. In essence, it makes the effective permissions the account can have to be the intersection between the permissions policy and the permissions boundary.

The intersection between the Permissions policy and the Permissions boundary.

The important part of this intersection is that the account with the boundary cannot do anything outside of the boundary. You can then give the employee access to create roles and policies, but not the permission to change or remove permission boundaries. You can restrict the employee’s ability to create roles to only enable the creation of roles initialized with the permission boundary, which basically only lets them create policies within the permissions boundary.

For this example, we’re creating a policy that gives full access to a single S3 bucket. This is our permissions boundary, any roles created by the employee should not be able to access other buckets through any means.

Creating a policy that gives full access to a single S3 bucket.

You can manually set the boundary for a given user under the “Policy Usage” tab, but all it does is restrict access to that permission boundary, ignoring other policies. Technically, the permissions boundary for the employee is assigned to any roles that employee creates, not to their own account. This way, you can give the employee read/write permission to use S3 on their own, but only allow read permission for any service roles they create. If you set the permissions boundary on the employee account as well, they will have the exact same roles as accounts they can create.

Manually setting the boundary for a given user under the "Policy Usage" tab.

What you really want to do is create a custom permission that only enables the employee IAM user to create new roles, but only within the permission boundary you set. Copy the ARN of the policy you’d like to use as the boundary. (You can find this on the policy info page).

Create the following role, replacing the condition with your own ARN.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "iam:DetachRolePolicy",
                "iam:CreateRole",
                "iam:AttachRolePolicy"
            ],
            "Resource": "*",
            "Condition": {
                "StringEquals": {
                    "iam:PermissionsBoundary": "arn:aws:iam::515436951152:policy/S3AccessBoundary"
                }
            }
        },
        {
            "Sid": "VisualEditor1",
            "Effect": "Allow",
            "Action": [
                "iam:CreateInstanceProfile",
                "iam:GetRole",
                "iam:GetPolicyVersion",
                "iam:GetInstanceProfile",
                "iam:ListRoleTags",
                "iam:GetPolicy",
                "iam:AddRoleToInstanceProfile",
                "iam:CreatePolicy",
                "iam:PassRole",
                "iam:ListPolicyVersions",
                "iam:ListAttachedRolePolicies",
                "iam:CreatePolicyVersion",
                "iam:ListRolePolicies",
                "iam:GetRolePolicy",
                "iam:DeletePolicyVersion"
            ],
            "Resource": [
                "arn:aws:iam::515436951152:role/service-*",
                "arn:aws:iam::515436951152:policy/service-*",
                "arn:aws:iam::515436951152:instance-profile/service-*"
            ]
        },
        {
            "Sid": "VisualEditor2",
            "Effect": "Allow",
            "Action": [
                "iam:ListPolicies",
                "iam:GetServiceLastAccessedDetailsWithEntities",
                "iam:ListRoles",
                "iam:GetServiceLastAccessedDetails"
            ],
            "Resource": "*"
        }
    ]
}

What this does is grant the CreateRole, AttachRolePolicy, and DetachRolePolicy permissions, granting the user permission to create service accounts and to use the role with other AWS services. But this policy comes with a condition, iam:PermissionsBoundary, which ensures the roles they create are kept in check with the permissions boundary you specify.

This policy also enables the user to create their custom policies, crucial for working with service accounts. Even if the user creates a policy that gives administrator access, it won’t give anything more than the permission boundary. Also, set here are a bunch of read-only permissions necessary for working with the IAM Console, which enable access to manage and update roles and policies, but nothing else.

This policy also only enables the user to interact with policies, roles, and instance profiles that start with the prefix service-. This is to prevent the user from being able to update existing policies that don’t have the permissions boundary set. You may want to create seperate prefixes for different permissions boundaries.


Now, let’s return to our employee account, and instead, assign our policy that provides for permission delegation within the set limits. Once you sign into the employee account and head to the IAM console, you find that you can no longer edit your own permissions, as there’s no policy to enable it. You can create policies as normal, and create roles as normal.

Let’s try breaking out. The permissions we’ve set up don’t enable you to create new roles that don’t have the permissions boundary set. If you try to create one without it, you’ll be met with an error. You have to have your employee manually select the access boundary associated with their account, though.

Attempting to break out.

Once the role is created, even though the employee gave it AmazonS3FullAccess, it will only have access to the specific bucket that we set in the permissions boundary.

The employee can e.dit the policies for roles once they’re created, but doesn’t have permission to edit permission boundaries on roles If you try, you’ll be met with a fat error.

The error received when you don't have permission to edit permission boundaries on roles.

Once that’s set up, you’re all set! You can give the DelegatePermissions policy to your employees, and they won’t have to bug you (or the root account holder) every time they want to give an EC2 instance permission to access S3.

Another Solution: A Separate Development and Production Environment

This solution doesn’t solve the problem directly, but can help take some of the edge off your permission management.

If you’re using one environment for development and production, there’s a better way to handle it. AWS Organizations enables you to create sub-accounts under your main account, with consolidated billing (the master account pays for everything). You can use this to logically split your production, development, staging, and testing environments apart, so that IAM users created in development can’t access resources in production.

Creating sub-accounts under your main account in AWS Organizations to split production, development, staging, and testing environments apart.

This can take a lot of weight off of the developers and make the development environment more relaxed. You won’t have to worry as much about restricting S3 access to specific development buckets; instead, you can give out S3FullAccess to developers, knowing that it only affects the development environment. You shouldn’t automatically make all your developers full administrators in that environment, and you might want to still use permission boundaries. But if it doesn’t affect production, you can give your develpers more freedom. Project managers or senior developers could be given full access to most services, provided you keep an eye on the spending to make sure they aren’t renting a c5.24xlarge instance to play Minecraft during off hours.

Anthony Heddings Anthony Heddings
Anthony Heddings is the resident cloud engineer for LifeSavvy Media, a technical writer, programmer, and an expert at Amazon's AWS platform. He's written hundreds of articles for How-To Geek and CloudSavvy IT that have been read millions of times. Read Full Bio »

The above article may contain affiliate links, which help support CloudSavvy IT.