JSON Policy Structure
IAM policies are JSON documents with a standard structure. Understanding each element is essential for writing correct and secure policies.
A policy contains a Version (always 2012-10-17), an optional Id, a Statement array with one or more statements, and each statement contains:
- Effect: Either
AlloworDeny. There is no implicit allow; unmentioned actions are implicitly denied. - Action: Specifies the API actions allowed or denied. Use
service:Actionformat likes3:GetObjector wildcards likes3:*. - Resource: The ARN(s) of the affected resources. Use
*for all resources, but prefer specific ARNs for least privilege. - Condition (optional): Conditions that must be true for the statement to apply, based on request context.
Example policy granting read access to a specific S3 bucket:
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:ListBucket"],
"Resource": [
"arn:aws:s3:::my-bucket",
"arn:aws:s3:::my-bucket/*"
]
}]
}
Note that s3:GetObject requires the object ARN (with /*), while s3:ListBucket requires the bucket ARN. Different actions require different resource ARNs.
Policy Evaluation Logic
When an API call is made, IAM evaluates all applicable policies to determine whether to allow or deny the request. The evaluation follows specific rules.
Default Deny: By default, all requests are denied. An explicit policy must allow an action for it to succeed.
Explicit Deny Overrides Allow: If any policy contains an explicit Deny for the requested action, the request is denied regardless of any Allow statements. This is the most important rule: explicit deny always wins.
Multiple Policies: When multiple policies apply, IAM evaluates all of them. If any policy denies, the request is denied. If at least one policy allows and none deny, the request is allowed.
Policy Evaluation Flow:
- Start with implicit deny
- Evaluate all identity-based policies (attached to user/group/role)
- Evaluate all resource-based policies (attached to resource)
- Evaluate permission boundaries
- Evaluate session policies (for assumed roles)
For example, if a user's group policy allows s3:GetObject but an inline policy denies s3:GetObject on a specific bucket, the user cannot access that bucket even though the group allows it.
Cross-Account Access: For cross-account scenarios, both the trusting account (resource owner) and the trusted account (requestor) must have policies that allow the action. The request must pass both accounts' policy evaluations.
Policy Variables and Condition Keys
Policy variables and condition keys make policies dynamic and context-aware, reducing the number of policies needed.
Policy Variables use ${variable-name} syntax to reference dynamic values at request time. The aws:username variable allows a policy to reference the requesting user:
{
"Effect": "Allow",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::my-bucket/home/${aws:username}/*"
}
This lets each user write objects only to their own folder. Without variables, you would need a separate policy for each user.
Condition Keys are pre-request or post-request context values. Common keys include:
aws:SourceIp: Restrict access by IP addressaws:CurrentTime: Restrict by time of dayaws:PrincipalTag: Use tags on the calling principals3:prefix: Control which S3 prefixes a user can list
Example: Restrict access to business hours:
"Condition": {
"DateGreaterThan": {"aws:CurrentTime": "2024-01-01T08:00:00Z"},
"DateLessThan": {"aws:CurrentTime": "2024-01-01T18:00:00Z"}
}
IAM Access Analyzer helps validate policies by identifying resources shared with external entities and detecting overly permissive policies. It runs against a sample of your CloudTrail logs to find the actual permissions required.
Wildcard Restrictions and Security
Wildcard usage in IAM policies is a common source of security vulnerabilities. Controlling wildcards is essential for maintaining least privilege.
Dangerous Wildcards:
Action: "*"allows every API action, equivalent to administrator accessResource: "*"applies the policy to all resourcesResource: "arn:aws:s3:::*"allows access to every S3 bucket
Safer Alternatives:
- Use specific actions:
s3:GetObjectinstead ofs3:* - Use specific ARNs:
arn:aws:s3:::my-bucket/*instead of* - Use wildcards only for variable parts:
arn:aws:s3:::app-logs-${aws:region}/*
IAM Access Analyzer flags overly permissive policies by detecting:
- Policies granting access to external principals
- Policies with wildcards on resources
- Unused permissions based on CloudTrail logs
A practical approach is to use IAM Access Analyzer to generate a policy based on CloudTrail logs. Start with broad permissions, run the analyzer, and it generates a refined policy with only the actions and resources actually used.
Policy Conditions as Guards: When wildcards are necessary, use conditions to add guardrails. For example, allow s3:* on a bucket but restrict by s3:prefix to limit which paths are accessible, or use aws:SourceIp to restrict access to corporate networks.
Quiz
1. What happens when an Allow and a Deny statement conflict in IAM?
2. What is the default behavior for unmentioned actions in IAM?
3. What does the policy variable ${aws:username} represent?
4. Why should you use specific resource ARNs instead of wildcards?
5. What does IAM Access Analyzer help you identify?
Flashcards
Question
Policy Effect
Click to reveal answer
Answer
Either Allow or Deny. Default behavior is implicit deny. Explicit Deny always overrides Allow.
Question
Policy Evaluation Order
Click to reveal answer
Answer
1. Implicit deny. 2. Identity-based policies. 3. Resource-based policies. 4. Permission boundaries. 5. Session policies.
Question
Policy Variables
Click to reveal answer
Answer
Dynamic values using ${variable-name} syntax, like ${aws:username}. Resolved at request time to personalize policies.
Question
Condition Keys
Click to reveal answer
Answer
Context-based conditions that must be true for a policy statement to apply. Include SourceIp, CurrentTime, and PrincipalTag.
Question
IAM Access Analyzer
Click to reveal answer
Answer
Tool that validates policies, identifies overly permissive permissions, finds unused permissions, and detects external resource sharing.
Revision Notes
Key Takeaways
- 1. Policy structure: Version, Statement array with Effect, Action, Resource, Condition
- 2. Explicit Deny always overrides Allow; default is implicit Deny
- 3. Use policy variables like ${aws:username} for dynamic personalization
- 4. Condition keys enable context-aware policies (IP, time, tags)
- 5. IAM Access Analyzer validates policies and detects overly permissive access
- 6. Use specific ARNs and actions; wildcards should be avoided or guarded with conditions
Interview Tips
- • Walk through the policy evaluation flow step by step
- • Explain why explicit Deny overrides Allow with an example
- • Describe how policy variables reduce the number of policies needed
- • Discuss how IAM Access Analyzer helps with least privilege
Cheat Sheet
Policy = Version + Statement[] (Effect, Action, Resource, Condition). Default = implicit Deny. Explicit Deny > Allow. Variables: ${aws:username}, ${aws:region}. Conditions: SourceIp, CurrentTime, PrincipalTag. IAM Access Analyzer = validate policies + find external sharing. Use specific ARNs, avoid wildcards.