Skip to content

Beginner · AWS account, IAM and billing · topic 8 of 50 · 35 min

IAM policy JSON and how AWS decides

Explanation

An IAM policy is JSON with a Version and one or more Statements. Each statement has an Effect (Allow or Deny), the Actions (like s3:GetObject), the Resources as ARNs, and optional Conditions. AWS starts from deny, an explicit Allow grants access, and an explicit Deny always wins.

Why read policy JSON?

The console can build policies with clicks, but in real jobs you review policies in code reviews, debug "Access Denied" errors and write least-privilege rules. All of that means reading the JSON. The good news: there are only a handful of parts.

The parts of a policy

ElementMeaningExample
VersionThe policy language version. Always use this exact date string."2012-10-17"
StatementA list of rules[ { ... }, { ... } ]
SidOptional label for the statement"ReadResults"
EffectAllow or Deny"Allow"
Actionservice:Action names; * wildcards allowed"s3:GetObject", "s3:Get*", "ec2:*"
ResourceWhich resources, as ARNs; * for all"arn:aws:s3:::college-results/*"
ConditionOptional extra checks on the requestsource IP, MFA used, region

"2012-10-17" is the current version of the policy language, not a date you should update. Older policies with "2008-10-17" lack features such as policy variables.

ARNs: names for resources

An ARN (Amazon Resource Name) uniquely names a resource. Its format is arn:partition:service:region:account-id:resource. The partition is aws for normal regions. Some parts are empty for global services: S3 bucket names are globally unique, so an S3 ARN has no region or account, and IAM is global, so its ARNs have no region.

