The IAM evaluation model
Deny wins, ceilings are conjunctive, grants additive.
IAM is the control plane of AWS security — every API call is an authorization decision, and getting the mental model exact is what separates a reviewer who spots an escalation path from one who waves it through. The decision is not "does a policy allow this?" but the interaction of several policy types with ceilings that override grants.
The evaluation order, precisely
For any request AWS starts denied by default. An explicit Deny in any policy — identity, resource, SCP, or permission boundary — wins immediately and ends the decision. Otherwise the action is allowed only if it is permitted by the identity or resource policy AND permitted by any permission boundary AND permitted by every SCP in the account path. Grants are additive; ceilings are conjunctive; a single Deny anywhere is absolute.
# A boundary lets you delegate role creation WITHOUT allowing escalation:# whatever policy a team lead attaches, the role can never exceed this.{"Version": "2012-10-17","Statement": [{ "Effect": "Allow", "Action": ["s3:*","dynamodb:*","logs:*","cloudwatch:*"], "Resource": "*" },{ "Effect": "Deny", "Action": ["iam:*","organizations:*","account:*"], "Resource": "*" }]}# The lead can now mint app roles freely, but cannot create an admin role —# the boundary denies iam:* even if their own grant allows it.
Least privilege that survives contact with reality
A wildcard "Action":"*" on "Resource":"*" grants full control of everything — the opposite of least privilege. Scope actions and resources to what a principal actually uses, lean on conditions (source VPC, tag, MFA present), and use IAM Access Analyzer to surface unintended external access and unused permissions you can prune. The goal is a policy where every statement answers "which principal, doing what, to which resource, under what condition".