Skip to content

Iam

Chapter 3: AWS Identity and Access Management (IAM)

Section titled “Chapter 3: AWS Identity and Access Management (IAM)”

Mastering Security and Access Control in AWS

Section titled “Mastering Security and Access Control in AWS”

IAM is the foundation of AWS security, enabling you to control who can do what in your AWS environment.

IAM Core Components
+------------------------------------------------------------------+
| |
| +------------------------+ |
| | IAM Service | |
| +------------------------+ |
| | |
| +--------------------+--------------------+ |
| | | | |
| v v v |
| +----------+ +----------+ +----------+ |
| | Users | | Groups | | Roles | |
| | | | | | | |
| | - People | | - User | | - AWS | |
| | who | | groups | | services| |
| | login | | - Policy | | - Cross- | |
| | | | attach | | account | |
| +----------+ +----------+ +----------+ |
| | | | |
| +--------------------+--------------------+ |
| | |
| v |
| +------------------------+ |
| | Policies | |
| | | |
| | - Identity-based | |
| | - Resource-based | |
| | - Permission | |
| | boundaries | |
| +------------------------+ |
| |
+------------------------------------------------------------------+

IAM Principals Hierarchy
+------------------------------------------------------------------+
| |
| IAM Principals |
| ============================================================ |
| |
| 1. Root User (Account Owner) |
| +----------------------------------------------------------+ |
| | - Created with AWS account | |
| | - Has full access to all resources | |
| | - Should NOT be used for daily tasks | |
| | - Enable MFA immediately! | |
| +----------------------------------------------------------+ |
| |
| 2. IAM Users |
| +----------------------------------------------------------+ |
| | - Represent people or applications | |
| | - Have long-term credentials (username/password) | |
| | - Can have access keys for programmatic access | |
| | - Should be in groups for easier management | |
| +----------------------------------------------------------+ |
| |
| 3. IAM Roles |
| +----------------------------------------------------------+ |
| | - Temporary credentials | |
| | - No long-term credentials | |
| | - Assumed by users, services, or applications | |
| | - Cross-account access | |
| +----------------------------------------------------------+ |
| |
| 4. Federated Users |
| +----------------------------------------------------------+ |
| | - External identity providers | |
| | - AWS SSO (IAM Identity Center) | |
| | - SAML 2.0 (Active Directory, Okta, etc.) | |
| | - Web Identity (Amazon Cognito, Google, Facebook) | |
| +----------------------------------------------------------+ |
| |
+------------------------------------------------------------------+

IAM User Structure
+------------------------------------------------------------------+
| |
| +------------------------+ |
| | IAM User | |
| | (developer@company) | |
| +------------------------+ |
| | |
| +-----------------+-----------------+ |
| | | |
| v v |
| +----------------+ +----------------+ |
| | Console Login | | Access Keys | |
| | | | | |
| | - Username | | - Access Key ID| |
| | - Password | | - Secret Key | |
| | - MFA (rec.) | | | |
| +----------------+ +----------------+ |
| | | |
| v v |
| +----------------+ +----------------+ |
| | AWS Console | | CLI/SDK/API | |
| | (Web UI) | | (Programmatic) | |
| +----------------+ +----------------+ |
| |
| User Security Best Practices: |
| +----------------------------------------------------------+ |
| | 1. Require MFA for console access | |
| | 2. Enforce password policy | |
| | 3. Rotate access keys regularly | |
| | 4. Use groups instead of attaching policies to users | |
| | 5. Remove unused users and credentials | |
| +----------------------------------------------------------+ |
| |
+------------------------------------------------------------------+
IAM User Creation Process
+------------------------------------------------------------------+
| |
| Step 1: Create User |
| +----------------------------------------------------------+ |
| | aws iam create-user \ | |
| | --user-name developer-john \ | |
| | --path /developers/ | |
| +----------------------------------------------------------+ |
| | |
| v |
| Step 2: Configure Login Profile |
| +----------------------------------------------------------+ |
| | aws iam create-login-profile \ | |
| | --user-name developer-john \ | |
| | --password TempPassword123! \ | |
| | --password-reset-required | |
| +----------------------------------------------------------+ |
| | |
| v |
| Step 3: Create Access Keys (Optional) |
| +----------------------------------------------------------+ |
| | aws iam create-access-key \ | |
| | --user-name developer-john | |
| +----------------------------------------------------------+ |
| | |
| v |
| Step 4: Add to Group |
| +----------------------------------------------------------+ |
| | aws iam add-user-to-group \ | |
| | --user-name developer-john \ | |
| | --group-name Developers | |
| +----------------------------------------------------------+ |
| | |
| v |
| Step 5: Enable MFA |
| +----------------------------------------------------------+ |
| | aws iam enable-mfa-device \ | |
| | --user-name developer-john \ | |
| | --serial-number arn:aws:iam::123456789012:mfa/john \ | |
| | --authentication-code1 123456 \ | |
| | --authentication-code2 789012 | |
| +----------------------------------------------------------+ |
| |
+------------------------------------------------------------------+

