Opening Framing
In traditional data centers, network location implied trust—if you could reach a server, you were probably on the internal network and somewhat trusted. Cloud obliterates this assumption. Every resource is accessible via API from anywhere in the world. The only thing standing between an attacker and your crown jewels is identity and access management (IAM).
IAM in the cloud is simultaneously your greatest security control and your greatest risk. Properly configured, it enforces least privilege at a granularity impossible in traditional environments. Misconfigured, a single overprivileged role can expose your entire cloud environment. The complexity of cloud IAM—with its users, groups, roles, policies, permissions, and federation—makes it both powerful and dangerous.
This week covers IAM fundamentals across major cloud providers, policy design and least privilege implementation, role-based access, identity federation, and common IAM vulnerabilities. Mastering IAM is the single most important cloud security skill.
Key insight: Compromise an identity with excessive permissions, and you compromise everything that identity can access.
1) IAM Fundamentals
Cloud IAM systems manage who can do what to which resources:
IAM Core Concepts:
THE IAM QUESTION:
┌─────────────────────────────────────────────────────────────┐
│ Who (Principal) can perform What (Action) on Which (Resource)│
│ under What conditions (Conditions)? │
└─────────────────────────────────────────────────────────────┘
PRINCIPALS (Who):
┌─────────────────────────────────────────────────────────────┐
│ Users: │
│ - Human identities with credentials │
│ - Username/password + MFA │
│ - Access keys for programmatic access │
│ │
│ Groups: │
│ - Collections of users │
│ - Permissions assigned to group, inherited by members │
│ - Simplifies permission management │
│ │
│ Roles: │
│ - Assumable identities (no permanent credentials) │
│ - Used by services, applications, cross-account │
│ - Temporary credentials via STS │
│ │
│ Service Accounts: │
│ - Machine identities for applications │
│ - Non-human principals │
│ - Critical for workload authentication │
└─────────────────────────────────────────────────────────────┘
ACTIONS (What):
┌─────────────────────────────────────────────────────────────┐
│ API operations that can be performed │
│ │
│ Examples: │
│ - s3:GetObject (read object from S3) │
│ - ec2:StartInstances (start EC2 instance) │
│ - iam:CreateUser (create IAM user) │
│ - rds:DeleteDBInstance (delete database) │
│ │
│ Action Patterns: │
│ - service:Action (specific action) │
│ - service:* (all actions in service) │
│ - * (all actions—dangerous!) │
└─────────────────────────────────────────────────────────────┘
RESOURCES (Which):
┌─────────────────────────────────────────────────────────────┐
│ Specific cloud resources actions apply to │
│ │
│ AWS ARN Format: │
│ arn:aws:service:region:account:resource │
│ │
│ Examples: │
│ - arn:aws:s3:::my-bucket/* │
│ - arn:aws:ec2:us-east-1:123456789:instance/* │
│ - arn:aws:iam::123456789:user/john │
│ │
│ Resource Patterns: │
│ - Specific resource ARN │
│ - Wildcards (* for all) │
│ - Resource tags (in some services) │
└─────────────────────────────────────────────────────────────┘
CONDITIONS (Under What Circumstances):
┌─────────────────────────────────────────────────────────────┐
│ Additional constraints on when permission applies │
│ │
│ Examples: │
│ - aws:SourceIp (request from specific IP) │
│ - aws:MultiFactorAuthPresent (MFA used) │
│ - aws:CurrentTime (time-based restrictions) │
│ - aws:RequestedRegion (limit to regions) │
│ - s3:x-amz-acl (object ACL conditions) │
│ │
│ Use Cases: │
│ - Require MFA for sensitive actions │
│ - Restrict access to corporate IP ranges │
│ - Enforce encryption requirements │
│ - Time-based access windows │
└─────────────────────────────────────────────────────────────┘
IAM Across Providers:
Provider IAM Comparison:
AWS IAM:
┌─────────────────────────────────────────────────────────────┐
│ Principals: Users, Groups, Roles │
│ Policies: JSON documents attached to principals/resources │
│ Types: │
│ - Identity-based (attached to user/group/role) │
│ - Resource-based (attached to resource) │
│ - Permission boundaries (max permissions) │
│ - SCPs (organization-level restrictions) │
│ │
│ Key Features: │
│ - Fine-grained permissions │
│ - Cross-account roles │
│ - Service-linked roles │
│ - Instance profiles for EC2 │
└─────────────────────────────────────────────────────────────┘
Azure AD / Entra ID:
┌─────────────────────────────────────────────────────────────┐
│ Principals: Users, Groups, Service Principals, Managed IDs │
│ Policies: RBAC roles assigned at scopes │
│ │
│ Structure: │
│ - Tenant (directory) │
│ └── Management Groups │
│ └── Subscriptions │
│ └── Resource Groups │
│ └── Resources │
│ │
│ Key Features: │
│ - Built-in roles (Owner, Contributor, Reader) │
│ - Custom roles │
│ - Managed identities (no credential management) │
│ - PIM (Privileged Identity Management) │
└─────────────────────────────────────────────────────────────┘
GCP Cloud IAM:
┌─────────────────────────────────────────────────────────────┐
│ Principals: Users, Groups, Service Accounts │
│ Policies: Bindings of principals to roles on resources │
│ │
│ Structure: │
│ - Organization │
│ └── Folders │
│ └── Projects │
│ └── Resources │
│ │
│ Key Features: │
│ - Predefined roles (curated permissions) │
│ - Custom roles │
│ - Workload identity federation │
│ - IAM Conditions │
└─────────────────────────────────────────────────────────────┘
Key insight: Despite different terminology, all cloud IAM systems answer the same question: who can do what to which resources under what conditions.
2) Policy Design and Least Privilege
Effective IAM requires designing policies that grant exactly the permissions needed—no more:
AWS IAM Policy Structure:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowS3ReadAccess",
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::my-bucket",
"arn:aws:s3:::my-bucket/*"
],
"Condition": {
"IpAddress": {
"aws:SourceIp": "192.168.1.0/24"
}
}
}
]
}
Policy Elements:
┌─────────────────────────────────────────────────────────────┐
│ Version: Policy language version (always "2012-10-17") │
│ Statement: Array of permission statements │
│ Sid: Statement identifier (optional, for documentation) │
│ Effect: "Allow" or "Deny" │
│ Action: What operations are permitted/denied │
│ Resource: What resources the actions apply to │
│ Condition: When the statement applies (optional) │
└─────────────────────────────────────────────────────────────┘
Least Privilege Principles:
Implementing Least Privilege:
PRINCIPLE 1: Start with Zero Permissions
┌─────────────────────────────────────────────────────────────┐
│ Default deny—only grant what's explicitly needed │
│ │
│ Bad: Start with admin, remove what's not needed │
│ Good: Start with nothing, add specific permissions │
│ │
│ Process: │
│ 1. Identify specific tasks user/role must perform │
│ 2. Determine minimum actions required │
│ 3. Scope to specific resources │
│ 4. Add conditions where possible │
└─────────────────────────────────────────────────────────────┘
PRINCIPLE 2: Scope Resources Narrowly
┌─────────────────────────────────────────────────────────────┐
│ Never use "*" for resources unless absolutely necessary │
│ │
│ Bad Policy: │
│ "Resource": "*" │
│ │
│ Good Policy: │
│ "Resource": "arn:aws:s3:::app-data-bucket/*" │
│ │
│ Better Policy (with tags): │
│ "Resource": "*", │
│ "Condition": { │
│ "StringEquals": { │
│ "aws:ResourceTag/Environment": "Production" │
│ } │
│ } │
└─────────────────────────────────────────────────────────────┘
PRINCIPLE 3: Use Conditions
┌─────────────────────────────────────────────────────────────┐
│ Add constraints beyond just action and resource │
│ │
│ Common Conditions: │
│ │
│ Require MFA: │
│ "Condition": { │
│ "Bool": {"aws:MultiFactorAuthPresent": "true"} │
│ } │
│ │
│ Restrict Source IP: │
│ "Condition": { │
│ "IpAddress": {"aws:SourceIp": "10.0.0.0/8"} │
│ } │
│ │
│ Require Encryption: │
│ "Condition": { │
│ "StringEquals": { │
│ "s3:x-amz-server-side-encryption": "AES256" │
│ } │
│ } │
└─────────────────────────────────────────────────────────────┘
PRINCIPLE 4: Separate Duties
┌─────────────────────────────────────────────────────────────┐
│ Different roles for different functions │
│ │
│ Example Separation: │
│ - Developers: Read logs, deploy to dev │
│ - Operators: Manage production, read configs │
│ - Security: Read all, modify security controls │
│ - Admins: IAM management (separate from operations) │
│ │
│ Critical Separations: │
│ - IAM administration separate from resource administration │
│ - Production access separate from development │
│ - Audit/read access separate from write access │
└─────────────────────────────────────────────────────────────┘
PRINCIPLE 5: Time-Bound Access
┌─────────────────────────────────────────────────────────────┐
│ Temporary permissions instead of permanent │
│ │
│ Implementations: │
│ - Assume roles instead of permanent credentials │
│ - Just-in-time access for privileged operations │
│ - Session-based permissions │
│ - Time conditions in policies │
│ │
│ Example Time Condition: │
│ "Condition": { │
│ "DateGreaterThan": {"aws:CurrentTime": "2024-01-01"}, │
│ "DateLessThan": {"aws:CurrentTime": "2024-12-31"} │
│ } │
└─────────────────────────────────────────────────────────────┘
Policy Examples:
Real-World Policy Examples:
DEVELOPER ROLE - Read-Only Production:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ReadProductionLogs",
"Effect": "Allow",
"Action": [
"logs:GetLogEvents",
"logs:DescribeLogStreams",
"logs:DescribeLogGroups"
],
"Resource": "arn:aws:logs:*:*:log-group:/aws/prod/*"
},
{
"Sid": "ReadProductionMetrics",
"Effect": "Allow",
"Action": [
"cloudwatch:GetMetricData",
"cloudwatch:ListMetrics"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:ResourceTag/Environment": "production"
}
}
}
]
}
APPLICATION ROLE - Specific S3 Access:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ReadAppConfig",
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::app-config-bucket/config/*"
},
{
"Sid": "WriteAppData",
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject"
],
"Resource": "arn:aws:s3:::app-data-bucket/${aws:userid}/*"
}
]
}
DENY POLICY - Prevent Region Escape:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyNonApprovedRegions",
"Effect": "Deny",
"Action": "*",
"Resource": "*",
"Condition": {
"StringNotEquals": {
"aws:RequestedRegion": [
"us-east-1",
"us-west-2",
"eu-west-1"
]
}
}
}
]
}
Key insight: Good policies are specific, scoped, and conditional. Every wildcard (*) is a potential security hole.
3) Roles and Service Accounts
Roles enable secure access without permanent credentials—critical for services and cross-account access:
AWS IAM Roles:
ROLE COMPONENTS:
┌─────────────────────────────────────────────────────────────┐
│ Trust Policy: WHO can assume the role │
│ Permission Policy: WHAT the role can do │
│ │
│ Trust Policy Example (EC2 can assume): │
│ { │
│ "Version": "2012-10-17", │
│ "Statement": [{ │
│ "Effect": "Allow", │
│ "Principal": { │
│ "Service": "ec2.amazonaws.com" │
│ }, │
│ "Action": "sts:AssumeRole" │
│ }] │
│ } │
│ │
│ This allows EC2 instances to assume this role │
│ and gain its permissions │
└─────────────────────────────────────────────────────────────┘
ROLE TYPES:
┌─────────────────────────────────────────────────────────────┐
│ Service Roles: │
│ - Allow AWS services to act on your behalf │
│ - Example: Lambda execution role, EC2 instance profile │
│ │
│ Cross-Account Roles: │
│ - Allow access from other AWS accounts │
│ - Trust policy specifies allowed account(s) │
│ │
│ Identity Provider Roles: │
│ - Allow federated users to access AWS │
│ - Trust policy specifies IdP │
│ │
│ Service-Linked Roles: │
│ - Pre-defined by AWS services │
│ - Cannot be modified, managed by service │
└─────────────────────────────────────────────────────────────┘
Instance Profiles and Workload Identity:
Workload Identity (No Hardcoded Credentials):
AWS - Instance Profiles:
┌─────────────────────────────────────────────────────────────┐
│ 1. Create IAM role with required permissions │
│ 2. Attach role to EC2 instance profile │
│ 3. Launch instance with instance profile │
│ 4. Application uses SDK to get temporary credentials │
│ │
│ How it works: │
│ - Instance metadata service provides credentials │
│ - http://169.254.169.254/latest/meta-data/iam/ │
│ - Credentials automatically rotated │
│ - No secrets in code or config files │
│ │
│ SDK automatically uses instance credentials: │
│ import boto3 │
│ s3 = boto3.client('s3') # Uses instance role │
│ s3.list_buckets() # No credentials specified │
└─────────────────────────────────────────────────────────────┘
Azure - Managed Identities:
┌─────────────────────────────────────────────────────────────┐
│ System-Assigned: │
│ - Created with and tied to specific resource │
│ - Deleted when resource is deleted │
│ - One per resource │
│ │
│ User-Assigned: │
│ - Created independently │
│ - Can be shared across resources │
│ - Lifecycle independent of resources │
│ │
│ Usage: │
│ from azure.identity import DefaultAzureCredential │
│ credential = DefaultAzureCredential() # Auto-detects │
└─────────────────────────────────────────────────────────────┘
GCP - Service Accounts and Workload Identity:
┌─────────────────────────────────────────────────────────────┐
│ Service Accounts: │
│ - Identity for compute resources │
│ - Attached to VMs, Cloud Functions, etc. │
│ │
│ Workload Identity Federation: │
│ - External workloads assume GCP identity │
│ - No service account keys needed │
│ - Supports GitHub Actions, AWS, Azure, Kubernetes │
│ │
│ Best Practice: │
│ - Never export service account keys │
│ - Use attached service accounts │
│ - Workload identity for external systems │
└─────────────────────────────────────────────────────────────┘
Cross-Account Access:
Cross-Account Role Assumption:
SCENARIO: Account B needs access to S3 in Account A
ACCOUNT A (Resource Owner):
┌─────────────────────────────────────────────────────────────┐
│ Create role: CrossAccountS3Access │
│ │
│ Trust Policy (who can assume): │
│ { │
│ "Version": "2012-10-17", │
│ "Statement": [{ │
│ "Effect": "Allow", │
│ "Principal": { │
│ "AWS": "arn:aws:iam::ACCOUNT-B-ID:root" │
│ }, │
│ "Action": "sts:AssumeRole", │
│ "Condition": { │
│ "StringEquals": { │
│ "sts:ExternalId": "shared-secret-123" │
│ } │
│ } │
│ }] │
│ } │
│ │
│ Permission Policy (what role can do): │
│ { │
│ "Version": "2012-10-17", │
│ "Statement": [{ │
│ "Effect": "Allow", │
│ "Action": "s3:GetObject", │
│ "Resource": "arn:aws:s3:::shared-data-bucket/*" │
│ }] │
│ } │
└─────────────────────────────────────────────────────────────┘
ACCOUNT B (Accessor):
┌─────────────────────────────────────────────────────────────┐
│ Grant permission to assume the role: │
│ │
│ { │
│ "Version": "2012-10-17", │
│ "Statement": [{ │
│ "Effect": "Allow", │
│ "Action": "sts:AssumeRole", │
│ "Resource": "arn:aws:iam::ACCOUNT-A-ID:role/ │
│ CrossAccountS3Access" │
│ }] │
│ } │
│ │
│ Usage in code: │
│ sts = boto3.client('sts') │
│ response = sts.assume_role( │
│ RoleArn='arn:aws:iam::ACCOUNT-A:role/CrossAccountS3', │
│ RoleSessionName='my-session', │
│ ExternalId='shared-secret-123' │
│ ) │
│ # Use temporary credentials from response │
└─────────────────────────────────────────────────────────────┘
Key insight: Roles eliminate the need for long-lived credentials. Every workload should use roles, never access keys.
4) Identity Federation
Federation allows external identity providers to authenticate users for cloud access:
Federation Concepts:
WHY FEDERATE:
┌─────────────────────────────────────────────────────────────┐
│ Problems without federation: │
│ - Multiple identities to manage │
│ - Users forget cloud passwords │
│ - No central identity governance │
│ - Termination doesn't disable cloud access │
│ - No SSO experience │
│ │
│ Benefits of federation: │
│ - Single identity source (corporate directory) │
│ - Centralized access control │
│ - Immediate deprovisioning on termination │
│ - Consistent authentication policies │
│ - SSO across cloud and on-premises │
└─────────────────────────────────────────────────────────────┘
FEDERATION PROTOCOLS:
┌─────────────────────────────────────────────────────────────┐
│ SAML 2.0: │
│ - XML-based protocol │
│ - Enterprise standard │
│ - Browser-based SSO │
│ - IdP sends signed assertion to cloud │
│ │
│ OIDC (OpenID Connect): │
│ - JSON/JWT-based │
│ - Modern, mobile-friendly │
│ - Built on OAuth 2.0 │
│ - Used by social providers, Okta, Azure AD │
│ │
│ Custom Federation (AWS): │
│ - AssumeRoleWithWebIdentity │
│ - Direct integration with IdP │
└─────────────────────────────────────────────────────────────┘
SAML FLOW:
┌─────────────────────────────────────────────────────────────┐
│ │
│ User Corporate IdP AWS │
│ │ │ │ │
│ │─── Login ─────►│ │ │
│ │ │ │ │
│ │◄── SAML ──────│ │ │
│ │ Assertion │ │ │
│ │ │ │ │
│ │────── POST Assertion ──────────►│ │
│ │ │ │ │
│ │◄───── Temporary Credentials ────│ │
│ │ │ │ │
│ │
└─────────────────────────────────────────────────────────────┘
AWS Federation Options:
AWS Identity Federation:
AWS IAM IDENTITY CENTER (SSO):
┌─────────────────────────────────────────────────────────────┐
│ Recommended approach for workforce identity │
│ │
│ Features: │
│ - Central portal for all AWS accounts │
│ - Permission sets define access │
│ - Integrates with external IdPs │
│ - Built-in user directory option │
│ │
│ Flow: │
│ 1. User logs into SSO portal │
│ 2. Authenticates via IdP (Okta, Azure AD, etc.) │
│ 3. Selects account and permission set │
│ 4. Gets temporary credentials │
│ 5. Accesses AWS console or CLI │
└─────────────────────────────────────────────────────────────┘
SAML 2.0 FEDERATION (Direct):
┌─────────────────────────────────────────────────────────────┐
│ Direct federation between IdP and AWS │
│ │
│ Setup: │
│ 1. Create SAML identity provider in IAM │
│ 2. Upload IdP metadata │
│ 3. Create IAM role trusting the IdP │
│ 4. Configure IdP to send appropriate attributes │
│ │
│ Trust Policy for SAML Role: │
│ { │
│ "Version": "2012-10-17", │
│ "Statement": [{ │
│ "Effect": "Allow", │
│ "Principal": { │
│ "Federated": │
│ "arn:aws:iam::123456789:saml-provider/Okta" │
│ }, │
│ "Action": "sts:AssumeRoleWithSAML", │
│ "Condition": { │
│ "StringEquals": { │
│ "SAML:aud": │
│ "https://signin.aws.amazon.com/saml" │
│ } │
│ } │
│ }] │
│ } │
└─────────────────────────────────────────────────────────────┘
WEB IDENTITY FEDERATION:
┌─────────────────────────────────────────────────────────────┐
│ For applications authenticating users via social/OIDC │
│ │
│ Use Cases: │
│ - Mobile apps with Cognito │
│ - GitHub Actions deploying to AWS │
│ - Kubernetes pods accessing AWS │
│ │
│ GitHub Actions Example: │
│ Trust Policy: │
│ { │
│ "Principal": { │
│ "Federated": │
│ "arn:aws:iam::123456789:oidc-provider/ │
│ token.actions.githubusercontent.com" │
│ }, │
│ "Condition": { │
│ "StringEquals": { │
│ "token.actions.githubusercontent.com:aud": │
│ "sts.amazonaws.com" │
│ }, │
│ "StringLike": { │
│ "token.actions.githubusercontent.com:sub": │
│ "repo:myorg/myrepo:*" │
│ } │
│ } │
│ } │
└─────────────────────────────────────────────────────────────┘
Azure AD Federation:
Azure AD as Identity Platform:
AZURE AD CONCEPTS:
┌─────────────────────────────────────────────────────────────┐
│ Tenant: Directory instance (organization) │
│ Application: Registered app that can request tokens │
│ Service Principal: App's identity in a tenant │
│ Managed Identity: Azure-managed service principal │
│ │
│ Authentication: │
│ - Users authenticate to Azure AD │
│ - Azure AD issues tokens │
│ - Tokens grant access to Azure resources │
│ - Tokens can grant access to other clouds (federation) │
└─────────────────────────────────────────────────────────────┘
CONDITIONAL ACCESS:
┌─────────────────────────────────────────────────────────────┐
│ Policy-based access control beyond simple authentication │
│ │
│ Signals: │
│ - User/group membership │
│ - Device state (compliant, hybrid joined) │
│ - Location (IP, country) │
│ - Application being accessed │
│ - Risk level (Azure AD Identity Protection) │
│ │
│ Controls: │
│ - Block access │
│ - Require MFA │
│ - Require compliant device │
│ - Require password change │
│ - Session controls │
│ │
│ Example Policy: │
│ IF user is accessing Azure Portal │
│ AND user is outside corporate network │
│ AND device is not compliant │
│ THEN require MFA │
└─────────────────────────────────────────────────────────────┘
Key insight: Federation centralizes identity management while enabling cloud access—eliminating orphan accounts and password sprawl.
5) IAM Security Best Practices and Common Vulnerabilities
IAM misconfigurations are the leading cause of cloud security incidents:
Common IAM Vulnerabilities:
OVERLY PERMISSIVE POLICIES:
┌─────────────────────────────────────────────────────────────┐
│ Problem: Using "*" for actions or resources │
│ │
│ Dangerous Patterns: │
│ "Action": "*" # Admin to everything │
│ "Action": "s3:*" # Full S3 access │
│ "Resource": "*" # All resources │
│ "Action": "iam:*" # IAM admin │
│ │
│ Real Example: │
│ Developer given "PowerUser" access │
│ - Can't manage IAM directly │
│ - CAN create Lambda with admin role │
│ - Privilege escalation achieved │
│ │
│ Fix: Specific actions on specific resources │
└─────────────────────────────────────────────────────────────┘
EXPOSED ACCESS KEYS:
┌─────────────────────────────────────────────────────────────┐
│ Problem: Hardcoded or leaked credentials │
│ │
│ Common Exposure Points: │
│ - Source code repositories (GitHub) │
│ - Configuration files │
│ - Environment variables in logs │
│ - Container images │
│ - Client-side code │
│ │
│ Attacker Actions: │
│ - Automated scanning of GitHub for AWS keys │
│ - Keys compromised within minutes of commit │
│ - Immediate cryptomining or data theft │
│ │
│ Fix: │
│ - Use roles instead of access keys │
│ - Secrets managers for necessary credentials │
│ - Git hooks to prevent committing secrets │
│ - Regular key rotation │
└─────────────────────────────────────────────────────────────┘
PRIVILEGE ESCALATION PATHS:
┌─────────────────────────────────────────────────────────────┐
│ Problem: Permissions that allow gaining more permissions │
│ │
│ Escalation Techniques: │
│ │
│ 1. iam:CreatePolicyVersion │
│ - Modify managed policy to add permissions │
│ │
│ 2. iam:AttachUserPolicy / AttachRolePolicy │
│ - Attach admin policy to self │
│ │
│ 3. iam:PassRole + service:Create* │
│ - Create resource with privileged role │
│ - Lambda, EC2, Glue, etc. │
│ │
│ 4. sts:AssumeRole on privileged role │
│ - Directly assume more privileged role │
│ │
│ 5. iam:UpdateLoginProfile │
│ - Change another user's password │
│ │
│ Fix: Audit for these permissions, use permission boundaries │
└─────────────────────────────────────────────────────────────┘
MISSING MFA:
┌─────────────────────────────────────────────────────────────┐
│ Problem: Sensitive actions without MFA requirement │
│ │
│ Risk: Stolen password = full access │
│ │
│ Where MFA Should Be Required: │
│ - Console login │
│ - Sensitive API actions │
│ - Production environment access │
│ - IAM changes │
│ - Billing access │
│ │
│ MFA Condition in Policy: │
│ "Condition": { │
│ "Bool": { │
│ "aws:MultiFactorAuthPresent": "true" │
│ } │
│ } │
└─────────────────────────────────────────────────────────────┘
ROOT ACCOUNT MISUSE:
┌─────────────────────────────────────────────────────────────┐
│ Problem: Using root account for daily operations │
│ │
│ Risks: │
│ - Root cannot be restricted │
│ - Root compromise = total account compromise │
│ - No audit trail attribution │
│ │
│ Fix: │
│ - Enable MFA on root (hardware key recommended) │
│ - Never create root access keys │
│ - Use root only for tasks that require it │
│ - Create IAM admin users for administration │
│ - Alert on any root account usage │
└─────────────────────────────────────────────────────────────┘
IAM Security Best Practices:
IAM Security Checklist:
IDENTITY MANAGEMENT:
□ MFA enabled on all human users
□ Hardware MFA on root and admins
□ No shared accounts or credentials
□ Regular access reviews
□ Immediate deprovisioning on termination
□ Federation for workforce identity
CREDENTIAL MANAGEMENT:
□ No long-lived access keys for humans
□ Roles used for all workloads
□ Secrets in secrets manager, not code
□ Regular credential rotation
□ Alerts on credential exposure
PERMISSION MANAGEMENT:
□ Least privilege policies
□ No wildcard actions or resources
□ Permission boundaries on roles
□ Regular permission audits
□ Service Control Policies at org level
□ No inline policies (use managed)
MONITORING:
□ CloudTrail enabled all regions
□ Alert on IAM changes
□ Alert on root account usage
□ Alert on failed authentication
□ Regular access analyzer reviews
GOVERNANCE:
□ Tagging policy for resources
□ Naming conventions for IAM entities
□ Policy review process
□ Change management for IAM
□ Documentation of access patterns
Tools for IAM Security:
IAM Security Analysis Tools:
AWS NATIVE:
┌─────────────────────────────────────────────────────────────┐
│ IAM Access Analyzer: │
│ - Identifies resources shared externally │
│ - Validates policies against best practices │
│ - Generates least-privilege policies │
│ │
│ IAM Policy Simulator: │
│ - Test policies before applying │
│ - Understand effective permissions │
│ │
│ AWS Config Rules: │
│ - iam-password-policy │
│ - iam-root-access-key-check │
│ - mfa-enabled-for-iam-console-access │
└─────────────────────────────────────────────────────────────┘
OPEN SOURCE:
┌─────────────────────────────────────────────────────────────┐
│ Prowler: │
│ - Comprehensive AWS security assessment │
│ - IAM-focused checks │
│ │
│ ScoutSuite: │
│ - Multi-cloud security auditing │
│ - IAM configuration analysis │
│ │
│ Cloudsplaining: │
│ - IAM policy analysis │
│ - Privilege escalation detection │
│ │
│ PMapper (Principal Mapper): │
│ - Maps IAM privilege escalation paths │
│ - Visualizes trust relationships │
│ │
│ IAM Vulnerable: │
│ - Creates intentionally vulnerable IAM for practice │
└─────────────────────────────────────────────────────────────┘
Key insight: Assume every IAM misconfiguration will be found and exploited. Regular auditing and automated enforcement are essential.
Real-World Context
Case Study: Capital One IAM Exploitation
The 2019 Capital One breach centered on IAM misconfiguration. An attacker exploited an SSRF vulnerability to access the EC2 metadata service and retrieve credentials for an IAM role attached to the instance. The role had excessive permissions— including the ability to list and read S3 buckets across the account. Proper least privilege would have limited the role to only the specific buckets and operations the application needed. Additionally, the role could have been scoped to specific source VPCs or required additional authentication for sensitive operations.
Case Study: GitHub Actions OIDC Federation
Organizations traditionally stored AWS access keys in GitHub secrets for CI/CD pipelines. These long-lived credentials were frequently exposed through repository misconfigurations or insider threats. AWS IAM's OIDC federation capability transformed this pattern: GitHub Actions can now assume AWS roles directly using short-lived tokens. No secrets stored, credentials automatically expire after the workflow, and access can be scoped to specific repositories and branches. This demonstrates how proper IAM architecture eliminates entire classes of vulnerabilities.
IAM Anti-Patterns to Avoid:
Common IAM Mistakes:
MISTAKE: "Just use admin for now, we'll fix later"
┌─────────────────────────────────────────────────────────────┐
│ Reality: "Later" never comes, admin persists │
│ Risk: Any compromise has full account access │
│ Fix: Start with least privilege from day one │
└─────────────────────────────────────────────────────────────┘
MISTAKE: One role for all environments
┌─────────────────────────────────────────────────────────────┐
│ Reality: Dev workload can affect production │
│ Risk: Dev compromise = production compromise │
│ Fix: Separate roles per environment with boundaries │
└─────────────────────────────────────────────────────────────┘
MISTAKE: Access keys instead of roles
┌─────────────────────────────────────────────────────────────┐
│ Reality: Keys get committed, shared, forgotten │
│ Risk: Long-lived credentials with no expiration │
│ Fix: Roles with temporary credentials everywhere │
└─────────────────────────────────────────────────────────────┘
MISTAKE: No MFA because "it's inconvenient"
┌─────────────────────────────────────────────────────────────┐
│ Reality: Password alone = trivial to compromise │
│ Risk: Phishing, credential stuffing succeed │
│ Fix: MFA required for all human access │
└─────────────────────────────────────────────────────────────┘
MISTAKE: Not reviewing access after role changes
┌─────────────────────────────────────────────────────────────┐
│ Reality: Former responsibilities retain access │
│ Risk: Privilege accumulation over time │
│ Fix: Regular access reviews, automated cleanup │
└─────────────────────────────────────────────────────────────┘
IAM is the foundation of cloud security. Every other control depends on IAM being correctly configured.
Guided Lab: IAM Policy Design and Analysis
In this lab, you'll design least-privilege policies and analyze existing policies for vulnerabilities.
Lab Environment:
- AWS account with IAM access
- IAM Policy Simulator
- Sample application requirements
Exercise Steps:
- Create IAM user with MFA
- Design policy for specific application needs
- Test policy using IAM Policy Simulator
- Create role for EC2 with instance profile
- Analyze provided overprivileged policy
- Identify privilege escalation paths
- Remediate policy to least privilege
- Document policy decisions
Reflection Questions:
- How did you determine the minimum required permissions?
- What privilege escalation paths did you identify?
- How would you monitor for IAM policy drift?
Week Outcome Check
By the end of this week, you should be able to:
- Explain IAM concepts: principals, actions, resources, conditions
- Compare IAM implementations across AWS, Azure, and GCP
- Design least-privilege IAM policies
- Implement roles for workloads instead of access keys
- Configure identity federation with external IdPs
- Identify common IAM vulnerabilities and privilege escalation paths
- Apply IAM security best practices
- Use IAM analysis tools to audit configurations
🎯 Hands-On Labs (Free & Essential)
Master IAM through hands-on practice—the single most critical cloud security skill.
🔐 TryHackMe: AWS IAM Privilege Escalation
What you'll do: Exploit misconfigured IAM policies to escalate privileges and
understand common attack vectors.
Why it matters: Learning attacker techniques helps you defend against real
IAM exploitation.
Time estimate: 2-3 hours
🛡️ AWS Skill Builder: IAM Policy Design
What you'll do: Complete IAM policy fundamentals lab—create least-privilege
policies and test with Policy Simulator.
Why it matters: Properly designed policies prevent 90% of IAM-related
breaches.
Time estimate: 2-3 hours
🧪 HackTheBox Academy: Cloud IAM Exploitation
What you'll do: Practice identifying and exploiting IAM misconfigurations in
realistic scenarios (free tier modules).
Why it matters: Hands-on exploitation experience is invaluable for
defensive security.
Time estimate: 2-4 hours
💡 Lab Strategy: Start with AWS Skill Builder for policy design fundamentals, then practice exploitation on TryHackMe and HTB to understand attacker perspectives.
Resources
Lab
Complete the following lab exercises to practice cloud IAM security.