AWS Organizations
Permissions boundaries vs. SCPs
Both cap permissions without granting any. SCPs apply to whole accounts and are managed centrally; boundaries apply to individual users or roles and make delegated IAM administration safe.
Published · Updated .
Permissions boundaries and service control policies are both ceilings: neither grants anything, and both can stop an identity from using a permission its policies allow. They solve different problems, though, and many accounts need both.
Side by side
| Question | Permissions boundary | Service control policy |
|---|---|---|
| Attached to | One IAM user or role (a managed policy set as its boundary) | Organisation root, OU or member account |
| Managed by | IAM administrators in the account | The management account (or a delegated policy administrator) |
| Affects the account root user | No (boundaries apply to users and roles) | Yes, in member accounts |
| Typical purpose | Safe delegation of IAM administration | Organisation-wide guardrails |
| Grants permissions | Never | Never |
How they combine
For a request from a role in a member account that has a boundary, the action must be allowed by the role's identity-based policy, by its boundary, and by every SCP above the account. An explicit deny in any of them ends the evaluation. This is an intersection: adding a boundary or an SCP can only reduce effective permissions.
One nuance concerns resource-based policies in the same account. If a bucket or secret policy grants access to an IAM user ARN or to a role session ARN, an implicit deny in the boundary does not limit that grant. A resource-based policy that grants to the role ARN is still limited by the boundary. An explicit Deny in the boundary always applies.
The main use case: delegating IAM administration
Without boundaries, letting an application team create its own roles is equivalent to giving it administrator access: it could create a role with AdministratorAccess and use it. With a mandatory boundary, the team can create and edit roles freely, and no role it creates can exceed the boundary.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "CreateAppRolesWithBoundary",
"Effect": "Allow",
"Action": [
"iam:CreateRole",
"iam:PutRolePermissionsBoundary"
],
"Resource": "arn:aws:iam::111122223333:role/app/*",
"Condition": {
"StringEquals": {
"iam:PermissionsBoundary": "arn:aws:iam::111122223333:policy/AppWorkloadBoundary"
}
}
},
{
"Sid": "ManageBoundedAppRoles",
"Effect": "Allow",
"Action": [
"iam:AttachRolePolicy",
"iam:DetachRolePolicy",
"iam:PutRolePolicy",
"iam:DeleteRolePolicy",
"iam:UpdateAssumeRolePolicy",
"iam:UpdateRole",
"iam:UpdateRoleDescription",
"iam:DeleteRole"
],
"Resource": "arn:aws:iam::111122223333:role/app/*",
"Condition": {
"StringEquals": {
"iam:PermissionsBoundary": "arn:aws:iam::111122223333:policy/AppWorkloadBoundary"
}
}
},
{
"Sid": "ReadIamForTroubleshooting",
"Effect": "Allow",
"Action": [
"iam:GetRole",
"iam:GetRolePolicy",
"iam:ListRoles",
"iam:ListRolePolicies",
"iam:ListAttachedRolePolicies",
"iam:GetPolicy",
"iam:GetPolicyVersion",
"iam:ListPolicies",
"iam:ListPolicyVersions",
"iam:SimulatePrincipalPolicy",
"iam:SimulateCustomPolicy"
],
"Resource": "*"
},
{
"Sid": "DenyRoleCreationWithoutBoundary",
"Effect": "Deny",
"Action": [
"iam:CreateRole",
"iam:PutRolePermissionsBoundary"
],
"Resource": "*",
"Condition": {
"StringNotEquals": {
"iam:PermissionsBoundary": "arn:aws:iam::111122223333:policy/AppWorkloadBoundary"
}
}
},
{
"Sid": "DenyBoundaryRemoval",
"Effect": "Deny",
"Action": "iam:DeleteRolePermissionsBoundary",
"Resource": "*"
},
{
"Sid": "DenyEditsToGuardrailPolicies",
"Effect": "Deny",
"Action": [
"iam:CreatePolicyVersion",
"iam:DeletePolicy",
"iam:DeletePolicyVersion",
"iam:SetDefaultPolicyVersion"
],
"Resource": [
"arn:aws:iam::111122223333:policy/AppWorkloadBoundary",
"arn:aws:iam::111122223333:policy/AppTeamIamAdmin"
]
}
]
}Three details make this safe: iam:PermissionsBoundary conditions on creating and editing roles, the /app/ path that limits which roles the team can touch, and the Deny that stops anyone removing the boundary or editing the boundary policy itself. The team also needs to pass these roles to services, scoped the same way:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PassAppRolesToLambdaOnly",
"Effect": "Allow",
"Action": "iam:PassRole",
"Resource": "arn:aws:iam::111122223333:role/app/*",
"Condition": {
"StringEquals": {
"iam:PassedToService": "lambda.amazonaws.com"
}
}
}
]
}When to use which
- A rule that must hold for every identity in an account (Regions, logging, leaving the organisation): SCP.
- A ceiling for roles created by someone you delegate to: permissions boundary.
- No AWS Organizations, or a single account: boundaries (SCPs require Organizations with all features enabled).
- Guardrails on access to your resources from outside: resource-based policies or resource control policies (RCPs).
Common mistakes
- Expecting a boundary to grant permissions. A role with only a boundary attached can do nothing.
- Forgetting to protect the boundary policy, so the delegated team can edit the ceiling.
- Delegating
iam:PassRoleon"*", which bypasses the boundary by passing an existing, more privileged role. - Testing an SCP from the management account, which SCPs never affect.
Verification
- As the delegated team, create a role without the boundary: expect AccessDenied.
- Create a role with the boundary, attach
AdministratorAccessto it, assume it, and try an action outside the boundary: expect AccessDenied that mentions a permissions boundary. - Try to delete the role's boundary or edit the boundary policy: expect an explicit deny.
Related: how AWS evaluates policies and SCP examples.