skip to content

Permissions Boundaries & Delegated Admin

A permissions boundary is a ceiling, not a grant: it caps what an identity policy can ever authorize. It is how I let a team create its own roles without letting them mint an admin, so it pairs naturally with privilege-escalation questions.

part ofAWSoverview, primer and where to startread it →
on this pageshow

questions

4

An AWS IAM role has the AWS managed policy AdministratorAccess attached as its identity policy and also has a permissions boundary that allows only s3:* and cloudwatch:*. What can the role actually do, and what could it do if the boundary were the only policy attached to it?

level: juniorimportance: must knowfreq 45%

answer

  1. one document, two possible slots
  2. filter, not a grant
  3. intersection of two allow sets
  4. boundary alone permits nothing
  5. explicit deny still wins over both

basics

~20 s

Effective permissions are the intersection of the two, so the role can call only S3 and CloudWatch actions. A permissions boundary never grants anything, so with the boundary alone and no identity policy the role could do nothing.

solid answer

~40 s

A permissions boundary is a ceiling, not a grant. For identity-based permissions, the effective set is the intersection of what the identity policies allow and what the boundary allows, so `AdministratorAccess` plus an `s3:*`/`cloudwatch:*` boundary yields exactly S3 and CloudWatch — every other call fails with an implicit deny, even though the attached policy says `Action: "*"`. Reverse the setup and you get nothing: the boundary's `Allow` statements are only a filter, so a role with a boundary and no identity policy has zero permissions. That asymmetry is the whole point — an IAM admin can hand a team a broad-looking policy and still be certain the identity can never exceed the ceiling. Explicit `Deny` anywhere still wins regardless of the boundary.

code

json · 10 lines
json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["s3:*", "cloudwatch:*"],
      "Resource": "*"
    }
  ]
}

go deeper

for a junior

Be ready to say plainly that effective permissions are the intersection, and that a boundary on its own grants nothing. Knowing which of the two documents is the grant is the whole answer here.

for a middle

Explain the mechanics: one managed policy per entity, users and roles only, set at create time or via PutRolePermissionsBoundary, and the default implicit deny that makes an unmentioned service fail.

for a senior

Show how this surfaces in production — an AccessDenied that a correct policy does not explain, found by checking the entity's PermissionsBoundary field before rewriting the policy again.

for a principal

Own the argument for why the asymmetry matters organizationally: a cap the delegated team cannot widen is what lets you push policy authorship down to teams without reviewing every policy they write.

