IAM Policy Types and Evaluation
Policy types
Section titled “Policy types”- Identity-based policies
- Attached to IAM users, groups or roles
- Define what actions the identity may perform, on which resources
- AWS managed, customer managed, or inline
- Resource-based policies
- Attached directly to a resource — an S3 bucket, an SQS queue, a KMS key, an IAM role’s trust policy
- Define who may access the resource and what they may do
- Always inline on the resource, and they must include a
Principalelement
- Permissions boundaries
- Set the maximum permissions an identity can have
- Grant nothing on their own — the effective permissions are the intersection of the boundary and the identity-based policy
- Used to delegate administration safely: a developer may create roles, but not roles more powerful than the boundary allows
- Service control policies and resource control policies
- Organisation-level guardrails that cap what member accounts may do, and what may be done to their resources
- Grant nothing. See Controlling access in AWS Organizations
- Session policies
- Passed when a role is assumed, to narrow that particular session below the role’s own permissions
Policy structure
Section titled “Policy structure”{ "Version": "2012-10-17", "Statement": [ { "Sid": "AllowObjectAccessFromOfficeRange", "Effect": "Allow", "Action": ["s3:GetObject", "s3:PutObject"], "Resource": "arn:aws:s3:::example-bucket/*", "Condition": { "IpAddress": { "aws:SourceIp": "203.0.113.0/24" } } } ]}Effect
Section titled “Effect”- Allow grants the listed actions.
- Deny refuses them.
- An explicit
Denyanywhere always wins, in any policy type.
Action
Section titled “Action”- Namespaced by service:
s3:,ec2:,kms: - Wildcards are permitted:
s3:*for every action in a service,s3:Get*for every Get action,s3:*Objectfor every action ending in Object - A wildcard in
Actioncombined with a wildcard inResourceis the shape most likely to be flagged in a review, and usually the shape that should be narrowed
Resource
Section titled “Resource”- Identified by ARN:
arn:partition:service:region:account-id:resource-type/resource-id - Wildcards may match several resources
- The resource must be one the action actually applies to —
s3:ListBucketacts on the bucket ARN,s3:GetObjecton the object ARN, and mixing them is the most common reason a bucket policy silently does nothing
Condition
Section titled “Condition”Common operators:
- Strings:
StringEquals,StringNotEquals,StringLike - Numbers:
NumericEquals,NumericGreaterThan - Dates:
DateEquals,DateGreaterThan,DateLessThan - Booleans:
Bool—aws:MultiFactorAuthPresentis the common one - Addresses:
IpAddress,NotIpAddress - ARNs:
ArnEquals,ArnLike
Condition keys come from AWS global context (aws:SourceIp, aws:RequestedRegion,
aws:PrincipalOrgID, aws:PrincipalTag/*, aws:ResourceTag/*) and from the individual
services.
Evaluation logic
Section titled “Evaluation logic”For a request within a single account:
- Everything is denied by default — an implicit deny.
- An explicit allow in any applicable policy overrides the implicit deny.
- An explicit deny in any applicable policy overrides every allow.
- All applicable policies are evaluated together, not in sequence. Identity-based policies, resource-based policies, permissions boundaries, session policies, SCPs and RCPs all participate.
For a cross-account request, both accounts must allow it: the identity-based policy in the calling account, and the resource-based policy (or an assumed role’s trust and permission policies) in the account that owns the resource.
Worked examples
Section titled “Worked examples”An EC2 instance reading and writing two buckets
Section titled “An EC2 instance reading and writing two buckets”Attached to the role in the instance profile:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "s3:GetObject", "s3:PutObject" ], "Resource": [ "arn:aws:s3:::product-data/*", "arn:aws:s3:::production-logs/*" ] } ]}A bucket shared with another account
Section titled “A bucket shared with another account”Attached to the bucket, in the account that owns it:
{ "Version": "2012-10-17", "Statement": [ { "Sid": "AllowPartnerAccountRead", "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::123456789012:role/PartnerReadRole" }, "Action": "s3:GetObject", "Resource": "arn:aws:s3:::example-bucket/*" } ]}Naming the specific role rather than the account root narrows the grant to the one identity that should hold it, instead of delegating to the other account’s administrators.
Practice
Section titled “Practice”- Grant the least privilege that works: specific actions, specific resource ARNs.
- Attach policies to groups and roles, not to individual users.
- Use roles for applications and AWS services rather than access keys.
- Use conditions to add context — MFA present, request from a known network, resource carrying the right tag, request in an approved Region.
- Review policies against what is actually used. IAM service last accessed data and IAM Access Analyzer both turn this into a concrete list.
- Test with the IAM policy simulator before attaching, and check the results of a change against a real caller afterwards.