IAM
IAM (Identity and Access Management) controls who can access what in your AWS account. Every API call to AWS is authenticated and authorized through IAM. Getting IAM right is the foundation of AWS security.
Core Concepts
Section titled “Core Concepts”┌──────────────────────────────────────────────────┐│ AWS Account ││ ││ ┌─────────┐ ┌─────────┐ ┌──────────────┐ ││ │ Users │ │ Groups │ │ Roles │ ││ │ (people) │ │(teams) │ │ (services/ │ ││ └────┬─────┘ └────┬─────┘ │ temp access)│ ││ │ │ └──────┬───────┘ ││ └──────┬───────┘ │ ││ ▼ ▼ ││ ┌────────────────────────────────┐ ││ │ Policies (JSON) │ ││ │ "Allow s3:GetObject on bucket" │ ││ └────────────────────────────────┘ │└──────────────────────────────────────────────────┘| Concept | What It Is |
|---|---|
| User | An identity for a person or application. Has long-term credentials (password, access keys). |
| Group | A collection of users (e.g. developers, ops). Policies attached to a group apply to all its members. |
| Role | An identity with temporary credentials. Used by AWS services (EC2, Lambda), cross-account access, or federated users. No permanent password or access keys. |
| Policy | A JSON document that defines permissions (allow or deny specific actions on specific resources). |
Creating a User
Section titled “Creating a User”# Create a useraws iam create-user --user-name alice
# Create access keys (for CLI/API access)aws iam create-access-key --user-name alice
# Enable console access (set a password)aws iam create-login-profile --user-name alice --password 'TempP@ss123!' --password-reset-requiredBest Practices for Users
Section titled “Best Practices for Users”- Don’t use the root account for daily work. Create IAM users instead.
- One user per person — never share credentials.
- Use access keys only when needed — prefer roles for services, SSO for humans.
- Rotate access keys regularly and delete unused ones.
- Enable MFA on every user, especially the root account.
Groups
Section titled “Groups”Groups simplify permission management — attach a policy to a group once, and every member inherits it.
# Create a groupaws iam create-group --group-name developers
# Add user to groupaws iam add-user-to-group --user-name alice --group-name developers
# Attach a policy to the groupaws iam attach-group-policy --group-name developers \ --policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccessCommon group patterns:
| Group | Typical Policies |
|---|---|
admins | AdministratorAccess |
developers | PowerUserAccess (everything except IAM) or custom |
read-only | ReadOnlyAccess |
billing | Billing + CostExplorerAccess |
Roles provide temporary credentials via the AWS Security Token Service (STS). They’re safer than long-term access keys because credentials expire automatically.
Common Use Cases
Section titled “Common Use Cases”| Use Case | Example |
|---|---|
| EC2 instance role | An EC2 server needs to read from S3 — attach a role, no access keys needed |
| Lambda execution role | A Lambda function needs to write to DynamoDB |
| Cross-account access | Account A lets a role in Account B access its S3 bucket |
| Federated access | Users from your company’s SSO (Okta, Azure AD) assume a role |
| EKS pod role | A Kubernetes pod needs AWS API access (IAM Roles for Service Accounts) |
Creating a Role (CLI)
Section titled “Creating a Role (CLI)”# Create a role that EC2 can assumeaws iam create-role --role-name MyEC2Role \ --assume-role-policy-document '{ "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Principal": {"Service": "ec2.amazonaws.com"}, "Action": "sts:AssumeRole" }] }'
# Attach a policy to the roleaws iam attach-role-policy --role-name MyEC2Role \ --policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess
# Create an instance profile (needed to attach role to EC2)aws iam create-instance-profile --instance-profile-name MyEC2Profileaws iam add-role-to-instance-profile --instance-profile-name MyEC2Profile --role-name MyEC2RoleTrust Policy vs Permission Policy
Section titled “Trust Policy vs Permission Policy”Every role has two types of policies:
| Policy Type | Question It Answers | Example |
|---|---|---|
| Trust policy | Who can assume this role? | "Principal": {"Service": "ec2.amazonaws.com"} |
| Permission policy | What can the role do? | "Action": "s3:GetObject" on arn:aws:s3:::my-bucket/* |
Policies
Section titled “Policies”Policies are JSON documents that define permissions. They follow an Evaluate → Deny by default → Explicit allow → Explicit deny wins model.
Policy Structure
Section titled “Policy Structure”{ "Version": "2012-10-17", "Statement": [ { "Sid": "AllowS3Read", "Effect": "Allow", "Action": [ "s3:GetObject", "s3:ListBucket" ], "Resource": [ "arn:aws:s3:::my-bucket", "arn:aws:s3:::my-bucket/*" ] } ]}| Field | Meaning |
|---|---|
Version | Always "2012-10-17" (the current policy language version) |
Statement | Array of permission rules |
Sid | Optional identifier for the statement |
Effect | "Allow" or "Deny" |
Action | AWS API actions (e.g. s3:GetObject, ec2:RunInstances, *) |
Resource | ARNs of the resources the actions apply to (* = all) |
Condition | Optional conditions (IP range, time, MFA required, etc.) |
Policy Types
Section titled “Policy Types”| Type | Attached To | Managed By |
|---|---|---|
| AWS managed | User/group/role | AWS (e.g. AmazonS3ReadOnlyAccess) |
| Customer managed | User/group/role | You (reusable across the account) |
| Inline | Single user/group/role | You (embedded, not reusable) |
| Resource-based | A resource (S3 bucket, SQS queue) | You (who can access this resource from outside) |
| Permission boundary | User/role | You (sets maximum permissions — a “guardrail”) |
| Service control policy (SCP) | AWS Organization OU/account | Org admin (restricts what an entire account can do) |
Policy Evaluation Logic
Section titled “Policy Evaluation Logic”Request arrives │ ▼Is there an explicit Deny? ──► Yes ──► DENIED │ No ▼Is there an explicit Allow? ──► Yes ──► ALLOWED │ No ▼DENIED (implicit deny — default)Explicit deny always wins, even if another policy says allow.
Common Policy Examples
Section titled “Common Policy Examples”Allow EC2 start/stop in a specific region:
{ "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Action": ["ec2:StartInstances", "ec2:StopInstances"], "Resource": "*", "Condition": { "StringEquals": {"aws:RequestedRegion": "us-east-1"} } }]}Deny all actions without MFA:
{ "Version": "2012-10-17", "Statement": [{ "Sid": "DenyWithoutMFA", "Effect": "Deny", "Action": "*", "Resource": "*", "Condition": { "BoolIfExists": {"aws:MultiFactorAuthPresent": "false"} } }]}Least Privilege
Section titled “Least Privilege”The principle of least privilege means granting only the permissions needed to perform a task — nothing more.
How to Apply It
Section titled “How to Apply It”- Start with zero permissions and add as needed.
- Use AWS managed policies as a starting point, then narrow down.
- Use IAM Access Analyzer to review what permissions are actually used vs granted.
- Scope resources — don’t use
"Resource": "*"when you know the specific bucket/table/queue. - Use conditions — restrict by IP, region, time, or MFA.
- Review regularly — remove unused users, roles, and permissions.
IAM Access Analyzer
Section titled “IAM Access Analyzer”# Generate a policy based on actual usage (last 90 days of CloudTrail)aws accessanalyzer generate-access-policy --principal-arn arn:aws:iam::123456789012:role/MyRoleThis shows you what the role actually used, so you can trim the policy.
Multi-Factor Authentication (MFA)
Section titled “Multi-Factor Authentication (MFA)”MFA adds a second factor (usually a TOTP app like Google Authenticator) to password-based logins.
Enabling MFA
Section titled “Enabling MFA”# Create a virtual MFA deviceaws iam create-virtual-mfa-device --virtual-mfa-device-name alice-mfa \ --outfile /tmp/qrcode.png --bootstrap-method QRCodePNG
# Enable MFA for a user (after scanning QR and getting two consecutive codes)aws iam enable-mfa-device --user-name alice \ --serial-number arn:aws:iam::123456789012:mfa/alice-mfa \ --authentication-code1 123456 --authentication-code2 789012MFA Priority
Section titled “MFA Priority”- Root account — Enable MFA immediately. Use a hardware key if possible.
- All human users — Enforce with a policy that denies actions without MFA.
- Sensitive operations — Require MFA for deleting resources, changing IAM, etc.
IAM Best Practices Summary
Section titled “IAM Best Practices Summary”| Practice | Why |
|---|---|
| Don’t use root account | Root has unrestricted access; use IAM users/roles instead |
| Enable MFA everywhere | Protects against credential theft |
| Use roles, not access keys | Temporary credentials are safer |
| Apply least privilege | Minimize blast radius of compromised credentials |
| Use groups for permissions | Easier to manage than per-user policies |
| Tag users and roles | Track ownership and purpose |
| Review with Access Analyzer | Find unused permissions and over-privileged roles |
| Use SCPs in AWS Organizations | Guardrails across multiple accounts |
Key Takeaways
Section titled “Key Takeaways”- Users have long-term credentials; roles have temporary credentials. Prefer roles whenever possible.
- Policies are JSON documents with Effect/Action/Resource. Explicit deny always wins.
- Groups simplify permission management — attach policies to groups, add users to groups.
- Least privilege means starting with zero permissions and adding only what’s needed.
- MFA is non-negotiable on the root account and recommended for all human users.