Permissions Boundaries Made Easy

In today's lab we'll implement something that even confuses the heck out of a lot of cloud experts. But it really isn't that complicated once you understand the basics.

Prerequisites

  • Have completed the IAM Identity Center Challenge lab (remember, you can just follow the instructions at that link).

    • You need the added policy (or something close) included in the permission set for IdentityCenterAdministration.

The Lesson

Of all our labs, this is the one that will make you look smarter than all the other so-called cloud experts at work! (Okay, maybe I should tone down my superlatives a smidge, but I’m in a good mood).

Today we will learn about permissions boundaries, which are a legitimately advanced IAM concept. When I mentioned this lab to a friend with over a decade of experience in AWS security, he said, “oh good, maybe now I’ll understand them”.

I wrote up the topic a while ago, and since then have figured out a reasonably easy way to explain what they are and why you might need them. It also turns out that I designed these labs to back us into a corner where only permission boundaries can save us.

A simple definition of permission boundaries

A permissions boundary is a guardrail; it doesn’t grant new permissions, but it restricts the total potential permissions of an identity, no matter what other policies are assigned. We mostly use them to allow someone to administer some IAM without allowing them to abuse it to give themselves more permissions.

A boundary says, “this is the most you are allowed to do, even if someone tries to let you do more.” A permission boundary is just another kind of guardrail.

Think back to when we talked about Service Control Policies (SCP), Amazon’s implementation of organization-based policies. As a reminder, in IAM we work with identity-based policies.

To paraphrase myself (and AWS), an SCP doesn’t grant any new permissions, it only restricts what can be done in an account. In our case we restricted a few things, including using the root account and using anything except two designated regions.

SCPs restrict the scope of what can be done in an account. They just sets some walls around things, so even someone with root or admin is still limited by the SCP.

A permissions boundary is like an SCP but applies to identities. It’s a way to restrict the maximum scope of what an identity can do, but doesn’t grant new permissions.

Why we need permission boundaries

SCPs are great for putting guardrails on accounts, but sometimes we need to limit what privileged roles/users can do. Okay, you may be saying, “we don’t have to give them permission for X.” That’s true, but sometimes they need that permission, but it could be abused to allow them to escalate their privileges, so we need another tool to limit that possibility.

Remember that a role/user can be assigned multiple policies at once. This makes it harder to be totally sure they are limited, since if they accidentally get assigned the wrong policy they could receive unintended permissions.

We nearly always use permissions boundaries when we need to allow someone to administer some IAM, but don’t want them to increase their own permissions. For example, if we want to allow someone to write and assign IAM policies, they could just assign themselves an admin policy.

We can use permissions boundaries for more than IAM, but I don’t often see them used for other use cases in real life. Amazon includes some good examples in their documentation but they are… a bit advanced.

I set us up for a really simple use case, which is also the most common one I’ve used permissions boundaries for myself. In IAM Identity Center we assigned our Identity Center Administrator permissions to write and assign policies to permission sets. But this means that manager could assign themselves a full administrator policy and take over everything. We will add a permissions boundary that prevents them from changing their own policies.

This prevents the Identity Center administrator from become a full administrator. There’s another hole they could still exploit.

The IAM administrator can still add themselves to a different group, like the Administrators group, or create a new user account for themself and add that to any group. In a real enterprise we could handle this two ways:

  • The most common option is that the enterprise would use a different Single Sign On (SSO) tool like Okta or even Microsoft’s Entra ID. The Identity Center administrator wouldn’t have permission to assign users and groups/roles in that tool, and thus couldn’t create a new user/role and assign it to themselves.

  • Identity Center requires unique email addresses for all users. To prevent creating a new user account for them, we could restrict using anything other than enterprise email addresses (which gets tricky if you use contractors). Since there is already a user account for the Identity Center’s administrators, they can’t create new users for themselves unless they can also create new email accounts.

  • Ideally we could restrict Identity Center actions on their own user account or group, but Identity Center doesn’t support that. I don’t get it — that’s important.

Let’s jump into the lab so I can show how all this works with our setup. Since I suspect people not participating in the labs might find this post, I’ll take more time than usual to explain how it all fits together.

Lesson Key Points

  • Permissions boundaries limit the maximum scope of things an identity can do.

  • We apply them to IAM users/groups and roles.

  • Permissions boundaries do not add permissions — they only take them away. Even an “Allow All” permission boundary wouldn’t allow… anything. It just wouldn’t block anything.

    • Fun tip: if you create a permission boundary with Deny statements to block specific actions, but don’t have any Allow statements, the identity won’t be able to do anything, because all IAM policies are default deny. I’ll explain more later.

  • The most common use case for permissions boundaries is to allow someone to administer IAM, but prevent them from giving themselves more permissions.

The Lab