IAM Groups Structure
+------------------------------------------------------------------+
| |
| +------------------------+ |
| | Organization | |
| +------------------------+ |
| | |
| +----------+----------+----------+----------+ |
| | | | | | |
| v v v v v |
| +--------+ +--------+ +--------+ +--------+ +--------+ |
| | Admins | | DevOps | |Develop-| | DBA | |Auditors| |
| | | | | | ers | | | | | |
| +--------+ +--------+ +--------+ +--------+ +--------+ |
| | | | | | |
| v v v v v |
| +--------+ +--------+ +--------+ +--------+ +--------+ |
| |Admin | |EC2, | |EC2, | |RDS, | |Read- | |
| |Policy | |S3, | |S3, | |Dynamo- | |Only | |
| | | |Lambda, | |Lambda | |DB | |Policy | |
| | | |CloudFor-| | | | | | | |
| | | |mation | | | | | | | |
| +--------+ +--------+ +--------+ +--------+ +--------+ |
| |
| Benefits of Groups: |
| +----------------------------------------------------------+ |
| | - Easier policy management | |
| | - Consistent permissions across team members | |
| | - Quick onboarding/offboarding | |
| | - Audit-friendly | |
| +----------------------------------------------------------+ |
| |
+------------------------------------------------------------------+

IAM Role Types
+------------------------------------------------------------------+
| |
| 1. AWS Service Roles |
| +----------------------------------------------------------+ |
| | Service: EC2 | |
| | Role: EC2InstanceProfile | |
| | Purpose: Allow EC2 to access S3, DynamoDB, etc. | |
| | | |
| | +--------+ +--------+ +--------+ | |
| | | EC2 | --> | Role | --> | S3 | | |
| | +--------+ +--------+ +--------+ | |
| +----------------------------------------------------------+ |
| |
| 2. Cross-Account Roles |
| +----------------------------------------------------------+ |
| | Account A (Dev) Account B (Prod) | |
| | +--------+ +--------+ | |
| | | Dev | Assume | Prod | | |
| | | User | -----------> | Role | | |
| | +--------+ Role +--------+ | |
| | | |
| | Use Case: Dev team needs read access to Prod resources | |
| +----------------------------------------------------------+ |
| |
| 3. AWS Service-Linked Roles |
| +----------------------------------------------------------+ |
| | Predefined by AWS services | |
| | Cannot be modified | |
| | Examples: | |
| | - AWSServiceRoleForEC2Spot | |
| | - AWSServiceRoleForAutoScaling | |
| | - AWSServiceRoleForRDS | |
| +----------------------------------------------------------+ |
| |
| 4. Web Identity Roles |
| +----------------------------------------------------------+ |
| | External Identity Provider | |
| | +--------+ +--------+ | |
| | | Google | Federate | AWS | | |
| | | User | -----------> | Role | | |
| | +--------+ via OIDC +--------+ | |
| +----------------------------------------------------------+ |
| |
+------------------------------------------------------------------+
Role Assumption Process
+------------------------------------------------------------------+
| |
| Step 1: User/Service Requests Role |
| +----------------------------------------------------------+ |
| | User: developer@company | |
| | Wants to assume: CrossAccountAdminRole | |
| +----------------------------------------------------------+ |
| | |
| v |
| Step 2: STS Verify Permissions |
| +----------------------------------------------------------+ |
| | Check: Does user have sts:AssumeRole permission? | |
| | Check: Does role trust policy allow this user? | |
| +----------------------------------------------------------+ |
| | |
| v |
| Step 3: Generate Temporary Credentials |
| +----------------------------------------------------------+ |
| | Returns: | |
| | - AccessKeyId: AKIAIOSFODNN7EXAMPLE | |
| | - SecretAccessKey: wJalrXUtnFEMI/K7MDENG/... | |
| | - SessionToken: AQoDYXdzEJr... | |
| | - Expiration: 2026-02-16T12:00:00Z | |
| +----------------------------------------------------------+ |
| | |
| v |
| Step 4: Use Temporary Credentials |
| +----------------------------------------------------------+ |
| | User can now access resources defined in role policy | |
| | Credentials expire after session duration | |
| +----------------------------------------------------------+ |
| |
+------------------------------------------------------------------+