output
arn:aws:s3:::college-results                    a bucket
arn:aws:s3:::college-results/*                  every object in that bucket
arn:aws:iam::123456789012:user/asha             an IAM user (no region)
arn:aws:ec2:ap-south-1:123456789012:instance/i-0abc1234def567890
arn:aws:dynamodb:ap-south-1:123456789012:table/Orders
Note the empty fields (:::) in S3 ARNs.

Example 1: read one bucket

json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "ListTheBucket",
      "Effect": "Allow",
      "Action": "s3:ListBucket",
      "Resource": "arn:aws:s3:::college-results"
    },
    {
      "Sid": "ReadTheFiles",
      "Effect": "Allow",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::college-results/*"
    }
  ]
}
ListBucket acts on the bucket ARN; GetObject acts on object ARNs ending in /*. Mixing them up is a classic bug.

Example 2: EC2 only in Indian regions

json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Ec2InIndiaOnly",
      "Effect": "Allow",
      "Action": "ec2:*",
      "Resource": "*",
      "Condition": {
        "StringEquals": { "aws:RequestedRegion": ["ap-south-1", "ap-south-2"] }
      }
    }
  ]
}
aws:RequestedRegion is the region the API call goes to. Calls to other regions match no Allow, so they are implicitly denied.

Example 3: no deleting without MFA

json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyDeletesWithoutMFA",
      "Effect": "Deny",
      "Action": ["ec2:TerminateInstances", "s3:DeleteBucket"],
      "Resource": "*",
      "Condition": {
        "BoolIfExists": { "aws:MultiFactorAuthPresent": "false" }
      }
    }
  ]
}
BoolIfExists also catches requests where the MFA key is missing (for example, long-term access keys), which a plain Bool would not.

Another common condition limits requests to an office network: "Condition": { "IpAddress": { "aws:SourceIp": "203.0.113.0/24" } }. The /24 is CIDR notation: the first 24 bits are fixed, so it covers 203.0.113.0 to 203.0.113.255.

How AWS evaluates a request (simplified)

  1. By default every request is denied. This is the implicit deny.
  2. AWS gathers every policy that applies: the identity's policies and the resource's policy.
  3. If any matching statement has Effect Deny, the answer is deny. An explicit deny always wins.
  4. Otherwise, if any matching statement has Effect Allow, the answer is allow.
  5. Otherwise the implicit deny stands.

A statement "matches" when the action matches its Action, the resource matches its Resource, and all its Conditions are true. In bigger setups there are extra layers: service control policies (SCPs) in AWS Organizations and permissions boundaries set the maximum an identity can ever get. An action must be allowed by those too. You will write a small version of this engine in the tasks.

Careful: Common mistakes: (1) Using arn:aws:s3:::bucket for s3:GetObject (it needs bucket/*), or bucket/* for s3:ListBucket (it needs the bucket ARN). (2) Writing "Effect": "allow" in lower case; use Allow and Deny exactly. (3) Trying to "un-deny" with an Allow: an explicit Deny cannot be overridden. (4) Using "Action": "*" with "Resource": "*" for an app; that is full admin. (5) Changing the Version date.
Tip: Use the IAM policy simulator or Access Analyzer's policy validation to test a policy before attaching it. When you see "AccessDenied", the error message often names the action and resource: start there.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

IAM policy JSON and how AWS decides · 1/7

IAM policy JSON

An IAM policy is a JSON document. Learning to read it helps you debug access denied errors and write safe permissions.

Prefer a video by a teacher? Find free videos on “AWS IAM policy JSON explained explicit deny evaluation logic” on YouTube ↗

In real life: A results portal that can only read results

A university in Chennai publishes semester results as PDF files in an S3 bucket. The web app that shows them runs on EC2 with a role whose only policy is Example 1: list the bucket and read its files. When a bug in the app later lets an attacker run commands on the server, the attacker cannot delete results, read other buckets or start servers, because the role was never allowed to. Least privilege turned a serious bug into a small one. An extra Deny statement like Example 3 protects the bucket from deletion even by admins who forgot their MFA.

json
{
  "Effect": "Allow",
  "Action": "s3:GetObject",
  "Resource": "arn:aws:s3:::semester-results/*"
}
The heart of the role: read files, nothing else.

Practice (0/3 done)

Task 1 · Question

A user has one policy: Allow s3:* on "*", and another: Deny s3:DeleteObject on "*". What happens when they try to delete an object?

Task 2 · Code · Javascript

Write evaluate(policies, action, resource), a simplified IAM engine. policies is a list of policy objects, each with a Statement list. In each statement, Action and Resource may be a string or a list of strings, and may contain * wildcards. A statement matches when ANY of its actions matches and ANY of its resources matches. Return "explicit-deny" if any matching statement has Effect "Deny"; otherwise "allow" if any matching statement has Effect "Allow"; otherwise "implicit-deny". The matches(pattern, value) helper is written for you.

Task 3 · Code · Javascript

Add Conditions to your engine. Now write evaluate(policies, request) where request is { action, resource, context }, and context holds keys like "aws:SourceIp" (an IPv4 address) and "aws:MultiFactorAuthPresent" (true or false). A statement matches only if action, resource AND all its conditions match. Support two condition operators: "Bool" (the context value, as a string, must equal one of the listed values) and "IpAddress" (the IP must be inside one of the listed CIDR ranges). If a condition key is missing from context, that condition is not met. Any other operator is not met. matches() and ipInCidr() are written for you.

Quick quiz

Question 1

1.Which value should "Version" have in a new IAM policy?

Question 2

2.Which ARN means "every object in the bucket named photos"?

Question 3

3.A user has no policies at all and tries s3:ListAllMyBuckets. What happens?

Question 4

4.Which condition key limits requests to an office IP range?

Question 5

5.Which statement about "s3:Get*" is true?

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

Which value should "Version" have in a new IAM policy?

Answer: "2012-10-17"

"2012-10-17" is the current policy language version.

Which ARN means "every object in the bucket named photos"?

Answer: arn:aws:s3:::photos/*

Objects are bucket-name/key, so /* covers every object. S3 ARNs have no region or account.

A user has no policies at all and tries s3:ListAllMyBuckets. What happens?

Answer: Implicit deny

With no Allow, the default implicit deny applies.

Which condition key limits requests to an office IP range?

Answer: aws:SourceIp

aws:SourceIp is the IP address the request came from.

Which statement about "s3:Get*" is true?

Answer: It matches s3:GetObject and s3:GetBucketPolicy

The * wildcard matches any characters after "s3:Get".

Can you sign in to AWS as an IAM group?Related

Answer: No, a group only holds users and their shared permissions

Groups have no credentials of their own; they only collect users.

From IAM: users, groups, roles and least privilege

Which bucket policy statement makes data public?Related

Answer: Allow, Principal "*", s3:GetObject, no Condition

Allow to Principal "*" without a limiting condition grants access to anyone on the internet.

From Securing and sharing S3 data

Why does a region-restricting SCP usually exclude services like IAM, Route 53 and CloudFront?Related

Answer: They are global services whose API calls go to us-east-1

Global services are served from a fixed region, so a strict region deny would block them.

From Identity is the new perimeter

What does a cloud IAM policy define?Related

Answer: Which actions are allowed or denied on which resources

Policies are the permission rules.

From Cloud identity and access management

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. 1 more topic in “AWS account, IAM and billing” before its exam: Pricing, billing and cost control.
  2. Module 2 exam: AWS account, IAM and billing · 13 questions · 20 min, without help. 4 topics of this module still to finish first.
  3. Then the next module, Compute and storage: EC2 and S3. 50 topics left in the course before the final exam.

← Previous: IAM: users, groups, roles and least privilege