When you first start working with Amazon Web Services, one of the most critical services you'll encounter is Identity and Access Management (IAM). Think of IAM as the security guard of your AWS account—it controls who can enter, what rooms they can access, and what actions they can perform.
In this guide, we'll break down IAM concepts with practical examples that you can immediately apply to your projects.
What is AWS IAM?
AWS Identity and Access Management (IAM) is a free service that allows you to securely manage access to AWS resources. With IAM, you can control:
- Who can access your resources (authentication)
- What they can do with those resources (authorization)
Every interaction with AWS—whether through the console, CLI, or SDK—goes through IAM for permission checks.
Core IAM Components
1. Users
An IAM user represents a person or application that interacts with AWS. Each user has unique credentials.
Real Example: Creating a Developer User
Imagine you're onboarding a new developer named Sarah to your team. She needs access to deploy applications to EC2 and view logs in CloudWatch.
{
"UserName": "sarah-developer",
"Tags": [
{
"Key": "Department",
"Value": "Engineering"
},
{
"Key": "Role",
"Value": "Backend Developer"
}
]
}
Best Practice: Never use the root account for daily tasks. Create individual IAM users for each team member.
2. Groups
Groups are collections of users. Instead of attaching policies to each user individually, you attach them to a group, and all members inherit those permissions.
Real Example: Team-Based Access Structure
├── Developers (Group)
│ ├── sarah-developer
│ ├── john-developer
│ └── Policy: DeveloperAccess
│
├── DevOps (Group)
│ ├── mike-devops
│ └── Policy: DevOpsFullAccess
│
└── Finance (Group)
├── lisa-finance
└── Policy: BillingReadOnly
When Sarah moves from Development to DevOps, you simply remove her from the Developers group and add her to DevOps. No policy changes needed.
3. Roles
Roles are similar to users but are meant to be assumed temporarily by users, applications, or AWS services. They don't have permanent credentials.
Real Example: EC2 Instance Accessing S3
Your application running on EC2 needs to upload images to an S3 bucket. Instead of storing AWS credentials in your code (a security risk), you create a role:
{
"RoleName": "EC2-S3-Upload-Role",
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
}
The EC2 instance automatically gets temporary credentials to access S3—no hardcoded keys required.
4. Policies
Policies are JSON documents that define permissions. They specify what actions are allowed or denied on which resources.
Policy Structure:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow | Deny",
"Action": "service:action",
"Resource": "arn:aws:service:region:account:resource",
"Condition": { }
}
]
}
Real-World Policy Examples
Example 1: S3 Read-Only Access to a Specific Bucket
A mobile app needs to read images from a bucket called my-app-images:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::my-app-images",
"arn:aws:s3:::my-app-images/*"
]
}
]
}
Example 2: Developer Access with Restrictions
Developers can manage EC2 instances but cannot terminate production servers:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:*",
"Resource": "*"
},
{
"Effect": "Deny",
"Action": "ec2:TerminateInstances",
"Resource": "*",
"Condition": {
"StringEquals": {
"ec2:ResourceTag/Environment": "production"
}
}
}
]
}
Example 3: Time-Based Access
Contractors can only access resources during business hours:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:*",
"Resource": "*",
"Condition": {
"DateGreaterThan": {
"aws:CurrentTime": "2025-01-01T09:00:00Z"
},
"DateLessThan": {
"aws:CurrentTime": "2025-12-31T18:00:00Z"
}
}
}
]
}
Example 4: Lambda Function Accessing DynamoDB
A Lambda function that reads and writes to a specific DynamoDB table:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"dynamodb:GetItem",
"dynamodb:PutItem",
"dynamodb:UpdateItem",
"dynamodb:Query"
],
"Resource": "arn:aws:dynamodb:ap-south-1:123456789012:table/UserProfiles"
},
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:*:*:*"
}
]
}
Understanding Policy Evaluation
When a request is made, AWS evaluates policies in this order:
- Explicit Deny — If any policy explicitly denies the action, access is denied (highest priority)
- Explicit Allow — If a policy allows the action and nothing denies it, access is granted
- Implicit Deny — If no policy mentions the action, access is denied by default
Request → Check Deny → Check Allow → Default Deny
↓ ↓ ↓
DENIED ALLOWED DENIED
Types of IAM Policies
| Policy Type | Description | Use Case |
|---|---|---|
| AWS Managed | Created and maintained by AWS | Quick setup with common permissions |
| Customer Managed | Created by you | Custom permissions for your organization |
| Inline | Embedded directly in a user, group, or role | Strict one-to-one relationship |
Recommendation: Use customer managed policies for reusability and easier maintenance.
Security Best Practices
1. Enable Multi-Factor Authentication (MFA)
Always enable MFA for the root account and privileged users.
2. Follow the Principle of Least Privilege
Grant only the permissions required to perform a task—nothing more.
// ❌ Bad: Too permissive
{
"Effect": "Allow",
"Action": "*",
"Resource": "*"
}
// ✅ Good: Specific and limited
{
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-bucket/public/*"
}
3. Use Roles Instead of Access Keys
For applications running on AWS services, always use IAM roles instead of embedding access keys.
4. Rotate Credentials Regularly
Set up automatic rotation for access keys and review unused credentials.
5. Use IAM Access Analyzer
This tool helps identify resources shared with external entities and validates policies.
Common IAM Scenarios
Scenario 1: Cross-Account Access
Your production and development accounts are separate. Developers need to access production S3 for debugging.
Solution: Create a role in production that developers can assume from the development account.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::DEV_ACCOUNT_ID:root"
},
"Action": "sts:AssumeRole",
"Condition": {
"Bool": {
"aws:MultiFactorAuthPresent": "true"
}
}
}
]
}
Scenario 2: Service-Linked Roles
Some AWS services create roles automatically to perform actions on your behalf. For example, when you use Elastic Load Balancing, AWS creates AWSServiceRoleForElasticLoadBalancing.
Scenario 3: Federated Access
Your company uses Google Workspace or Microsoft Azure AD. Instead of creating IAM users, you can federate identity:
Corporate Identity Provider → AWS STS → Temporary Credentials → AWS Access
Debugging IAM Issues
When access is denied, check these areas:
- Policy Simulator — Test policies before applying them
- CloudTrail Logs — See exactly what was denied and why
- IAM Access Advisor — View which services a user actually accessed
Common Error:
An error occurred (AccessDenied) when calling the PutObject operation: Access Denied
Debugging Steps:
- Verify the policy is attached to the user/role
- Check for explicit deny statements
- Ensure the resource ARN matches exactly
- Verify the correct region is specified
Quick Reference: Common IAM Actions
| Service | Common Actions |
|---|---|
| S3 |
s3:GetObject, s3:PutObject, s3:DeleteObject, s3:ListBucket
|
| EC2 |
ec2:RunInstances, ec2:StopInstances, ec2:TerminateInstances
|
| Lambda |
lambda:InvokeFunction, lambda:CreateFunction, lambda:UpdateFunctionCode
|
| DynamoDB |
dynamodb:GetItem, dynamodb:PutItem, dynamodb:Query, dynamodb:Scan
|
| RDS |
rds:CreateDBInstance, rds:DeleteDBInstance, rds:DescribeDBInstances
|
Conclusion
AWS IAM is the foundation of security in the cloud. By understanding users, groups, roles, and policies, you can build secure applications that follow the principle of least privilege.
Start with these steps:
- Create individual users for your team members
- Organize users into groups based on job functions
- Use roles for applications and cross-account access
- Write specific policies that grant only necessary permissions
- Enable MFA and regularly audit your IAM configuration
Security isn't a one-time setup—it's an ongoing practice. Regularly review your IAM policies and adjust as your application evolves.
Happy building on AWS!
Top comments (0)