Mastering AWS IAM Policies: A Simple, Practical Guide

December 3, 2025
In AWS, policies are the foundation of access control. They define who (or what) can perform which actions on specific resources, and under what conditions. This guide combines straightforward explanations with real-world examples to help you understand and apply them effectively.
Core Concepts in Plain English
A policy in AWS is a JSON document that defines permissions. It answers the question: “Who can do what to which resources under what conditions?” Policies are evaluated in a strict order: any explicit Deny wins immediately, followed by checking for an Allow; if there's no Allow, it's a default Deny.
- Identity-based policies – attached to IAM users, groups, or roles (most common)
- Resource-based policies – attached directly to resources (S3, KMS, etc.)
- Permissions boundaries – hard ceiling on what a user/role can do
- Service Control Policies (SCPs) – organization-wide restrictions (only deny)
- Session policies – temporary restrictions when assuming a role
- Trust policies – define who can assume an IAM role
Although AWS allows you to attach policies directly to users, groups, roles, and resources, that flexibility often creates confusion and long-term permission drift. In real environments, the cleanest, most maintainable approach is the User → Group → Role pattern. Human IAM users should not receive functional permissions directly. Instead, they belong to Groups, which grant them the authority to assume specific Roles. These Roles hold the actual identity-based permissions, providing temporary and least-privilege access for tasks such as development, operations, or production support.
This design keeps long-lived user credentials low-privilege, enforces MFA through role assumption, simplifies audits, and mirrors how modern AWS Identity Center (SSO) operates internally. While some AWS services still rely on resource-based policies (e.g., S3, KMS) for cross-account or service-to-service access, your identity-based access model remains cleanest when actual permissions live in well-structured, customer-managed Role policies. Just because AWS lets you attach a policy in many places doesn’t mean you should—centralizing permissions in Roles is the scalable, secure default.
1. Identity-Based Policies (Most Common)
AWS identity-based policies are JSON documents attached to IAM users, groups, or roles that explicitly define their permissions. These policies outline which actions an identity is allowed to perform, the resources those actions apply to, and any conditions that must be met. They govern what an identity can do inside your AWS environment.
- AWS Managed Policies: Prebuilt policies created and maintained by AWS for common tasks (e.g., ReadOnlyAccess, AWSLambda_FullAccess). They’re convenient starting points but often too broad to meet strict least-privilege requirements.
- Customer Managed Policies: Custom policies that you design and manage within your AWS account. They provide finer-grained control and can be reused across multiple users, groups, and roles — making them the preferred option for production environments.
- Inline Policies: Policies attached directly to a single IAM user, group, or role in a one-to-one relationship. Because they’re tightly coupled, they’re deleted automatically when the identity is deleted. Inline policies are best reserved for exceptional, identity-specific permissions.
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": "*",
"Resource": "*",
"Condition": {
"StringEquals": {"aws:RequestedRegion": "us-east-1"},
"Bool": {"aws:MultiFactorAuthPresent": "true"}
}
}]
}
{
"Version": "2012-10-17",
"Statement": [
{"Effect": "Allow", "Action": ["ec2:*","rds:*","elasticloadbalancing:*","cloudwatch:*","logs:*","ssm:*"], "Resource": "*"},
{"Effect": "Deny", "Action": ["aws-portal:*","iam:CreateUser","iam:DeleteUser"], "Resource": "*"}
]
}
2. Resource-Based Policies
Attached to the resource itself (S3, KMS, SNS, etc.). Perfect for cross-account or public access.
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {"Service": "cloudfront.amazonaws.com"},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-website/*",
"Condition": {"StringEquals": {"AWS:SourceArn": "arn:aws:cloudfront::123456789012:distribution/E1234567890ABC"}}
}]
}
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {"AWS": "arn:aws:iam::999999999999:role/analytics-role"},
"Action": "s3:*",
"Resource": ["arn:aws:s3:::company-data-lake","arn:aws:s3:::company-data-lake/*"]
}]
}
3. Permissions Boundaries
Guardrails — even AdministratorAccess cannot exceed them.
{
"Version": "2012-10-17",
"Statement": [
{"Effect": "Allow","Action":"ec2:RunInstances","Resource":"arn:aws:ec2:*:*:instance/*",
"Condition":{"StringEquals":{"ec2:InstanceType":["t3.nano","t3.micro","t3.small","t3.medium","t3.large"]}}},
{"Effect": "Allow","Action": "ec2:*","Resource": "*"}
]
}
4. Service Control Policies (SCPs)
Organization-wide restrictions (only Deny). Even root is bound.
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Deny",
"Action": ["cloudtrail:DeleteTrail","cloudtrail:StopLogging","cloudtrail:UpdateTrail"],
"Resource": "*"
}]
}
5. Session Policies
Temporary restrictions when assuming a role.
{
"Version": "2012-10-17",
"Statement": [
{"Effect":"Allow","Action":"s3:ListBucket","Resource":"arn:aws:s3:::confidential-client-data"},
{"Effect":"Allow","Action":"s3:GetObject","Resource":"arn:aws:s3:::confidential-client-data/2025/contractor123/*"}
]
}
6. Trust Policies
An AWS trust policy is a JSON document attached to an IAM role that defines which principals—users, services, or entire AWS accounts—are allowed to assume that role. It establishes the trust relationship required for granting temporary, secure access without exposing long-term credentials. For example, a trust policy might let an EC2 instance assume a role or allow an external AWS account to access resources in your account.
Key Functions
- Specifies who can assume the role: The
Principalelement identifies the entities permitted to take on the role. - Controls assumption patterns: It’s essential for use cases such as allowing AWS services to call other services or enabling cross-account delegation.
- Defines trust: It forms the trust relationship between the role and the principals that may assume it.
- JSON-based structure: The policy is written in JSON and is part of the role’s configuration.
How It Works
A trust policy is a form of resource-based policy attached to IAM roles. It works alongside identity-based policies, which define what actions the role can perform once assumed.
When AWS receives an AssumeRole request, it evaluates both:
- The trust policy on the target role (who is allowed to assume it)
- The identity-based policy of the caller (whether they are allowed to request the role)
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {"Federated": "arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com"},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {"token.actions.githubusercontent.com:aud": "sts.amazonaws.com"},
"StringLike": {"token.actions.githubusercontent.com:sub": "repo:myorg/myrepo:*"}
}
}]
}
Key Concepts & Best Practices
| Concept | Real-World Use | Example Snippet |
|---|---|---|
| Least Privilege | CI/CD only touches specific stacks | "Resource": "arn:aws:cloudformation:*:*:stack/myapp-*/*" |
| Condition Keys | Only from company IPs | "Condition": {"IpAddress": {"aws:SourceIp": "203.0.113.0/24"}} |
| Deny Overrides Allow | Block dangerous actions in SCPs | "Effect": "Deny", "Action": "iam:CreateUser" |
| Principal * | Public website via CloudFront only | "Principal": "*" + CloudFront condition |
Summary Table of Policy Types
| Policy Type | Attached To | Can Grant Cross-Account? | Typical Use Case |
|---|---|---|---|
| Identity-based | User, Group, Role | Yes (with resource policy) | Normal permissions |
| Resource-based | S3, KMS, SNS, etc. | Yes | Cross-account, public |
| Permissions Boundary | User or Role | N/A (restrict only) | Guardrails |
| SCP (Organizations) | Account or OU | N/A (deny only) | Enterprise governance |
| Session Policy | Assumed session | Restricts only | Contractors, auditors |
| Trust Policy | IAM Role | Yes | Who can assume role |
These are the exact policies used by real companies every day. Copy, adapt, and secure your environment.
- By the Eclipsos AWS Architecture Team
- Empowering Innovation Through Cloud