Skip to content
AWS aws iam 5 min read

Permission Boundaries

A permission boundary is a special policy you attach to an IAM (Identity and Access Management — AWS’s system for controlling who can do what) user or role that sets the maximum permissions that identity can ever have. It does not grant anything by itself. Instead, it acts like a ceiling: no matter how generous the policies attached to the user or role are, the actual allowed actions can never rise above the boundary. This matters most when you want to let other teams create their own roles and policies without being able to escalate their own privileges.

How a permission boundary works

To understand boundaries, you need to know how IAM decides whether a request is allowed. By default everything is denied. An action is only allowed if a policy explicitly allows it and nothing explicitly denies it.

When a permission boundary is attached, AWS adds one more rule. The action must be allowed by both the identity’s own policies and the boundary. In other words, the effective permission is the intersection of the two.

Identity policy saysBoundary saysEffective result
Allow s3:*Allow s3:GetObjectOnly s3:GetObject is allowed
Allow ec2:*Allow s3:*Nothing allowed (no overlap)
Allow nothingAllow s3:*Nothing allowed (boundary never grants)
Allow s3:GetObject(no boundary)s3:GetObject allowed

The key takeaway: a boundary can only ever remove permissions. It never adds them. If you forget to grant a permission in the identity policy, the boundary will not magically supply it.

When to use this (and when not to)

Use a permission boundary when:

  • You want to delegate permission management to developers or team leads, but stop them from granting themselves admin rights.
  • You run a self-service platform where engineers create roles for their own applications.
  • You want a safety net so a misconfigured policy cannot exceed an agreed limit.

Do not use a permission boundary when:

  • You simply want to grant permissions. Use a normal identity policy instead.
  • You want to enforce rules across a whole AWS account or organization. For that, use a Service Control Policy (SCP), which works at the account or organizational-unit level rather than per identity.
  • You are the only person managing IAM and trust yourself. Boundaries add complexity that small setups rarely need.

The delegation use case

The classic reason boundaries exist is safe delegation. Imagine you want to let a developer create roles for their Lambda functions, but you never want those roles to touch IAM or billing.

You do two things:

  1. Create a boundary policy that defines the absolute maximum (for example, full access to S3, DynamoDB, and CloudWatch Logs, but nothing else).
  2. Give the developer permission to create roles only if they attach that exact boundary to every role they create.

That second condition is enforced using a policy condition key called iam:PermissionsBoundary. The developer can be as creative as they like with their own policies, but every role they produce is silently capped by your boundary.

Console steps — create a boundary policy

  1. Open the IAM console and choose Policies in the left menu.
  2. Click Create policy, switch to the JSON tab, and paste the maximum-permissions document.
  3. Click Next, name it team-boundary, and click Create policy. (A boundary is just an ordinary managed policy; what makes it a boundary is how it is attached.)

CLI — create the boundary and attach it

aws iam create-policy \
  --policy-name team-boundary \
  --policy-document file://team-boundary.json

Output:

{
    "Policy": {
        "PolicyName": "team-boundary",
        "Arn": "arn:aws:iam::123456789012:policy/team-boundary",
        "DefaultVersionId": "v1",
        "AttachmentCount": 0
    }
}

Now attach that boundary to an existing role:

aws iam put-role-permissions-boundary \
  --role-name app-deploy-role \
  --permissions-boundary arn:aws:iam::123456789012:policy/team-boundary

Output: (this command returns no output on success)

Forcing the boundary during delegation

The developer’s own permissions should include a condition that they may only create roles carrying your boundary. Here is the delegation policy you give them:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["iam:CreateRole", "iam:AttachRolePolicy"],
      "Resource": "arn:aws:iam::123456789012:role/dev/*",
      "Condition": {
        "StringEquals": {
          "iam:PermissionsBoundary": "arn:aws:iam::123456789012:policy/team-boundary"
        }
      }
    }
  ]
}

If the developer tries to create a role without attaching team-boundary, the request is denied. They cannot escape the ceiling you set.

The big gotcha — boundaries only limit, never grant

This is where most teams get burned. The full evaluation for an IAM principal is:

Effective permission = identity policy AND permission boundary AND any SCP (and not blocked by any explicit Deny).

Every one of those layers must say “allow” for the action to succeed. If your boundary is too narrow, it silently strips permissions that the identity policy clearly grants. There is no error at attach time and nothing in the policy looks wrong, so the breakage can be confusing.

Warning: An over-restrictive boundary fails closed and silently. A role can have AdministratorAccess attached and still be unable to read a single S3 bucket if the boundary does not also allow it. When something “should work but doesn’t,” check the boundary first.

To diagnose this, use the IAM Policy Simulator or the aws iam simulate-principal-policy command, which both account for the attached boundary when they show you whether an action is allowed.

Best practices

  • Treat the boundary as the maximum blast radius. Define it broadly enough that normal work succeeds, but narrow enough to block dangerous services like IAM, Organizations, and billing.
  • Always pair delegation with the iam:PermissionsBoundary condition so delegated users cannot create roles that escape the ceiling.
  • Never rely on a boundary to grant access. Grant in the identity policy; cap with the boundary.
  • Use a small number of named boundaries (for example, team-boundary, readonly-boundary) rather than one per role, so they stay easy to reason about.
  • Test changes with the Policy Simulator before rolling a new boundary out to production roles.
  • Document which roles carry which boundary, because the cap is invisible unless you go looking for it.
Last updated June 15, 2026
Was this helpful?