IAM Policy Evaluation Logic Explained: Why Your Allow Does Not Work

2–3 minutes

Updated

Short answer: AWS evaluates every request against all policies that apply. It starts from an implicit deny, an explicit Deny anywhere ends the evaluation, and an Allow only works if every other layer that applies also allows it.

The evaluation order

  1. Explicit Deny in any policy: the request is denied. Nothing overrides it.
  2. Organizations SCPs and RCPs: if they apply to the account and do not allow the action, it is denied.
  3. Resource-based policy (for example a bucket policy): can grant access on its own in the same account.
  4. Permissions boundary: caps what the identity can do. The action must be inside it.
  5. Session policy (assumed-role sessions): caps the session further.
  6. Identity-based policy: must allow the action, unless a resource-based policy already did.

Simplified for a single account. Cross-account requests need an Allow on both sides: the identity policy in the caller account and the resource policy in the resource account.

Four situations where your Allow “does not work”

SituationWhat is really happening
Role has s3:* and still gets AccessDeniedA Deny in the bucket policy, an SCP or the KMS key policy
Admin in a member account cannot use a RegionAn SCP restricts aws:RequestedRegion
New role created by a pipeline cannot do what its policy saysA permissions boundary attached by the pipeline
Cross-account access works in one direction onlyOnly one side (identity or resource policy) allows it

Debug it with the tools AWS gives you

debug-iam.sh

# Which identity is actually making the call?
aws sts get-caller-identity

# Simulate a principal policy against an action and resource
aws iam simulate-principal-policy \
  --policy-source-arn arn:aws:iam::123456789012:role/app-role \
  --action-names s3:GetObject \
  --resource-arns arn:aws:s3:::my-bucket/reports/2026.csv

Many AccessDenied messages now include the type of policy that denied the request (for example “with an explicit deny in a service control policy”). Read the full message before changing anything.

The policy simulator does not evaluate every layer the same way the real request does (for example some resource policies and SCP details). Use it to narrow the cause, then confirm with CloudTrail.

Rules of thumb

  • Look for Deny statements first; they are the most common cause and the fastest to rule out.
  • Check the resource ARN format: bucket ARN versus object ARN (bucket/*) is a classic mistake.
  • For encrypted data, the KMS key policy is part of the decision.

Joniel Gallo · Cloud & AI Engineer

I build these labs in a real AWS account and publish the code. Need a second opinion on your architecture or your AWS bill? Work with me.

One tested AWS & AI lab a week

Real costs, working code and what changed in Bedrock this month. Subscribe and get the free AWS Permission Debugger (PDF).