AWS Cloud Practitioner Study Notes · Part 55

AWS IAM Policies: JSON Elements, Permissions, and Evaluation

AWS Cloud Practitioner study notes explaining IAM policy JSON, Allow and Deny, Actions, Resources, Conditions, policy types, and least privilege.

When an AWS user, role, or application calls an AWS API, AWS needs to decide whether that request is allowed. An IAM policy is the JSON document that describes the decision: which principal may perform which action on which resource, optionally under which conditions.

This is Part 55 of the AWS Cloud Practitioner Study Notes. A useful way to read any policy statement is:

Who can do WHAT
to WHICH resource
under WHAT conditions?

IAM policies are permission documents. They do not create an IAM user, role, or resource; they define what an identity or resource is allowed to do.

A basic IAM policy

This identity-based policy allows access to objects in one S3 bucket:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::company-files/*"
    }
  ]
}

The policy allows the s3:GetObject action on objects inside company-files. It does not automatically allow listing the bucket, deleting objects, accessing other buckets, or performing unrelated AWS actions.

The main JSON elements

The most important policy elements for the Cloud Practitioner exam are Version, Statement, Effect, Action, Resource, and Condition.

Version

"Version": "2012-10-17"

This identifies the IAM policy language version. It is not the date on which your policy was created, and it is not a managed-policy revision number. Modern IAM policies normally use 2012-10-17.

Statement

Statement contains one or more permission rules. A policy can use an object for one statement or an array for multiple statements, although the array form is common and makes the structure clear.

"Statement": [
  { "Effect": "Allow", "Action": "s3:GetObject", "Resource": "..." },
  { "Effect": "Deny", "Action": "s3:DeleteObject", "Resource": "..." }
]

Each statement is evaluated as part of the request’s overall policy decision.

Effect

Effect has only two values:

  • Allow permits the matching request, subject to the other policy layers.
  • Deny explicitly rejects the matching request.

AWS starts with an implicit deny. An Allow is needed to grant access, while an explicit Deny overrides an applicable Allow.

{
  "Effect": "Deny",
  "Action": "s3:DeleteObject",
  "Resource": "arn:aws:s3:::company-files/*"
}

If one policy allows s3:* and another applicable policy explicitly denies s3:DeleteObject, deletion is denied. The same deny does not prevent actions that do not match it, such as s3:GetObject.

Action

Action identifies the AWS API operation. The value uses the service prefix and operation name:

s3:GetObject
ec2:StartInstances
lambda:InvokeFunction
dynamodb:GetItem
secretsmanager:GetSecretValue

You can specify one action or an array of actions:

"Action": [
  "s3:GetObject",
  "s3:PutObject"
]

Wildcards are powerful but broad. s3:* matches S3 actions, while * can match actions across AWS services. Broad wildcards may be valid in an administrator policy, but they conflict with least privilege when used for an application that needs only one operation.

Resource

Resource identifies the resource to which the action applies. AWS uses Amazon Resource Names (ARNs) for many resource-level permissions:

S3 bucket:  arn:aws:s3:::company-files
S3 objects: arn:aws:s3:::company-files/*
Lambda:     arn:aws:lambda:ap-southeast-1:123456789012:function:ProcessImage
EC2:        arn:aws:ec2:ap-southeast-1:123456789012:instance/i-1234567890abcdef0

The bucket ARN and the object ARN are different resources. A policy for s3:GetObject normally targets arn:aws:s3:::company-files/*, while bucket-level actions such as s3:ListBucket target arn:aws:s3:::company-files.

Some AWS actions do not support resource-level permissions and require "Resource": "*". Check the service’s actions, resources, and condition keys documentation before assuming that every action can be narrowed to a particular ARN.

Condition

Condition adds requirements based on request context. For example, this statement permits the action only when the request comes from the specified IP range:

{
  "Effect": "Allow",
  "Action": "s3:GetObject",
  "Resource": "arn:aws:s3:::company-files/*",
  "Condition": {
    "IpAddress": {
      "aws:SourceIp": "203.0.113.10/32"
    }
  }
}

Another common condition requires a recent MFA-authenticated request:

"Condition": {
  "Bool": {
    "aws:MultiFactorAuthPresent": "true"
  }
}

Conditions can test IP addresses, Regions, tags, MFA, request dates, encryption settings, VPC endpoints, and service-specific context keys. If a required context key is missing or the condition does not match, that statement does not allow the request.

Identity-based and resource-based policies

IAM permissions policies are commonly divided into two groups:

Policy typeAttached toAnswers
Identity-basedIAM user, group, or roleWhat can this identity do?
Resource-basedA supported resource such as an S3 bucket or SQS queueWho can access this resource, and what can they do?

Identity-based policies can be AWS managed, customer managed, or inline. Resource-based policies are attached directly to supported resources and include a Principal that identifies who may access the resource.

For example, an S3 bucket policy can grant a role in another AWS account permission to read objects. Cross-account access generally requires the identity side and resource side to trust and allow the request; a policy in only the caller’s account is not enough.

Do not confuse a resource-based policy with resource-level permissions. Resource-level permissions mean an identity policy can name a specific ARN. A resource-based policy is a policy document attached to the resource itself.

Other policy layers

Several related policy mechanisms can limit or shape effective permissions:

Policy mechanismMain purpose
Service Control Policy (SCP)Maximum permissions for principals in member accounts or OUs
Permissions boundaryMaximum permissions an IAM user or role can receive
Session policyFurther limits permissions for a temporary session
Resource-based policyGrants access through a supported resource

For example, a role’s identity policy might allow s3:GetObject, but a permissions boundary or SCP can prevent the role from using that permission. The relevant policy layers must all permit the request, and an explicit deny in an applicable policy overrides an allow.

See AWS ABAC with IAM tags for an example of using policy conditions to compare principal and resource attributes, and AWS Organizations for the account-level role of SCPs.

Policy evaluation

The exam-friendly model is:

Request arrives

AWS gathers applicable policies and request context

Is there an applicable explicit Deny?
      ├── Yes → Denied
      └── No

      Is there an applicable Allow?
      ├── Yes → Allowed, subject to other policy layers
      └── No  → Implicitly denied

A practical decision is not based on one policy in isolation. AWS may evaluate identity-based policies, resource-based policies, permissions boundaries, SCPs, session policies, and conditions. The exact interaction can vary by principal type, account boundary, and resource policy, so troubleshoot the full request rather than looking only at the user’s attached policy.

IAM roles for workloads

An application on EC2 should normally use an IAM role rather than a long-term access key embedded in code. Attach the required policy to the role, associate the role with the instance, and let the AWS SDK or CLI obtain temporary credentials through the instance metadata service.

EC2 instance
      ↓ assumes
IAM role
      ↓ receives
Temporary credentials
      ↓ calls
S3, DynamoDB, Secrets Manager, or another service

For example, an image-processing instance might need only:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "s3:PutObject",
      "Resource": "arn:aws:s3:::processed-images/*"
    }
  ]
}

The role supplies temporary credentials that expire and can be rotated by AWS. The policy still determines what those credentials can do. See the EC2 instance metadata article for the metadata and credential-delivery context.

Least privilege and common mistakes

The principle of least privilege means granting only the actions, resources, and conditions required for a task.

Avoid starting an application with:

{
  "Effect": "Allow",
  "Action": "*",
  "Resource": "*"
}

Prefer a narrowly scoped statement such as one s3:GetObject action on one bucket’s object ARN. Also review these common mistakes:

  • Granting s3:* when the application only reads objects
  • Using the bucket ARN for an object action
  • Forgetting a required resource-level action such as s3:ListBucket
  • Adding a condition key that the request does not provide
  • Embedding long-term IAM access keys in application code
  • Assuming an Allow overrides an explicit Deny
  • Forgetting that an SCP or permissions boundary may limit an otherwise valid allow

Use IAM Access Analyzer, policy validation, CloudTrail activity, and the IAM policy simulator where appropriate to review and troubleshoot permissions.

Common exam questions

What defines which AWS actions a user or role can perform?

An IAM policy.

Which policy element specifies the operation?

Action, such as s3:GetObject or ec2:StartInstances.

Which element specifies the target?

Resource, usually an ARN or * when the action does not support resource-level permissions.

Which element adds requirements such as MFA or source IP?

Condition.

What happens when one policy allows an action and another explicitly denies it?

The explicit deny wins.

What is the safest credential pattern for an EC2 application?

Attach an IAM role and use temporary credentials, rather than embedding long-term access keys.

Final memory map

Version   → Policy language version
Statement → Permission rule or rules
Effect    → Allow or Deny
Action    → What operation?
Resource  → Which AWS resource?
Condition → Under what circumstances?

The one-sentence takeaway is: An IAM policy is a JSON permission document that matches actions and resources, optionally applies conditions, and participates in AWS’s policy evaluation where an explicit deny always wins.

Sources

Back to the journal