Permission boundaries: the IAM control nobody explains well
Cloud Security
SCPs gate the account, role policies grant the action, and permission boundaries cap what a delegated admin can hand out. Here's when each one is the right answer.
By Arjun Raghavan, Security & Systems Lead, BIPI · March 9, 2024 · 8 min read
A platform engineering lead asked us why their developers could create roles that could create roles that could become admin. The answer was that they had given developers iam:CreateRole and iam:AttachRolePolicy and trusted the SCPs to catch abuse. SCPs do not gate IAM principal-creation paths inside an account. Permission boundaries do.
There are three levers in AWS that shape what a principal can do, and most teams reach for the wrong one. Getting clear on which lever solves which problem is the difference between IAM that scales and IAM that turns into a ticket queue.
The three levers, side by side
SCPs apply to every principal in an account, including the root user, and cap the maximum permissions available. Role policies and identity policies grant specific permissions. Permission boundaries are an upper bound that you attach to a principal: the effective permissions are the intersection of the boundary and the identity policy. Resource policies and session policies are out of scope here; we will write that up separately.
When to use each
Use SCPs for org-wide invariants: no IAM user creation, no leaving the org, no disabling CloudTrail. Use permission boundaries for delegated administration: developers can create their own roles, but the roles they create cannot escape the boundary. Use role policies for the day-to-day grants that the principal actually needs to do their job.
The developer self-service pattern
Here is the pattern we deploy at almost every client. Developers get a CICDDeveloperRole with permissions to create IAM roles and attach policies, but only if the role being created has a specific permission boundary attached. The boundary itself denies iam:CreateUser, iam:DeleteRolePermissionsBoundary, iam:PutRolePolicy with policies containing certain admin actions, and any attempt to modify the boundary itself. Result: developers can ship Lambda, EKS, and Step Functions without filing tickets, and the worst they can create is a role no more privileged than they are.
The trick that catches people: the developer role's own policy must include a Condition on iam:PassRole and iam:CreateRole that requires the boundary be attached. Otherwise developers can create roles without the boundary.
Common mistakes we see
First mistake: putting Allow statements inside the boundary. Boundaries are caps, not grants. An Allow in the boundary does nothing useful and confuses the next engineer to read it. Second: forgetting the Condition on the developer role that forces the boundary on created principals. Without that, developers create unbounded roles and the whole pattern collapses. Third: making the boundary too permissive, so it functionally allows admin minus a handful of obviously-bad actions. Treat the boundary as the worst-case privilege you are willing to grant, not as a fence around the obvious bad stuff.
Boundaries do not replace SCPs
We have seen teams try to use boundaries to enforce account-wide rules. It does not work, because boundaries only apply to the principals you remember to attach them to. If a future admin creates a role and forgets the boundary, the rule is not enforced. SCPs apply to everyone unconditionally. Use boundaries for delegated patterns where you control the role creation flow; use SCPs for invariants that must hold across every principal in the account.
The clients who get this layered model right are the ones whose developers stop filing IAM tickets. The ones who do not end up with a security team that is also a permissions help desk.
Read more field notes, explore our services, or get in touch at info@bipi.in. Privacy Policy · Terms.