## What a permissions boundary is A permissions boundary is a **managed policy attached to an IAM user or role in a special slot** — not as one of its permission policies, but as a cap on them. AWS evaluates the same JSON document you would write for an identity policy, but in this slot the document answers a different question: not "what may this identity do?" but "what is this identity *ever* allowed to be given?" You set it when creating the entity (`aws iam create-role --permissions-boundary <policy-arn>`) or afterwards with `iam:PutRolePermissionsBoundary` / `iam:PutUserPermissionsBoundary`, and you remove it with `iam:DeleteRolePermissionsBoundary` / `iam:DeleteUserPermissionsBoundary`. Each entity has at most **one** boundary, and it must be a managed policy (AWS-managed or customer-managed) — an inline policy cannot serve as a boundary. Boundaries attach to users and roles only; there is no boundary slot on an IAM group. ## The intersection rule For an identity-based request, a permission survives only if **both** sides allow it: - the identity's policies (attached managed policies, inline policies, and for a user, its group policies) allow the action, **and** - the boundary allows the same action. So `AdministratorAccess` (`"Action": "*", "Resource": "*"`) intersected with a boundary of `s3:*` plus `cloudwatch:*` leaves precisely S3 and CloudWatch. A call to `ec2:RunInstances` is denied — not by an explicit `Deny`, but because the boundary contains no matching `Allow`, and IAM's default answer to "no applicable allow" is deny. ```json { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": ["s3:*", "cloudwatch:*"], "Resource": "*" } ] } ``` Attached as an identity policy, that document grants S3 and CloudWatch. Attached as a boundary, the identical document grants nothing — it only permits those services to be granted by something else. ## Why the reverse direction is the real teaching point Candidates who have only skimmed the feature often describe a boundary as "a policy that gives the role its maximum permissions", which quietly implies it grants them. It does not. A role carrying only a boundary and no identity policy is inert: every API call returns AccessDenied. This is exactly what makes the mechanism safe to delegate — an administrator can attach a boundary to a role *before* anyone writes its permissions, knowing that whatever policy is attached later cannot escape the cap. It also explains a common operational surprise: someone attaches a shiny new policy to a role to fix an AccessDenied, the policy is obviously correct, and the call still fails. The missing piece is usually a boundary that never mentioned that service. ## Boundaries and Deny A boundary changes only what can be *allowed*. It does not weaken denials anywhere else. An explicit `Deny` in the identity policy, in a resource policy, in a session policy, or in an organization-level control still wins outright — deny is never overridden by an allow, and the boundary has no power to re-permit something a deny has removed. Practically, this means a boundary is a *maximum*, and other controls can push the effective set lower, never higher. Equally, a boundary is not a substitute for the permissions on the target resource. Cross-account access, an S3 bucket policy, a KMS key policy — those are separate gates. A boundary that allows `s3:*` says nothing about whether some other account's bucket will accept the call. ## Reading a setup quickly When you see an entity with both, answer in two moves. First, list what the identity policies allow. Second, strike out everything the boundary does not also allow. What survives is the effective set. Then check for explicit denies, which remove more. Interviewers usually give the deliberately alarming version — an admin policy with a narrow boundary — because the intersection answer proves you know which document is the grant and which is the filter. ## A note on scope Boundaries live inside one account and cap one entity at a time. They are the right tool when you want a specific user or role to stay under a ceiling, and especially when you want to let someone else write that entity's policies. They are not an account-wide control and not a session-lifetime control; those are different mechanisms with different attachment points.

  • If the role's identity policy allows s3:* but the boundary allows nothing for S3, and a bucket policy in the same account grants s3:GetObject to that role, what should you expect?
    Treat the boundary as capping the role's identity-based permissions, so an S3 call authorized only through the role's own policies fails. Resource policies are a separate gate with their own evaluation rules, so never reason about them from the boundary alone — test the exact call with the IAM policy simulator or a dry run rather than assuming.
  • Can you attach two permissions boundaries to one role to combine two caps?
    No. An entity has at most one permissions boundary, and it must be a single managed policy. If you need a combined cap, author one policy document that expresses it. That single-slot design is deliberate: a reviewer can find the ceiling for an entity by reading exactly one document rather than reconciling several.
  • How would you diagnose an AccessDenied that a correct-looking identity policy does not explain?
    Check whether the entity carries a permissions boundary — `aws iam get-role` shows it in the `PermissionsBoundary` field. Then read that policy for the action in question. The IAM policy simulator reports which policy type produced the denial, which distinguishes a boundary cap from a missing allow or an explicit deny.

saying these in an interview costs you the question

  • Says the boundary grants the role its maximum permissions
  • Answers that AdministratorAccess wins because it is broader
  • Thinks a boundary alone makes the role usable
  • Believes a boundary can override an explicit Deny
  • Confuses the boundary slot with just another attached policy

context

open as a page

In AWS, compare a permissions boundary, a service control policy (SCP) and a session policy: what does each attach to, who controls it, and can any of them grant a permission?

level: middleimportance: should knowfreq 52%

basics

~20 s

All three are caps and none grants anything. A permissions boundary attaches to one IAM user or role, an SCP attaches to an organization root, OU or account, and a session policy is passed at AssumeRole time and lives only for that session.

open as a page

An application team wants to create its own IAM roles in an AWS account instead of filing tickets with the platform team, but must never be able to create a role with administrator permissions. How do you delegate iam:CreateRole safely, and what else must the delegation policy lock down?

level: seniorimportance: should knowfreq 38%

basics

~20 s

Grant the IAM write actions only with a StringEquals condition on the iam:PermissionsBoundary key naming your boundary policy, so every role they create carries the cap. Then explicitly deny removing or replacing that boundary, editing the boundary policy itself, and passing roles they should not.

open as a page

Many product teams at your company need self-service on AWS. How would you decide between giving each team its own AWS account governed by organization-level policies and keeping teams together in shared accounts governed by permissions boundaries?

level: principalimportance: nice to knowfreq 26%

basics

~20 s

Separate accounts give hard isolation of blast radius, quotas and billing with guardrails teams cannot lift, at the cost of account sprawl and cross-account plumbing. Permissions boundaries are cheaper and finer-grained but sit inside one account, so they cap identities without isolating resources.

open as a page