IAM Policy Types
+------------------------------------------------------------------+
| |
| 1. Identity-Based Policies (Attached to Principals) |
| +----------------------------------------------------------+ |
| | Managed Policies (AWS or Customer) | |
| | +----------------------------------------------------+ | |
| | | - Reusable across users/roles | | |
| | | - Version controlled | | |
| | | - AWS Managed: AdministratorAccess, PowerUser... | | |
| | +----------------------------------------------------+ | |
| | | |
| | Inline Policies | |
| | +----------------------------------------------------+ | |
| | | - Embedded in user/role/group | | |
| | | - Deleted when principal is deleted | | |
| | | - Use for one-off permissions | | |
| | +----------------------------------------------------+ | |
| +----------------------------------------------------------+ |
| |
| 2. Resource-Based Policies (Attached to Resources) |
| +----------------------------------------------------------+ |
| | Examples: | |
| | - S3 Bucket Policy | |
| | - SQS Queue Policy | |
| | - Lambda Function Policy | |
| | - SNS Topic Policy | |
| | | |
| | Can specify WHO can access the resource | |
| +----------------------------------------------------------+ |
| |
| 3. Permission Boundaries |
| +----------------------------------------------------------+ |
| | - Sets maximum permissions for a principal | |
| | - Used with SCPs for permission boundaries | |
| | - Does NOT grant permissions | |
| +----------------------------------------------------------+ |
| |
| 4. Service Control Policies (SCPs) |
| +----------------------------------------------------------+ |
| | - AWS Organizations feature | |
| | - Sets permission guardrails | |
| | - Applied to OUs or accounts | |
| +----------------------------------------------------------+ |
| |
+------------------------------------------------------------------+
{
"Version": "2012-10-17", // Policy version (always use this)
"Id": "S3ReadPolicy", // Optional identifier
"Statement": [ // Array of statements
{
"Sid": "AllowS3ReadAccess", // Optional statement ID
"Effect": "Allow", // Allow or Deny
"Principal": { // Who the policy applies to
"AWS": "arn:aws:iam::123456789012:user/developer"
},
"Action": [ // What actions
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [ // Which resources
"arn:aws:s3:::my-bucket",
"arn:aws:s3:::my-bucket/*"
],
"Condition": { // Optional conditions
"IpAddress": {
"aws:SourceIp": "192.0.2.0/24"
}
}
}
]
}
Policy Evaluation Flow
+------------------------------------------------------------------+
| |
| Start: Request Made |
| | |
| v |
| +---------------------+ |
| | Explicit Deny? | |
| | (Any policy) | |
| +----------+----------+ |
| | |
| +------------+------------+ |
| | | |
| v v |
| (Yes) (No) |
| | | |
| v v |
| +----------+ +---------------------+ |
| | DENY | | Explicit Allow? | |
| | Request | +----------+----------+ |
| +----------+ | |
| +---------+---------+ |
| | | |
| v v |
| (Yes) (No) |
| | | |
| v v |
| +----------+ +------------------+ |
| | ALLOW | | Default Deny | |
| | Request | | (Implicit) | |
| +----------+ +------------------+ |
| |
| Order of Evaluation: |
| 1. Explicit DENY in any policy -> DENY |
| 2. Explicit ALLOW in any policy -> ALLOW |
| 3. No explicit ALLOW -> IMPLICIT DENY |
| |
+------------------------------------------------------------------+

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:Get*",
"s3:List*"
],
"Resource": [
"arn:aws:s3:::my-bucket",
"arn:aws:s3:::my-bucket/*"
]
}
]
}
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowAllWithMFA",
"Effect": "Allow",
"Action": "*",
"Resource": "*",
"Condition": {
"Bool": {
"aws:MultiFactorAuthPresent": "true"
}
}
},
{
"Sid": "DenyWithoutMFA",
"Effect": "Deny",
"NotAction": [
"iam:GetUser",
"iam:ListMFADevices",
"iam:EnableMFADevice"
],
"Resource": "*",
"Condition": {
"Bool": {
"aws:MultiFactorAuthPresent": "false"
}
}
}
]
}
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "*",
"Resource": "*",
"Condition": {
"IpAddress": {
"aws:SourceIp": [
"192.0.2.0/24",
"203.0.113.0/24"
]
}
}
}
]
}
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "*",
"Resource": "*",
"Condition": {
"DateGreaterThan": {
"aws:CurrentTime": "2026-02-01T09:00:00Z"
},
"DateLessThan": {
"aws:CurrentTime": "2026-02-01T18:00:00Z"
}
}
}
]
}
// Trust Policy (in Account B - Prod)
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::ACCOUNT-A-ID:root"
},
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {
"sts:ExternalId": "unique-external-id"
}
}
}
]
}
// Permission Policy (in Account B - Prod)
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::prod-bucket",
"arn:aws:s3:::prod-bucket/*"
]
}
]
}