First let’s review what we already configured in previous labs:

  • We enabled IAM Identity Center.

  • We created one user. That user is in multiple groups. That’s your user, in case you weren’t paying attention.

  • One of those groups is called IAM Administrators.

  • That group has a permission set called IdentityCenterAdministration. Reminder that a permission set is a “folder” for a group of IAM policies. This one includes:

    • The AWSSSOMemberAccountAdministrator AWS managed policy, which includes permissions to manage most of Identity Center.

    • Our ManagePoliciesForIdentityCenter policy which adds permissions to write and assign IAM policies. Your policy may have a different name because of how we did the challenge. Don’t worry, that won’t be a problem.

Our problem is that, as configured, anyone in the IAM Administrators group could write and assign themselves a policy with… any permission they want. That’s because the first policy in the permission set allows sso:AttachManagedPolicyToPermissionSet, and the second policy allows iam:CreatePolicy. That combination means someone could create any policy and attach it to a permission set, or even just attach AdministratorAccess to their own permission set.

We will use a permissions boundary to fix this:

  • We will log in with full AdministratorAccess.

  • We will create a customer managed policy that:

    • Allows All. What the <bleep>? Remember that IAM policies are deny all? If you don’t have a permission boundary in place, that’s fine — nothing happens. But the moment you add one it will instantly deny any actions not allowed. I tend to write permission boundaries to block specific actions under specific conditions, so I start with Allow All so it won’t completely break whatever standard IAM policies are applied.

    • Deny All actions if the permission set is IdentityCenterAdministration. This stops the user from attaching any new policies to their existing permissions, deleting policies, or removing the permission boundary. There are 4 kinds of policies, each with a different API call, in use (AWS managed, customer managed, inline, and boundary), so we will use “*” to block mucking with any of them.

      • This will also block some other API calls that are less important, like assigning the permission set for access to another AWS account.

That’s a pretty solid set of restrictions, but it leaves one hole we can’t fix until AWS helps. The identitystore service is the part of Identity Center which manages users and groups. Unlike basically every other service I’ve worked with in AWS, there’s no way to use users or groups in a policy, so we can’t restrict the IAM administrator from just adding themselves to the Administrators group and taking over everything.

Oh well. We’ll learn how to monitor for that down the road, when we start building threat detectors.

Video Walkthrough

Step by Step

Sign into your sign-in portal, then go to IAM > AdministratorAccess:

The first step is to collect the ARN of the IdentityCenterAdministration permission set. Go to IAM Identity Center > Permission sets > IdentityCenterAdministration, and copy the ARN. Either keep it on your clipboard or paste it someplace — you’ll need it in a moment:

Then go to IAM > Policies > Create policy:

Copy this code, and paste the ARN of your permission set where I’m shouting at you:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowAllActions",
      "Effect": "Allow",
      "Action": "*",
      "Resource": "*"
    },
    {
      "Sid": "DenyActionsOnSpecificPermissionSet",
      "Effect": "Deny",
      "Action": "*",
      "Resource": "INSERT YOUR ARN HERE"
    }
  ]
}

Then click the JSON tab and paste in that policy:

You’ll get a security warning due to the Allow All statement, but this is expected. Remember, we need that or default-deny will block any and every action. This is a permission boundary, so it doesn’t really give them permission — it just says “don’t block anything except the one explicit deny in the next statement”. Then click Next at the bottom.

On the next page name it SSOPermissionBoundary (SSO is the old name of Identity Center, and is still what all the API calls and permissions use). Provide a clear description like “Restricts an IAM Identity Center administrator from escalating their privileges.”

Then scroll down and click Create policy. You will need to copy the name onto your clipboard! If you recall, Identity Center won’t look up Customer Managed Policies — only AWS Managed Policies — when you pick.

No go back to IAM Identity Center > Permission sets > IdentityCenterAdministration. Then scroll down to the Permissions boundary section and click Set:

Select Customer managed policy, then paste in SSOPermissionBoundary and click Set permissions boundary:

This permission set only lives in the IAM account, but you still need to wait for it to deploy:

Then go to the upper right corner of the console and Sign out:

Now sign in as IdentityCenterAdministration, go to IAM Identity Center, and notice you are locked out of your own permission set:

Boom goes the dynamite!

You’ve now implemented a legitimately advanced IAM defense. The IAM Administrator can’t change their own permission set, and can’t grant themselves more permissions.

The only hole in this is due to a weakness in using IAM Identity Center as a directory: you can’t restrict the admin from adding themself to another group. If you used an external identity provider, this wouldn’t be an issue. I could be wrong, but I haven’t figured out a way to implement that restriction. It is, however, easy to monitor for once we get into threat detectors.

Lab Key Points

  • Permissions boundaries always need to be managed policies.

  • You need an Allow All, or at least to allow all expected actions, even if you are using the permissions boundary with Deny statements. Without this, default deny would block everything.

  • We used a Deny All if the resource is our permission set. You can use the same pattern to protect regular IAM roles, but you would use the ARN of the role instead.

-Rich

Reply

or to participate.