Anatomy of an IAM Policy
An IAM policy is a JSON document made up of one or more statements, each with an Effect (Allow or Deny), an Action (or list of actions, such as s3:GetObject), a Resource (the ARN the action applies to), and optionally a Condition that narrows when the statement applies — for example, requiring MFA or restricting by source IP. Policies come in two broad flavors: identity-based policies, attached to a user, group, or role, and resource-based policies, attached directly to a resource like an S3 bucket or an SQS queue, which additionally require a Principal element specifying who the statement applies to.
Cricket analogy: A policy statement is like an umpire's ruling structure — Effect is the decision (out or not out), Action is the specific appeal type (LBW, caught), Resource is the specific delivery in question, and Condition is the extra context, like whether DRS confirms the ball was hitting the stumps.
Policy Evaluation Logic: Explicit Deny Wins
When AWS evaluates whether a request is allowed, it starts from an implicit deny — nothing is permitted unless something explicitly allows it. It then checks all applicable policies: organization-level Service Control Policies (SCPs), resource-based policies, identity-based policies, permissions boundaries, and session policies. If any statement anywhere contains an explicit Deny, the request is denied, full stop, regardless of how many Allow statements exist elsewhere. Only if there is at least one applicable Allow and no explicit Deny does the request succeed. This is why a permissions boundary or an SCP can be used to enforce hard limits — a Deny at that layer overrides even an administrator-granted Allow on a user's own policy.
Cricket analogy: Explicit deny is like a third umpire's 'Not Out' call being overturned by a clear no-ball signal from the square-leg umpire — no matter how favorable every other angle of review looks, one definitive deny signal ends the discussion instantly.
Least Privilege and Policy Conditions
The principle of least privilege means granting only the specific actions on the specific resources a principal actually needs, rather than broad wildcards like 's3:*' on 'Resource: *'. Condition blocks make this practical: you can require aws:MultiFactorAuthPresent for sensitive actions, restrict aws:SourceIp to a corporate VPN range, limit s3:x-amz-server-side-encryption to enforce encrypted uploads, or use aws:RequestedRegion to block resource creation outside approved regions. AWS Policy Simulator and IAM Access Analyzer are the practical tools for validating that a policy grants exactly the intended access — Access Analyzer specifically flags resources shared with entities outside your account or organization, which is invaluable for catching accidental over-sharing.
Cricket analogy: Conditions on a policy are like a stadium pass that only works for gate entry between 9 AM and match start — the pass (Allow) is real, but the Condition narrows exactly when and how it can be used, closing off misuse outside match hours.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowS3ReadWithMFA",
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:ListBucket"],
"Resource": [
"arn:aws:s3:::reports-bucket",
"arn:aws:s3:::reports-bucket/*"
],
"Condition": {
"Bool": { "aws:MultiFactorAuthPresent": "true" },
"IpAddress": { "aws:SourceIp": "203.0.113.0/24" }
}
}
]
}An explicit Deny always wins, even against an Allow granted elsewhere by an account administrator. This is intentional and is the mechanism behind Service Control Policies and permissions boundaries, but it also means a stray Deny statement — perhaps copy-pasted from another policy — can silently lock out access in a way that's confusing to debug if you don't check every applicable policy layer.
- An IAM policy statement has an Effect, Action, Resource, and optional Condition (resource-based policies also require a Principal).
- Access is denied by default (implicit deny); at least one Allow is required for a request to succeed.
- An explicit Deny in any applicable policy always overrides any Allow, no matter where the Allow comes from.
- Service Control Policies and permissions boundaries use explicit-deny logic to enforce organization-wide hard limits.
- Least privilege means scoping Action and Resource as tightly as possible instead of using wildcards.
- Condition keys like aws:MultiFactorAuthPresent and aws:SourceIp let you narrow exactly when a grant applies.
- IAM Access Analyzer and Policy Simulator help validate policies and catch accidental external resource sharing.
Practice what you learned
1. What is the default access outcome for an AWS request with no applicable policy statements at all?
2. If one policy attached to a role has an explicit Allow for an action, but a Service Control Policy has an explicit Deny for the same action, what happens?
3. Which element is required in a resource-based policy statement but not typically required in an identity-based policy?
4. What does the aws:MultiFactorAuthPresent condition key allow you to enforce?
5. What is the primary purpose of AWS IAM Access Analyzer?
Was this page helpful?
You May Also Like
IAM Users, Groups, and Roles
AWS Identity and Access Management (IAM) defines who or what can act in your account, using users, groups, and roles as the core identity building blocks.
AWS KMS Basics
AWS Key Management Service (KMS) creates and controls the cryptographic keys used to encrypt data across AWS services, without exposing the underlying key material.
DynamoDB Basics
Amazon DynamoDB is a fully managed, serverless NoSQL key-value and document database designed for single-digit-millisecond performance at any scale.