IAM Security Checklist
+------------------------------------------------------------------+
| |
| 1. Root Account Security |
| +----------------------------------------------------------+ |
| | [ ] Lock away root credentials | |
| | [ ] Enable MFA on root account | |
| | [ ] Don't use root for daily tasks | |
| | [ ] Delete root access keys | |
| +----------------------------------------------------------+ |
| |
| 2. User Management |
| +----------------------------------------------------------+ |
| | [ ] Use groups for permission assignment | |
| | [ ] Require MFA for console access | |
| | [ ] Enforce strong password policy | |
| | [ ] Rotate credentials regularly | |
| | [ ] Remove unused users | |
| +----------------------------------------------------------+ |
| |
| 3. Role Management |
| +----------------------------------------------------------+ |
| | [ ] Use roles for cross-account access | |
| | [ ] Use roles for EC2/Lambda services | |
| | [ ] Implement external ID for third-party | |
| | [ ] Set appropriate session duration | |
| +----------------------------------------------------------+ |
| |
| 4. Policy Management |
| +----------------------------------------------------------+ |
| | [ ] Follow least privilege principle | |
| | [ ] Use managed policies for reuse | |
| | [ ] Use conditions for additional security | |
| | [ ] Regular policy review and audit | |
| +----------------------------------------------------------+ |
| |
| 5. Monitoring & Auditing |
| +----------------------------------------------------------+ |
| | [ ] Enable CloudTrail | |
| | [ ] Use IAM Access Analyzer | |
| | [ ] Set up IAM credential reports | |
| | [ ] Monitor for unused permissions | |
| +----------------------------------------------------------+ |
| |
+------------------------------------------------------------------+
Least Privilege Approach
+------------------------------------------------------------------+
| |
| BAD: Too Permissive |
| +----------------------------------------------------------+ |
| | { | |
| | "Effect": "Allow", | |
| | "Action": "*", <-- Allows EVERYTHING! | |
| | "Resource": "*" <-- On ALL resources! | |
| | } | |
| +----------------------------------------------------------+ |
| |
| GOOD: Least Privilege |
| +----------------------------------------------------------+ |
| | { | |
| | "Effect": "Allow", | |
| | "Action": [ | |
| | "s3:GetObject", <-- Only specific actions | |
| | "s3:ListBucket" | |
| | ], | |
| | "Resource": [ | |
| | "arn:aws:s3:::my-bucket", <-- Only specific bucket| |
| | "arn:aws:s3:::my-bucket/*" | |
| | ] | |
| | } | |
| +----------------------------------------------------------+ |
| |
| Process to Determine Least Privilege: |
| +----------------------------------------------------------+ |
| | 1. Start with no permissions | |
| | 2. Identify required actions | |
| | 3. Add minimum required permissions | |
| | 4. Test and iterate | |
| | 5. Use IAM Access Analyzer to verify | |
| +----------------------------------------------------------+ |
| |
+------------------------------------------------------------------+

IAM Access Analyzer
+------------------------------------------------------------------+
| |
| Purpose: Identify resources shared with external entities |
| |
| +----------------------------------------------------------+ |
| | Access Analyzer | |
| | | |
| | Scans: | |
| | - S3 Bucket Policies | |
| | - IAM Roles (trust policies) | |
| | - KMS Key Policies | |
| | - Lambda Function Policies | |
| | - SQS Queue Policies | |
| | | |
| | Findings: | |
| | +------------------+------------------+ | |
| | | Resource | Shared With | | |
| | +------------------+------------------+ | |
| | | s3://my-bucket | Account: 999999 | | |
| | | Role: CrossAcct | Account: 888888 | | |
| | | KMS: my-key | Public: * | <-- ALERT! | |
| | +------------------+------------------+ | |
| +----------------------------------------------------------+ |
| |
| Actions: |
| +----------------------------------------------------------+ |
| | 1. Review findings | |
| | 2. Verify intended or unintended | |
| | 3. Remediate unintended access | |
| | 4. Archive resolved findings | |
| +----------------------------------------------------------+ |
| |
+------------------------------------------------------------------+

