How to Read AWS IAM Policies Like a Pro
AWS Identity and Access Management (IAM) policies are the backbone of access control in AWS. But let’s be honest: IAM policies can look intimidating at first. They are written in JSON, filled with permissions jargon, and one wrong setting can lock you out of your own resources.
In this post, we’ll break down how to read and understand AWS IAM policies, piece by piece. We’ll also share a few tips to spot common mistakes and understand what a policy really allows (or denies). By the end, you’ll be able to approach an IAM policy with confidence.
1. Understanding the Key Concepts
Before diving into IAM policies, it’s important to understand a few core AWS concepts.
1.1 Account
An AWS account is the fundamental container for all your AWS resources. Every account has its own:
- Billing and payment settings
- Resources (like EC2 instances, S3 buckets)
- Security boundaries
Each AWS account has a well-defined security boundary. By default, resources, users, and permissions are confined within the account. Accounts are isolated from each other unless explicitly connected. Explicit connections include:
- Cross-account IAM roles: Allow an identity (user or service) in one AWS account to assume a role in another account, gaining temporary permissions.
- VPC Peering or PrivateLink: Establish private network connectivity between resources in different AWS accounts without traversing the public internet.
- Resource policies with cross-account access: Directly attach policies to resources (like S3 buckets or KMS keys) that permit access from another AWS account.
These explicit connections must be deliberately configured, ensuring isolation is preserved unless intentional collaboration is set up.
1.2 IAM (Identity and Access Management)
IAM is the service AWS provides to manage access to AWS resources securely. IAM helps you:
- Create and manage AWS users and groups
- Assign permissions to control which resources users and groups can access
IAM operates within the boundary of an AWS account but can also interact across accounts with features like roles and cross-account access.
1.3 IAM User, Group, and Role
- User: Represents a person or application. Each user has long-term credentials like a password or access keys.
- Group: A collection of IAM users. You can attach policies to a group to apply the same permissions to all members.
- Role: A set of permissions that can be assumed by a user, application, or service. Roles are temporary and don’t have long-term credentials. They are powerful for cross-account access or service-to-service communication.
Common examples and use cases for roles include:
- Developer Role: Grants developers access to necessary AWS services like S3, EC2, and DynamoDB for development and testing. Typically full access in non-production environments and restricted or read-only access in production.
- Read-Only Role: Allows users to view AWS resources without modifying or deleting them. Commonly used for auditors, compliance officers, or business analysts.
- EC2 Instance Role: Assign a role to an EC2 instance to allow it to access other AWS services like S3 or DynamoDB without embedding long-term credentials in the code.
- Lambda Execution Role: Provide AWS Lambda functions the necessary permissions to interact with AWS services, such as reading from an S3 bucket or writing to CloudWatch Logs.
- Cross-Account Role: Enable users or services in one AWS account to access resources in another account securely.
- Federated User Role: Allow users authenticated via an external identity provider (like Google Workspace or Active Directory) to assume roles and access AWS resources temporarily.
1.4 Principal
A Principal is the entity that is allowed or denied access to a resource. It can be:
- An IAM user
- An IAM role
- A federated user (someone accessing via an external identity provider)
In a policy, Principal
defines who the policy applies to.
1.5 Action
The Action element describes what the principal is allowed or denied to do. Each AWS service has its own set of actions. For example:
s3:PutObject
— Upload an object to an S3 bucketec2:StartInstances
— Start an EC2 instance
Actions are specific to services and control the operations allowed.
1.6 Resource
The Resource element specifies which AWS resources the action applies to. Resources are defined by their Amazon Resource Name (ARN).
Examples:
- An S3 bucket:
arn:aws:s3:::my-bucket
- An EC2 instance:
arn:aws:ec2:us-west-2:123456789012:instance/i-1234567890abcdef0
In short:
- Account: Container for all your AWS assets
- IAM: Service to control access
- Principal: Who is trying to access
- Action: What they want to do
- Resource: What they want to act on
2. Anatomy of an IAM Policy
Here is a basic IAM policy:
1
2
3
4
5
6
7
8
9
10
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::example-bucket"
}
]
}
Let’s break this down:
- Version: Policy language version. Almost always
2012-10-17
. AWS uses this to interpret the policy. - Statement: The main block that describes permissions. You can have a single statement or multiple statements inside a policy.
Each statement has:
- Effect: Either
Allow
orDeny
. - Action: The specific operation(s) permitted or denied.
- Resource: The AWS resource(s) the action applies to.
- Condition (optional): Additional requirements for the statement to apply.
- Principal (resource-based policies only): Specifies who is affected.
3. Key Elements Explained
Understanding each element in depth helps in mastering IAM policies.
3.1 Effect
The Effect
element controls whether the statement allows or denies access.
- Allow: Grants permission for the specified actions.
- Deny: Explicitly denies permission, even if another policy allows it.
Important:
- AWS applies an implicit deny by default.
- An explicit deny always overrides an allow.
Tip: Favor Allow
policies and let the implicit deny work for everything else unless you have a specific reason to deny explicitly.
3.2 Action
The Action
element specifies the operations you allow or deny.
Examples:
s3:GetObject
— Download an object from an S3 bucket.ec2:StartInstances
— Start a specific EC2 instance.
You can specify multiple actions or use wildcards:
s3:*
— Grants all S3 actions.s3:Get*
— Grants allGet
actions on S3.
Tip: Avoid over-broad actions (*
). Be as specific as possible to apply the principle of least privilege.
3.3 Resource
The Resource
element specifies what the action can apply to.
AWS uses Amazon Resource Names (ARNs) to uniquely identify resources.
Example:
- S3 bucket:
arn:aws:s3:::example-bucket
- Objects inside a bucket:
arn:aws:s3:::example-bucket/*
Tip: When granting access to S3 objects, don’t forget to include /*
to cover the contents of the bucket.
3.4 Principal
The Principal
element identifies who the policy applies to.
- In identity-based policies, AWS assumes the principal is the identity (user/role/group) the policy is attached to.
- In resource-based policies, you explicitly specify the principal.
Example:
1
2
3
"Principal": {
"AWS": "arn:aws:iam::123456789012:user/Alice"
}
Note: Resource-based policies allow cross-account access by specifying a principal from another account.
3.5 Condition
Conditions refine when a policy is effective.
Example Conditions:
- IP restriction:
1
2
3
"Condition": {
"IpAddress": {"aws:SourceIp": "203.0.113.0/24"}
}
- Require MFA:
1
2
3
"Condition": {
"Bool": {"aws:MultiFactorAuthPresent": "true"}
}
Common condition operators:
StringEquals
StringLike
NumericLessThan
IpAddress
Bool
Tip: Conditions make your policies much safer but can also complicate them. Review them carefully.
4. Types of IAM Policies
There are several types of IAM policies, each serving different purposes.
4.1 Identity-Based Policies
- Attached to users, groups, or roles.
- Define what actions those identities can perform on resources.
Example: A policy that allows a user to read from an S3 bucket.
4.2 Resource-Based Policies
- Attached directly to a resource like an S3 bucket, Lambda function, or SQS queue.
- Specify who (Principal) can access the resource and what they can do.
Example: A bucket policy that allows cross-account access.
4.3 Permissions Boundaries
- Advanced feature.
- Define the maximum permissions a user or role can have, even if identity policies grant more.
Useful for:
- Restricting delegated administrators
- Enforcing security policies
4.4 Service Control Policies (SCPs)
- Used in AWS Organizations.
- Apply to AWS accounts.
- Set permission guardrails; they don’t grant permissions, only restrict.
Common use cases:
- Prevent deletion of CloudTrail logs
- Restrict creation of internet-facing resources
4.5 Session Policies
- Passed when a role or federated identity is assumed.
- Temporary policies that limit what a session can do.
Useful for:
- Fine-grained access control during short-lived sessions
5. Example: Reading a Real Policy
Let’s look at a real-world example.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject"
],
"Resource": "arn:aws:s3:::example-bucket/*"
},
{
"Effect": "Deny",
"Action": "s3:DeleteObject",
"Resource": "arn:aws:s3:::example-bucket/*"
}
]
}
Interpretation:
- Allow putting and getting objects in
example-bucket
. - Explicitly deny deleting objects.
Even though permissions can be granted broadly, using an explicit deny for deletion provides extra safety.
6. Common Mistakes When Reading Policies
- Missing Resource Detail: Forgetting
/*
in S3 policies means you are only granting access to the bucket itself, not the objects inside. - Overusing Wildcards:
*
in actions or resources can grant more permissions than intended. - Ignoring Explicit Deny: Always check for explicit denies; they override allows.
- Not Checking Conditions: Conditions can dramatically change the policy’s behavior.
7. Useful Tools to Help
IAM Policy Simulator: Test policies against hypothetical requests.
IAM Access Analyzer: Highlights resources shared externally.
AWS Docs: Comprehensive action and condition key listings.
8. Tips for Writing and Reading Better Policies
- Start with least privilege.
- Review and audit policies regularly.
- Use specific actions and resources.
- Add conditions to tighten access.
- Test policies with IAM Policy Simulator.
- Document the purpose of each policy.
9. Practice: Reading a Complex Policy
Try reading this policy:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ListAndGetS3",
"Effect": "Allow",
"Action": [
"s3:ListBucket",
"s3:GetObject"
],
"Resource": [
"arn:aws:s3:::example-bucket",
"arn:aws:s3:::example-bucket/*"
]
},
{
"Sid": "RestrictIP",
"Effect": "Deny",
"Action": "s3:*",
"Resource": "arn:aws:s3:::example-bucket/*",
"Condition": {
"NotIpAddress": {
"aws:SourceIp": "203.0.113.0/24"
}
}
}
]
}
Interpretation:
- Allow listing and getting objects in
example-bucket
. - Deny any S3 action if the request doesn’t come from the specified IP range.
This policy ensures secure, IP-restricted access.
10. Final Thoughts
IAM policies are powerful, but with power comes responsibility. Misconfigured policies can lead to serious security risks.
By understanding the structure and meaning behind each part of an IAM policy, you can read them like a pro. Start small, read carefully, and practice often.
And remember: when in doubt, simulate.
Happy policy reading!
Did you find this guide useful? Feel free to share it with others who want to get better at AWS security!