How AWS IAM Policy Evaluation Works
AWS IAM policy evaluation determines whether a principal may perform an action on an AWS resource. It combines policies attached to the identity, policies attached to the resource, permission limits, and organization-wide controls to produce an allow or deny decision.
The problem it solves is that AWS authorization is distributed. A user may belong to a group, assume a role, access an S3 bucket with its own policy, and be subject to an AWS Organizations restriction—all in one request. Without a consistent evaluation model, each service would need a different answer to “may this request proceed?” IAM evaluates the relevant rules together instead.
The policy types
A principal is the identity making the request: an IAM user, role, or role session. A resource is the thing being accessed, such as an S3 object, DynamoDB table, or KMS key. A policy is a JSON document containing statements that match actions, resources, principals, and optional conditions.
The main policy categories are:
- Identity-based policies are attached to users, groups, or roles. They say what actions that identity may perform on which resources. A policy attached to a group applies to its users; a policy attached to a role applies when someone uses that role.
- Resource-based policies are attached to resources. They say which principals may perform which actions. S3 bucket policies, SQS queue policies, SNS topic policies, and KMS key policies are common examples.
- A permissions boundary is a policy that sets the maximum permissions an IAM user or role can receive from its identity-based policies. It is a limit, not an additional grant.
- An organization control is a policy applied through AWS Organizations. A service control policy (SCP) limits the maximum permissions available to accounts, organizational units, or the organization root. A resource control policy (RCP) limits permissions on supported resources. Neither type grants access by itself.
A request also has a principal session: the temporary execution context created when a role is assumed or a user obtains temporary credentials. Session policies can impose another limit, although they are not required to understand the four policy categories in this article.
Start with the request
When AWS receives a request, it identifies the principal, action, resource, account, and context such as the source IP, requested region, tags, or whether MFA was used. It then looks for policy statements whose Action, Resource, Principal, and Condition match that request.
For example, this identity policy allows a role to read objects in one bucket:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::reports-example/*"
}
]
}
A matching statement with "Effect": "Allow" contributes an allow. A matching statement with "Effect": "Deny" contributes an explicit deny. A statement that does not match contributes nothing.
If no applicable policy allows the request, the result is an implicit deny. That is the default: permission is absent unless an applicable policy grants it. An implicit deny is different from an explicit deny because it means no allow was found, not that a deny statement specifically matched.
Combining identity and resource policies
For a request within one AWS account, an allow in an applicable identity-based policy or an applicable resource-based policy can generally provide the required permission. Their allows form a union: either side can supply an allow.
This is why a bucket policy can grant access to a principal without editing that principal’s identity policy. Conversely, an identity policy can grant access to a resource whose policy does not itself name that principal, provided the service supports that authorization pattern.
Cross-account access normally requires cooperation from both accounts. The principal’s account must authorize the action through an identity-based policy, and the resource’s account must authorize it through a resource-based policy or an appropriate resource-owner mechanism. An allow in only one account is not enough.
There are important service and principal details behind this simplified rule. For example, a resource policy that names an IAM role session ARN directly can grant permissions to that session in ways that are not limited by the role’s permissions boundary or session policy. A resource policy that names the role ARN instead is evaluated differently: the role’s identity permissions and limits remain relevant. When troubleshooting an unusual result, check whether the policy names a user, role, or role session—not just the friendly name shown in the console.
Boundaries and organization controls
For ordinary identity-based authorization, a permissions boundary acts like an intersection:
The identity policy may allow an action, but the boundary must also allow it.
A boundary cannot create permission that the identity policy did not grant. If a role policy allows s3:GetObject but its boundary does not, the role cannot use that permission through the normal identity-based path.
SCPs and RCPs work similarly as maximum-permission filters. An SCP can say, in effect, “even if an account’s policies allow this action, the organization does not permit it.” An RCP applies the corresponding kind of organization limit to supported resources. The account still needs an ordinary identity- or resource-based allow; an organization policy is not an allow list that grants access on its own.
The effective result can therefore be pictured as several requirements:
- An applicable identity-based or resource-based policy must allow the request.
- Any applicable boundary or session limit must permit it.
- Applicable SCP and RCP limits must permit it.
- No applicable policy may explicitly deny it.
This is a useful mental model, but service-specific behavior and resource-policy principal types can change which limits apply. IAM documentation describes those exceptions for each authorization path.
Why explicit deny always wins
IAM evaluates an explicit deny as a veto. If any applicable statement says "Effect": "Deny", the request is denied even when several other policies say Allow.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Action": "s3:DeleteObject",
"Resource": "arn:aws:s3:::reports-example/*"
}
]
}
This lets administrators write broad grants and then carve out non-negotiable restrictions: deny access outside approved regions, deny deletion of protected data, or deny actions unless a required condition is present. The deny must still match the actual request; an unrelated deny does not affect it.
The model explains familiar errors such as AccessDenied and messages saying an action is blocked by an SCP or permissions boundary. Start by identifying the exact principal, action, resource, and context, then find both the missing allow and any matching explicit deny. IAM is not asking which single policy “wins”; it is evaluating the complete set of applicable grants and limits, with an explicit deny overriding every allow.