Terminal window
# List all users
aws iam list-users --query 'Users[*].UserName' --output table
# Create a new user
aws iam create-user --user-name developer-john
# Create access keys for a user
aws iam create-access-key --user-name developer-john
# Create a group
aws iam create-group --group-name Developers
# Add user to group
aws iam add-user-to-group --user-name developer-john --group-name Developers
# Attach managed policy to group
aws iam attach-group-policy \
--group-name Developers \
--policy-arn arn:aws:iam::aws:policy/PowerUserAccess
# Create a role with trust policy
aws iam create-role \
--role-name EC2InstanceRole \
--assume-role-policy-document file://trust-policy.json
# Create instance profile
aws iam create-instance-profile --instance-profile-name EC2InstanceProfile
# Add role to instance profile
aws iam add-role-to-instance-profile \
--role-name EC2InstanceRole \
--instance-profile-name EC2InstanceProfile
# Assume a role
aws sts assume-role \
--role-arn arn:aws:iam::123456789012:role/CrossAccountRole \
--role-session-name "DevSession"
# Get credential report
aws iam get-credential-report --query 'Content' --output text | base64 --decode
# List MFA devices
aws iam list-mfa-devices --user-name developer-john
# Enable MFA device
aws iam enable-mfa-device \
--user-name developer-john \
--serial-number arn:aws:iam::123456789012:mfa/john-device \
--authentication-code1 123456 \
--authentication-code2 789012
import boto3
import json
# Initialize IAM client
iam = boto3.client('iam')
# Create a user
user = iam.create_user(UserName='developer-john')
print(f"Created user: {user['User']['UserName']}")
# Create a group
group = iam.create_group(GroupName='Developers')
# Attach policy to group
iam.attach_group_policy(
GroupName='Developers',
PolicyArn='arn:aws:iam::aws:policy/PowerUserAccess'
)
# Add user to group
iam.add_user_to_group(
UserName='developer-john',
GroupName='Developers'
)
# Create access keys
keys = iam.create_access_key(UserName='developer-john')
print(f"Access Key ID: {keys['AccessKey']['AccessKeyId']}")
print(f"Secret Access Key: {keys['AccessKey']['SecretAccessKey']}")
# Create a role
trust_policy = {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
role = iam.create_role(
RoleName='EC2InstanceRole',
AssumeRolePolicyDocument=json.dumps(trust_policy)
)
# List all users
users = iam.list_users()
for user in users['Users']:
print(f"User: {user['UserName']}, Created: {user['CreateDate']}")

IAM Troubleshooting Guide
+------------------------------------------------------------------+
| |
| Issue 1: "Access Denied" Error |
| +----------------------------------------------------------+ |
| | Possible Causes: | |
| | - Missing policy | |
| | - Explicit deny | |
| | - Condition not met | |
| | - Resource ARN incorrect | |
| | | |
| | Debug Steps: | |
| | 1. Check IAM policy simulator | |
| | 2. Review CloudTrail for denied calls | |
| | 3. Verify resource ARNs | |
| | 4. Check conditions | |
| +----------------------------------------------------------+ |
| |
| Issue 2: "Not authorized to assume role" |
| +----------------------------------------------------------+ |
| | Possible Causes: | |
| | - Missing sts:AssumeRole permission | |
| | - Trust policy doesn't include user | |
| | - External ID mismatch | |
| | | |
| | Debug Steps: | |
| | 1. Check user has sts:AssumeRole | |
| | 2. Verify trust policy Principal | |
| | 3. Check for ExternalId condition | |
| +----------------------------------------------------------+ |
| |
| Issue 3: EC2 instance can't access S3 |
| +----------------------------------------------------------+ |
| | Possible Causes: | |
| | - No instance profile attached | |
| | - Role doesn't have S3 permissions | |
| | - S3 bucket policy denies access | |
| | | |
| | Debug Steps: | |
| | 1. Check instance has IAM role attached | |
| | 2. Verify role has S3 permissions | |
| | 3. Check S3 bucket policy | |
| +----------------------------------------------------------+ |
| |
+------------------------------------------------------------------+

Exam Tip

  1. Root Account: Never use for daily tasks; always enable MFA
  2. IAM Users vs Roles: Users for people, roles for services and temporary access
  3. Policy Evaluation: Explicit deny > Explicit allow > Implicit deny
  4. Least Privilege: Always grant minimum required permissions
  5. Groups: Use groups to manage permissions, not individual users
  6. MFA: Required for sensitive operations, can be enforced via policy
  7. Cross-Account: Use roles, not users, for cross-account access
  8. Instance Profiles: Required for EC2 to assume roles
  9. Access Analyzer: Identifies resources shared externally

Chapter 4: AWS CLI and SDKs


Last Updated: February 2026