AWS permission boundaries for dummy

Abstract

Regular IAM policies let you do things, but can also stop you from doing things. Permission boundaries only stop you from doing things

AWS permission boundaries are confusing. I know they are confusing because they confused me, and it took me a couple years to figure them out. I also know they are confusing because Corey Quinn said so, and asked for someone to make them less confusing.

AWS Copilot, a CLI for the containerized apps, adds IAM permission boundaries and more – Someday someone is going to use very small words and explain to me what IAM Permission Boundaries are. Maybe today?

I’ll probably fail, but here it goes.

TL;DR: Regular IAM policies let you do things, but can also stop you from doing things. Permission boundaries only stop you from doing things. You mostly use them to let someone administer some IAM stuff but not so much IAM stuff that they can escalate privileges (for themselves or someone else). They are a failsafe. If you let someone manage IAM in an account and don’t want them to be able to escalate privileges, you almost always need a permission boundary!

The official AWS documentation has a lot of detail, but is still kind of confusing. This post is to help you understand the concepts and reason they exist, not to know the ins and outs of writing them (with one exception).

Pretend I’m a Fifth Grader, Not a Dummy, and Explain Them Again

Well, if you insist.

Before IAM Permission Boundaries it was REALLY HARD to let someone manage IAM permissions on their stuff, but not create a security problem by assigning too many permissions to something like an EC2 instance or… themselves. It mostly was an issue when you wanted to let them write IAM policies and then assign them. It’s the problem with delegated administration. “Let someone administer some things related to IAM but not those things”.

This is a very common scenario. Developers will often create a role for an instance, lambda function, or container task in their application stack and then assign that role permissions. It could be as simple as letting an instance read data out of an S3 bucket. Turns out, this is tough to handle from a security perspective:

  • If you let the developer write their own policies, they could add excessive privileges… like ..
  • If you let the developer assign policies, they could attach an existing policy with too many permissions.
  • If you allow the developer to create a new role AND assign a policy… you have the same issues.

Yes, you could just have security or a high-level admin handle all this, but that is inefficient. Permission boundaries let you have two levels of IAM administrators- the high level ones with overall security responsibility, and lower-level ones that do day to day things.

A permission boundary is just an IAM policy that lists the maximum privileges someone or something can have. You attach that policy and the developers who manage the thing can never give it more permissions than what’s allowed in the boundary. You can then even allow the developer to create new roles and users and assign them permissions, but you require that anything they create has that permission boundary on it. Thus they can never create or change anything and give it more permissions than you want.

I’m Not Sure that was for a Fifth Grader, but Maybe Give Me an Example?

Alice is the super-administrator for an AWS organization. She has to oversee hundreds of accounts, and each account has its own local admins and developers that do the actual Building of Applications.

Bob is one of those local developers. Bob is building a new application and it is more efficient for Bob to create his own roles and policies since he knows what his app needs.

Alice decides to let Bob manage the IAM for parts of his application. Specifically:

  • Bob can write and assign new IAM policies with the permissions his instances and lambda functions need.
  • There are some other AWS services in use that those components should never touch. Thus you can’t just turn them off with a Service Control Policy. That would break those services for the components allowed to use them.
  • Bob is not allowed to assign a new policy to himself.

It’s a classic delegated administration case- Bob is allowed to admin just some of the IAM. This is where you would use a permission boundary:

  • Alice creates a permission boundary “A” which allow permissions for the AWS services that Bob’s instances and lambda functions can talk to (e.g. S3, SNS, SQS).
  • Alice creates a permission boundary “B” that allows Bob to create IAM roles and policies (and assign them) but NOT assign them to himself.
  • Alice gives Bob IAM permissions to create and assign new roles and policies, but any new roles must have the “A” permission boundary. This means those instances and lambda functions will NEVER have more permissions than what is in the boundary, but they can have less.
  • Alice assigns the permission boundary “B” to Bob to keep him from assigning permissions to himself. Now he can’t take off the requirement that he has to deploy things with “A” on them.

Yes, there are multiple ways to approach this problem… but the short version is anytime you want to let someone administer some IAM in an account, you probably need a permission boundary if you don’t want them to do too much.

Tell Me Again Why a Service Control Policy Won’t Work Here?

Sometimes an SCP might work, but you can only use an SCP if you are in an Organization and a permission boundary will work in any account. Also, SCPs are really good for things like limiting what API calls you can make (and thus which AWS services you can use), but they aren’t really meant for this kind of granularity and conditionals.

Think of my example above- Alice might have to know the resource identifiers to allow access to services in the account, but not from the resources created by Bob. There are ways of possibly handling this (e.g. resource paths) but it isn’t any simpler than our permission boundary example and doesn’t always work depending on the supported condition keys.

In my Incident Response Training Range I use an SCP to restrict admin users (students) in the accounts from breaking my Organizations-level access and a few other things. But that only works because I allow them full IAM, and they are already one of those super-admins. If I wanted to limit their ability to create resources with excessive permissions, I would need a permission boundary or an SCP to restrict them to only assigning certain pre-made policies.

Can’t I just Use Deny Policies?

Not really. We tried that before permission boundaries existed and, aside from the complexity, there were just too many loopholes.

Can I Have One More Simple Example?

Sure thing! Here is one we use ourselves.

Some users let us make IAM changes in their accounts. We use a cross-account roles for this. When users deploy the role, they apply a permission boundary that never lets us change permissions on ourselves. This prevents privilege escalation.

I Think I Get It, But How Do All These IAM Policies Interact?

Check out the AWS documentation for their policy logic evaluation, but here are my crib notes:

  • Service Control Policies limit what anyone is allowed to do in an account (e.g. they can turn services on and off).
  • IAM permission policies allow users and roles to do things in an account.
  • IAM resource policies allow users and roles to interact with the resource the policy is attached to.
  • Permission boundaries set the maximum privileges a user or role can have. They don’t allow you do to things, but they can stop you from doing things.

The policies all work together. For you to do something, you have to have a permission someplace in the stack to do it, and have no deny policies anywhere from stopping you from doing it. Any single Deny will override any Allow, no matter where it is.

Remind Me Again When to Use Permission Boundaries?

When you want to allow someone to administer some of the IAM in an account, but still limit how much, you should find yourself thinking of a permission boundary.

Even when you are using advanced IAM tools like our new FireMon Authorization Control, you may still want some permission boundaries, especially in highly-sensitive accounts.

What’s the One Example You Said you Would Include?

Although permission boundaries are meant to prevent you from doing things, they still need you to specify all the allow permissions. In other words, if you write a permission boundary with a DENY statement to block the one thing you don’t want that user/role to do, you would still need an ALLOW * statement or they can’t do anything.

This is the part that confused me at first, since I misread Amazon’s description and thought you could just use a permission boundary to block actions. You can, but except for a resource policy use case I don’t want to get into today, the permission boundary also needs to include everything you want to allow. You can’t just DENY one thing in the permission boundary and ALLOW other things in the regular IAM permission policy and have it work. The permission boundary also needs to have the ALLOW statements (and yes, I cheat and will use ALLOW * here at times).