DevTools Hub

Search tools

Search for a developer tool

How AWS Evaluates Multiple IAM Policies

Part of the AWS Toolkit

IAM Policy Basics covers the three-rule core that's enough to reason about a single identity-based policy: deny by default, an explicit allow is required, an explicit deny always wins. That post is upfront about where it stops — real AWS accounts almost never evaluate just one policy. Permission boundaries, organization-level policies, and resource-based policies from another account all stack on top, and each one behaves differently: some of them grant access, others only put a ceiling on what's already been granted. Getting that distinction backwards is exactly how "my IAM policy allows this, why is it still denied" happens.

Two shapes: grants and ceilings

Per AWS's own policy evaluation logic reference, every extra policy layer falls into one of two categories, and they combine with your identity-based policy in opposite ways:

LayerCombines with identity-based policy viaCan it grant access by itself?
Resource-based policy (same account)Union — either side allowing is enoughYes
Permissions boundaryIntersection — both must allowNo — ceiling only
Service control policy (SCP)Intersection — both must allowNo — ceiling only
Resource control policy (RCP)Intersection — both must allowNo — ceiling only

A permissions boundary, SCP, or RCP never adds a permission — attaching one to an identity that already has broad access can only narrow what it can do, never widen it. This is the single most common source of confusion: someone adds a permissions boundary expecting it to grant the listed actions, when its entire job is the opposite — capping whatever the identity-based policy already allows.

The union case has two real exceptions

For most resource-based policies, an explicit Allow on either side — the identity-based policy or the resource-based policy — is enough to grant access, with an explicit deny on either side still overriding. Two resource types don't follow that rule: IAM role trust policies and AWS KMS key policies must explicitly allow the requesting principal regardless of what the identity-based policy says. This is why an IAM policy that includes sts:AssumeRole on a role's ARN still isn't enough on its own — the target role's own trust policy has to name that principal too, or the assumption fails no matter how permissive the caller's side is.

The full evaluation order

Within a single account, AWS checks every applicable policy for an explicit deny first, across all layers at once — if any one exists, the request is denied immediately and nothing else matters. If none is found, evaluation proceeds layer by layer:

  1. RCPs — must have an applicable Allow, or the request is denied. (An AWS-managed policy called RCPFullAWSAccess is auto-attached to every account and can't be removed, so an account with no custom RCP always has this default allow in place.)
  2. SCPs — same shape as RCPs, but scoped to what the principal can do rather than what the resource can be accessed by.
  3. Resource-based policies — can independently grant access per the union rule above (with the trust-policy/KMS exceptions).
  4. Identity-based policies — must have an applicable Allow, or the request is denied.
  5. Permissions boundary — must also allow the action, or the request is denied.
  6. Session policies — only relevant for a role session or federated-user session; if one was passed and doesn't allow the action, denied.

Every one of these checks has to pass for the request to succeed — a single unmet layer anywhere in the list ends it.

RCPs are the newest layer, and they run the opposite direction from SCPs

Resource control policies launched in November 2024 as the resource-side counterpart to SCPs. An SCP caps what a principal in the organization is allowed to do, full stop, regardless of which resource it targets. An RCP caps who's allowed to touch a resource, regardless of which principal is asking — useful for something like "no identity outside this organization can ever read from this S3 bucket," enforced centrally, that no single account's bucket policy could accidentally override. At launch, RCPs apply to S3, STS, KMS, SQS, and Secrets Manager — not every service yet.

Cross-account access needs an Allow from both accounts, independently

Everything above describes evaluation within one account. When the requesting principal is in a different account than the resource — the common "trusted account" (where the principal lives) and "trusting account" (where the resource lives) setup — AWS runs the entire evaluation twice, once against each account's applicable policies, and both have to independently come back Allow.

Say a role in Account A needs to write objects into an S3 bucket in Account B. Account A's side needs an identity-based policy on the role allowing s3:PutObject on that bucket's ARN. Account B's side needs a bucket policy naming Account A's role as the Principal and allowing the same action. Drop either one and the request fails — a generous bucket policy in Account B can't substitute for a missing identity-based policy in Account A, and the reverse is just as true. Both accounts are evaluated as fully separate single-account decisions per everything above (RCPs, SCPs, and permissions boundaries all still apply on the Account A side); the cross-account rule only adds the requirement that both decisions land on Allow.

What this means for testing a policy locally

IAM Policy Simulator on this site is deliberately scoped to identity-based policies only, for exactly the reason this post exists: a permissions boundary, an SCP, an RCP, or a resource-based policy from another account can each independently flip the real answer, and none of that is knowable from a pasted identity-based policy alone. A tool with no AWS credentials and no visibility into your organization's attached policies can tell you what one document says — it can't tell you what actually happens at request time. For that, AWS's own IAM Access Analyzer or the real iam:SimulatePrincipalPolicy API — which does have that visibility — is the only trustworthy source.

Try it yourself

IAM Policy Simulator, IAM Policy Viewer, and IAM Policy Generator all work with the identity-based-policy layer this post builds on top of. See IAM Policy Examples for a working role trust policy and a cross-account resource-based policy, the two shapes this post spends the most time on. For what permissions boundaries and SCPs are actually for in practice — beyond just being another ceiling in the evaluation order — see Enforcing Least Privilege at Scale. If a policy is deployed across an organization, AWS Tag Policy Validator covers the other AWS Organizations policy type — tag policies — with the same kind of document-level check. All of it runs entirely in your browser.

Related tools