Amazon IAM Essentials
IAM essentials, policies, roles, CLI commands, and best practices
AWS Identity and Access Management (IAM) is the service that controls who can access which resources in your AWS account and under what conditions. It's AWS's centralized authentication and authorization system.
The problem it solves: Granular permission control, secure credential management, access auditing, and eliminating hardcoded credentials in applications.
When to use it: ALWAYS. IAM is mandatory in any AWS architecture. The question isn't "should I use IAM?" but rather "how do I design my permission structure securely and scalably?"
Key Concepts
| Concept | Description |
|---|---|
| Policies | JSON documents that define specific permissions (what actions on what resources). They answer the question: "WHAT can you do?" |
| Identity-based Policies | Policies attached to identities (users, groups, roles). Example: "This user can read S3 and write to CloudWatch" |
| Resource-based Policies | Policies attached to resources (S3 buckets, Lambda functions). Example: "This S3 bucket allows access from this specific role" |
| Users (IAM Users) | Identities for human beings. Have permanent credentials (password and/or access keys) until manual rotation |
| Groups | Collections of users that share the same permissions. Simplifies management when multiple users need identical access |
| Roles (IAM Roles) | Identities that can be temporarily assumed by AWS services, applications, or users. Grant temporary credentials with automatic expiration |
| Trust Policy (Assume Role Policy) | Special policy that defines WHO can assume a role. It's the role's "guest list". Answers: "WHO can use these permissions?" |
| Instance Profile | Wrapper/container that makes a Role "attachable" to EC2 instances. It's the technical bridge between Roles and EC2 |
| Managed Policies | Pre-created policies maintained by AWS. Examples: AmazonS3ReadOnlyAccess, AmazonSSMManagedInstanceCore |
| Custom Policies | Policies created by you for specific use cases. You have full control over exact permissions |
| Instance Metadata Service (IMDS) | Service at 169.254.169.254 that provides temporary credentials to EC2 instances. Allows boto3/SDKs to obtain credentials automatically |
| ARN (Amazon Resource Name) | Unique identifier for AWS resources. Format: arn:aws:service:region:account:resource |
Essential AWS CLI Commands
Creating Resources
# CREATE POLICY (Custom)
aws iam create-policy \
--policy-name MyCustomPolicy \
--policy-document file://policy.json \
--description "Policy description"
# CREATE USER
aws iam create-user \
--user-name developer-john
# Create access keys for the user (for CLI/SDK)
aws iam create-access-key --user-name developer-john
# Create password for console login
aws iam create-login-profile \
--user-name developer-john \
--password 'TempPassword123!' \
--password-reset-required
# CREATE GROUP
aws iam create-group --group-name backend-developers
# Add users to the group
aws iam add-user-to-group \
--user-name developer-john \
--group-name backend-developers
# CREATE ROLE
# 1. Create the Trust Policy first
cat > trust-policy.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Action": "sts:AssumeRole"
}]
}
EOF
# 2. Create the Role
aws iam create-role \
--role-name EC2AccessRole \
--assume-role-policy-document file://trust-policy.json \
--description "Role for EC2 instances"
# CREATE INSTANCE PROFILE
aws iam create-instance-profile \
--instance-profile-name EC2AccessProfile
# Associate Role to Instance Profile
aws iam add-role-to-instance-profile \
--instance-profile-name EC2AccessProfile \
--role-name EC2AccessRoleAttaching Policies
# Attach policy to USER
aws iam attach-user-policy \
--user-name developer-john \
--policy-arn arn:aws:iam::123456789012:policy/MyCustomPolicy
# Attach policy to GROUP
aws iam attach-group-policy \
--group-name backend-developers \
--policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess
# Attach policy to ROLE
aws iam attach-role-policy \
--role-name EC2AccessRole \
--policy-arn arn:aws:iam::123456789012:policy/MyCustomPolicy
# Attach AWS managed policy
aws iam attach-role-policy \
--role-name EC2AccessRole \
--policy-arn arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCoreQuerying Resources
# List users
aws iam list-users
# List groups
aws iam list-groups
# List roles
aws iam list-roles
# List policies (custom)
aws iam list-policies --scope Local
# List policies (AWS managed)
aws iam list-policies --scope AWS
# View policies attached to a user
aws iam list-attached-user-policies --user-name developer-john
# View policies attached to a group
aws iam list-attached-group-policies --group-name backend-developers
# View policies attached to a role
aws iam list-attached-role-policies --role-name EC2AccessRole
# View policy content
aws iam get-policy-version \
--policy-arn arn:aws:iam::123456789012:policy/MyCustomPolicy \
--version-id v1
# View which users are in a group
aws iam get-group --group-name backend-developers
# View instance profiles
aws iam list-instance-profiles
# View credentials from EC2 (inside the instance)
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/Modifying Resources
# Change user password
aws iam update-login-profile \
--user-name developer-john \
--password 'NewPassword456!'
# Rotate access keys (create new, delete old)
aws iam create-access-key --user-name developer-john
aws iam delete-access-key \
--user-name developer-john \
--access-key-id AKIAIOSFODNN7EXAMPLE
# Update trust policy of a role
aws iam update-assume-role-policy \
--role-name EC2AccessRole \
--policy-document file://new-trust-policy.jsonDeleting Resources
# Detach policy from user/group/role
aws iam detach-user-policy \
--user-name developer-john \
--policy-arn arn:aws:iam::123456789012:policy/MyCustomPolicy
aws iam detach-group-policy \
--group-name backend-developers \
--policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess
aws iam detach-role-policy \
--role-name EC2AccessRole \
--policy-arn arn:aws:iam::123456789012:policy/MyCustomPolicy
# Remove user from group
aws iam remove-user-from-group \
--user-name developer-john \
--group-name backend-developers
# Delete access keys
aws iam delete-access-key \
--user-name developer-john \
--access-key-id AKIAIOSFODNN7EXAMPLE
# Delete login profile (console access)
aws iam delete-login-profile --user-name developer-john
# Delete user (must have no policies or access keys)
aws iam delete-user --user-name developer-john
# Delete group (must be empty)
aws iam delete-group --group-name backend-developers
# Remove role from instance profile
aws iam remove-role-from-instance-profile \
--instance-profile-name EC2AccessProfile \
--role-name EC2AccessRole
# Delete instance profile
aws iam delete-instance-profile \
--instance-profile-name EC2AccessProfile
# Delete role (must have no attached policies)
aws iam delete-role --role-name EC2AccessRole
# Delete custom policy
aws iam delete-policy \
--policy-arn arn:aws:iam::123456789012:policy/MyCustomPolicyArchitecture and Flows
Typical Architecture Diagram
EC2 Authentication Flow with IAM Role
Comparison: User vs Role
Best Practices Checklist
Security
- Principle of Least Privilege: Grant only the minimum permissions needed
- Don't use Root User: Create IAM users for administrative tasks
- Enable MFA: Multi-Factor Authentication for privileged users
- Rotate credentials: Access keys every 90 days maximum
- Use Roles instead of hardcoding keys: For applications in AWS, always use Roles
- Specific policies: Avoid
"Resource": "*"when possible - Restrictive Trust Policies: Limit who can assume roles
- Review permissions regularly: Use IAM Access Analyzer to identify unused permissions
- Never commit credentials: Don't include access keys in source code
Cost Optimization
- IAM is free: No cost for users, groups, roles, or policies
- Delete unused resources: Users, roles, or policies that are no longer needed
- Consolidate policies: Reuse policies instead of duplicating
Performance
- Credential caching: SDKs cache temporary credentials automatically
- Roles over Users: For applications, Roles have better performance (automatic renewal)
Reliability
- Multiple admin users: Don't depend on a single admin user
- Backup policies: Document or version custom policies in IaC
- Service Control Policies (SCPs): For multi-account organizations
Operational Excellence
- Naming conventions: Descriptive names (e.g.,
prod-api-ec2-role,dev-s3-access-policy) - Tagging: Tag roles and policies with
Environment,Team,Project - Infrastructure as Code: Manage IAM with Terraform/CloudFormation
- Enable CloudTrail: Audit all IAM actions
- Environment separation: Different roles for dev/staging/prod
Common Mistakes to Avoid
Hardcoding Access Keys in Code
Why it happens: It's the "fastest" way to make it work locally.
The problem:
- Keys exposed in GitHub repositories
- Keys compromised if the server is hacked
- Difficult to rotate (need to change code and redeploy)
How to avoid it:
# NEVER do this
s3 = boto3.client('s3',
aws_access_key_id='AKIAIOSFODNN7EXAMPLE',
aws_secret_access_key='wJalrXUtnFEMI/K7MDENG/bPxRfiCY'
)
# DO this (boto3 gets credentials from Instance Profile)
s3 = boto3.client('s3') # Automatically uses the EC2's RoleForgetting the Instance Profile When Creating EC2
Why it happens: You create the Role but not the Instance Profile, or create the EC2 without associating it.
The problem: EC2 without permissions, boto3 fails with "Unable to locate credentials".
How to avoid it:
# Always create both and associate
aws iam create-role --role-name MyRole ...
aws iam create-instance-profile --instance-profile-name MyProfile
aws iam add-role-to-instance-profile --role-name MyRole --instance-profile-name MyProfile
# And specify when launching EC2
aws ec2 run-instances --iam-instance-profile Name=MyProfile ...Incorrect Trust Policy
Why it happens: Confusing "who can assume" with "what it can do".
The problem: Role created but Lambda/EC2 can't assume it.
Example:
// Trust Policy with wrong service
{
"Principal": {
"Service": "ec2.amazonaws.com" // Role for EC2
}
}
// Trying to use it with Lambda → Error: Access Denied
// Correct Trust Policy for Lambda
{
"Principal": {
"Service": "lambda.amazonaws.com"
}
}Overly Permissive Policies
Why it happens: Using "Effect": "Allow", "Action": "*", "Resource": "*" to "make it work".
The problem: Violation of least privilege, security risk if credentials are compromised.
How to avoid it:
// Too permissive
{
"Effect": "Allow",
"Action": "*",
"Resource": "*"
}
// Specific and limited
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject"
],
"Resource": "arn:aws:s3:::my-specific-bucket/*"
}Not Distinguishing Bucket ARN vs Objects in S3
Why it happens: Not understanding that ListBucket operates on the bucket, but GetObject operates on objects.
The problem: Policy seems correct but gives Access Denied.
How to avoid it:
{
"Statement": [
{
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::my-bucket" // Without /*
},
{
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:PutObject"],
"Resource": "arn:aws:s3:::my-bucket/*" // With /*
}
]
}Mixing Identity-based and Resource-based Policies
Why it happens: Not understanding when to use each type.
Simple rule:
- Identity-based: To control what YOUR identity can do
- Resource-based: To control WHO can access YOUR resource
Example:
// Identity-based (attached to a Role)
// "My EC2 can read any S3 bucket"
{
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "*"
}
// Resource-based (bucket policy in S3)
// "My bucket allows reading only from this specific Role"
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:role/EC2Role"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-bucket/*"
}Not Using Managed Policies for Common Cases
Why it happens: Not checking if AWS already has a policy for the use case.
The problem: Creating custom policies duplicating what AWS already maintains.
How to avoid it:
# Search for existing managed policies
aws iam list-policies \
--scope AWS \
--query 'Policies[?contains(PolicyName, `S3`)].PolicyName'
# Example: Instead of creating custom policy for SSM, use:
aws iam attach-role-policy \
--role-name MyRole \
--policy-arn arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCoreCost Considerations
What Doesn't Generate Costs in IAM
| Resource | Cost |
|---|---|
| IAM Users | FREE (no limit) |
| Groups | FREE (no limit) |
| Roles | FREE (no limit) |
| Policies (custom and managed) | FREE (limit: 10,000 custom policies per account) |
| Instance Profiles | FREE |
| AssumeRole operations | FREE |
| CloudTrail logs for IAM | Only S3 storage cost where they're saved |
Related Indirect Costs
- CloudTrail: $2/100,000 events (after first 5,000 free/month)
- IAM Access Analyzer: $0.20/100 findings (after first 10,000 free)
How to Optimize
- Delete unused resources: Roles, users, policies that are no longer needed
- Consolidate policies: Reuse instead of duplicating
- Disable users instead of deleting: If they might be needed in the future
Free Tier
IAM is 100% covered in the free tier permanently (not just 12 months). There's no limit on normal usage.
Integration with Other Services
| AWS Service | How it integrates with IAM | Typical use case |
|---|---|---|
| EC2 | Instance Profiles allow EC2 to assume Roles | Give instances access to S3, RDS, secrets without hardcoding keys |
| Lambda | Execution Role defines function permissions | Allow Lambda to write logs, access DynamoDB, invoke other functions |
| S3 | Bucket Policies (resource-based) + IAM policies (identity-based) | Control who can read/write to specific buckets |
| RDS | IAM Database Authentication | Authenticate database connections without passwords |
| Secrets Manager | IAM policies control who can read secrets | Control access to API keys, passwords, certificates |
| CloudWatch | IAM policies allow writing logs and metrics | EC2/Lambda send logs using Role permissions |
| DynamoDB | IAM policies for granular table access | Allow only reading, or only writing, or access to specific items |
| STS (Security Token Service) | Generates temporary credentials when assuming Roles | Backend of the Roles system, AssumeRole operations |
| Systems Manager | Session Manager uses IAM Roles (not SSH keys) | Connect to EC2 without opening SSH ports, using IAM auth |
| API Gateway | IAM authorization for APIs | Require AWS Signature V4 signing on requests |
| CloudFormation | Service Role defines stack permissions | Allow CFN to create resources on your behalf |
| Organizations | Service Control Policies (SCPs) | Restrict permissions at the entire account level |
| SSO (AWS IAM Identity Center) | Temporary role assignment via SSO | Single login for multiple AWS accounts |
Additional Resources
Official Documentation
Relevant Whitepapers
Useful Tools
- IAM Policy Simulator - Test policies before applying them
- IAM Access Analyzer - Detect excessive permissions
- AWS Policy Generator - Generate policies visually