Conditions & evaluation
How AWS evaluates policies (and why explicit deny wins)
Every request starts as an implicit deny; one explicit deny anywhere ends evaluation. Walk through the evaluation chain and the cross-account rule that both accounts must allow.
Published · Updated .
When an IAM role's request is denied, the instinct is to add another Allow. That fails whenever the cause is an explicit deny, a guardrail or a missing grant on the other side of an account boundary. Knowing the order AWS evaluates policies in turns “why is this denied?” from guesswork into a checklist.
Two rules that never change
- Default deny. Every request starts as an implicit deny. Only the account root user starts with full access, and even the root user of a member account is limited by SCPs.
- Explicit deny wins. If any applicable policy contains a Deny statement that matches the request, the request is denied. No Allow can override it.
The evaluation sequence (single account)
AWS's enforcement code checks applicable policies in this order:
- Explicit deny check across all applicable policies: SCPs, RCPs, resource-based policies, identity-based policies, permissions boundaries and session policies. Any match: Deny.
- Resource control policies (RCPs) on the resource's account. If they do not allow the action: Deny. (When RCPs are enabled, AWS attaches
RCPFullAWSAccess, which cannot be detached.) - Service control policies (SCPs) on the principal's account. If they do not allow the action: Deny.
- Resource-based policies. In the same account, an Allow that names the IAM user, or the role session making the request, can produce a final Allow even if identity policies, boundaries or session policies would implicitly deny. An Allow naming the role ARN is still subject to the role's boundary and session policies.
- Identity-based policies. If none allows the action: Deny.
- Permissions boundary, if the user or role has one. If it does not allow the action: Deny.
- Session policies, if the request comes from a session created with one. If it does not allow the action: Deny. Otherwise: Allow.
Cross-account requests
When the principal and the resource are in different accounts, the request needs an Allow from the resource side (a resource-based policy naming the principal, or a role the principal can assume) and an Allow from the principal's own account (identity policy, within its boundary and SCPs). Guardrails on both sides apply: the caller's SCPs and the resource owner's RCPs.
Worked scenarios
| Scenario | Result | Why |
|---|---|---|
| Identity policy allows s3:GetObject; nothing else applies | Allow | An explicit Allow and no Deny anywhere. |
| Identity policy allows; bucket policy denies non-TLS; request over HTTP | Deny | One explicit Deny ends evaluation, whatever else allows. |
| Identity policy allows; the account's SCPs do not allow the action | Deny | SCPs set the ceiling; an action not allowed by every SCP level is denied. |
| Role's identity policy allows; its permissions boundary does not include the action | Deny | Identity policy and boundary must both allow (implicit deny in the boundary). |
| Same account: bucket policy grants the role session ARN; no identity policy allows | Allow | A resource-based grant to the session principal is not limited by implicit denies. |
| Cross-account: bucket policy grants an external role; that role has no identity policy for S3 | Deny | Across accounts, both accounts must allow. |
The second scenario uses a guardrail like this one. It denies everyone, but only for plain-HTTP requests:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyInsecureTransport",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::amzn-s3-demo-bucket",
"arn:aws:s3:::amzn-s3-demo-bucket/*"
],
"Condition": {
"Bool": {
"aws:SecureTransport": "false"
}
}
}
]
}A debugging checklist
- Read the error. AWS access-denied messages name the type of policy responsible, for example “with an explicit deny in a service control policy” or “because no identity-based policy allows the … action”. That points straight at the step above that failed.
- Check CloudTrail for the denied event: the
userIdentityshows which principal and session actually made the call. It is often not the one you expected. - Simulate identity policies with
aws iam simulate-principal-policyorsimulate-custom-policy, supplying context keys for conditions. Check the simulator documentation for which policy types it includes for your scenario. - Look outside the account for cross-account and organisation-level policies, which account-level administrators often cannot see.
Related: identity vs. resource-based policies and boundaries vs. SCPs.