AWS IAM
LearningTree Β· AWS Security Β· Deep Dive

AWS IAM β€”
Identity & Access Management

The complete guide from first principles to professional mastery. Every API call, every service interaction, every resource access β€” IAM controls it all. Understand it deeply, secure everything.

8 Chapters Beginner β†’ Professional Exam Ready Real-World Patterns

⚑ IAM in 30 Seconds

  • WHO: IAM defines every identity in AWS β€” humans (IAM Users), machines (IAM Roles), federated identities (SSO/OIDC).
  • WHAT: Policies (JSON documents) define what actions are allowed or denied. Nothing is allowed by default.
  • WHICH: Every policy targets specific AWS resources using ARNs β€” precise down to a single S3 object.
  • HOW: IAM sits between every caller and every AWS service. Every API call is authenticated then authorized through IAM β€” no exceptions.
01
Chapter One

What is IAM

The Problem IAM Solves Introductory

Imagine you just created an AWS account. You have one set of credentials β€” the root account. Your team grows: developers, data scientists, DevOps engineers, QA testers. You share the root credentials. One developer accidentally deletes a production database. Another downloads customer data to their laptop. There is no log of who did what. There is no way to restrict who can do what. You are one mistake away from catastrophe.

IAM exists to solve this exact problem. AWS Identity and Access Management gives you a way to create separate identities for every person and every service, grant each one exactly the permissions they need β€” nothing more β€” and audit every single action with a full trail.

☠️

Without IAM (The Chaos Scenario)

  • Everyone shares root credentials β€” no individual accountability
  • All-or-nothing access β€” intern can delete production data
  • No audit trail β€” breach discovered weeks later, no idea who did it
  • Shared access keys checked into code β€” leaked publicly on GitHub
  • Services access everything β€” Lambda can read any S3 bucket
  • No instant revocation β€” must change all creds to remove one person
πŸ›‘οΈ

With IAM (Controlled Access)

  • Individual identities β€” every person and service has unique, traceable creds
  • Least privilege β€” developers deploy but cannot delete production databases
  • Full audit trail β€” CloudTrail logs every API call with identity, time & outcome
  • Roles for services β€” Lambda can only access its specific DynamoDB table
  • Instant revocation β€” disable one user in seconds, no others affected
  • Conditions β€” access only from corporate IP, only with MFA active
What IAM Is β€” The Precise Definition Core

IAM is the AWS service that answers two fundamental security questions for every single action taken in your AWS account:

Authentication (AuthN)
"Who are you?" β€” Verify the identity of the caller. Prove that this request comes from who it claims, using credentials: a password, an access key, or a temporary security token.
Authorization (AuthZ)
"What are you allowed to do?" β€” After identity is confirmed, check whether that identity has permission to perform the requested action on the requested resource. Done by evaluating policies.
Enforcement
"Allow or Deny?" β€” IAM renders a final decision. Allowed β†’ action proceeds. Denied β†’ 403 Forbidden. No partial execution. No fallthrough. The action either fully executes or does not execute at all.
⚑ Core Principle

IAM is not a firewall you can bypass. It is not an optional security layer. Every single AWS API call β€” Console, CLI, SDK, or service-to-service β€” passes through IAM. There is no path around it. This is by design: a single, unified security enforcement point for the entire cloud.

Diagram 1 β€” Concept: The Security Decision Flow Introductory
Concept Diagram β€” Identity β†’ Authenticate β†’ Authorize β†’ Decision β†’ Resource
β‘  IDENTITY β‘‘ AUTHENTICATE β‘’ AUTHORIZE β‘£ DECIDE β‘€ OUTCOME CALLER πŸ‘€ IAM User 🎭 IAM Role 🌐 Federated βš™οΈ AWS Service 🚫 Root API call AUTHΒ·N Who are you? Check credentials Password / Key Fail β†’ 401 verified AUTHΒ·Z What can you do? Evaluate policies Effect / Action / Resource / Condition result DECIDE Allow or Deny? allow? Global Β· Free Β· Default DENY YES NO βœ… ALLOWED Action proceeds S3 / EC2 / Lambda … ❌ DENIED 403 Forbidden Action does NOT execute ⚠️ DEFAULT DENY β€” the fundamental rule If no policy explicitly grants Allow, the answer is DENY. "Not denied" does NOT mean allowed. Silence = Deny.
Every AWS API call follows this exact 5-phase path. No exceptions, no shortcut, no bypass.
Authentication vs Authorization β€” The Critical Distinction Core

These two concepts are frequently conflated but represent completely different phases. IAM handles both, in strict sequence β€” authorization never runs if authentication fails.

DimensionAuthentication (AuthN)Authorization (AuthZ)
Core Question"Who are you?""What can you do?"
IAM ChecksCredentials β€” password, access key, token signaturePolicies β€” JSON permission documents
SequenceAlways first. Authorization won't run without it.Runs only after identity is confirmed.
Success meansIdentity proven β€” AWS knows who is making the requestPermission confirmed β€” identity is allowed
Failure HTTP Code401 Unauthorized403 Forbidden
Real-World AnalogyShowing your passport β€” proves who you areBoarding pass β€” you're allowed on THIS specific flight
What makes it failWrong password, expired key, invalid token signatureNo Allow in any policy, or an explicit Deny exists
πŸ’‘ Debug Example: 401 vs 403

You run aws s3 ls s3://my-bucket. If 401 β†’ your AWS credentials are missing or misconfigured (~/.aws/credentials issue). If 403 β†’ credentials are fine, but no IAM policy grants s3:ListBucket on that bucket. Different problems, completely different fixes.

The Four Dimensions of IAM Control Core

Every IAM permission statement is built on four questions. Together, they define every access boundary in AWS:

πŸ‘€

WHO β€” The Principal

  • IAM Users β€” individual human identities (permanent)
  • IAM Roles β€” assumed identities (services, cross-account)
  • IAM Groups β€” collections of users sharing policies
  • Federated identities β€” SSO, SAML, OIDC, Web Identity
  • AWS Services β€” EC2, Lambda, ECS using service roles
  • Root account β€” unrestricted access (never use for daily work)
⚑

WHAT β€” The Action

  • s3:GetObject β€” read a specific file from S3
  • ec2:StartInstances β€” start an EC2 instance
  • lambda:InvokeFunction β€” call a Lambda function
  • iam:CreateUser β€” create an IAM user (high sensitivity!)
  • * β€” wildcard for all actions (use with extreme care)
  • Each service defines its own set of available actions
πŸ—‚οΈ

WHICH β€” The Resource (ARN)

  • arn:aws:s3:::my-bucket/* β€” all objects in one bucket
  • arn:aws:ec2:us-east-1:123:instance/i-abc β€” one instance
  • arn:aws:dynamodb:*:*:table/orders β€” one DynamoDB table
  • * β€” all resources (dangerous at account level)
  • ARN = Amazon Resource Name β€” globally unique identifier
πŸ”

WHEN/HOW β€” The Condition

  • aws:SourceIp β€” only from specific IP/range
  • aws:MultiFactorAuthPresent β€” only if MFA is active
  • aws:RequestedRegion β€” restrict to specific regions
  • s3:prefix β€” objects with specific path prefix only
  • aws:CurrentTime β€” time-bounded access windows
Mental Model β€” Corporate Building Security Core

The best mental model for IAM is a large corporate office building with an advanced security system. Every element maps precisely to an IAM concept:

🏒 Building Security System

The building β€” the AWS Account. Everything inside is your cloud infrastructure.

Building's master key β€” Root account. Opens every door. Kept in the CEO's safe. Never used daily.

ID badge / keycard β€” IAM credentials. Proves who you are at any door.

Access level on badge β€” IAM policies. Badge level 3 opens floors 1–3, not floor 7 (exec suite).

Visitor / contractor pass β€” IAM Role. Temporary. Returned when done. Cannot reuse it.

Department access group β€” IAM Group. All Finance employees share the same floor access. Change group β†’ affects everyone.

Security guard log β€” CloudTrail. Every door entry: who, when, which door.

☁️ AWS IAM Equivalent

AWS Account β€” isolated environment containing all your AWS resources.

Root account β€” email + password at account creation. Unrestricted. Create β†’ MFA β†’ lockbox.

IAM User credentials β€” username+password (console) or access key+secret (CLI/SDK). Long-lived, tied to one individual.

IAM Policy β€” JSON document: Effect, Action, Resource, Condition. The exact rules that grant or deny access.

IAM Role β€” assumed identity returning temporary credentials (15 min–12 hr). Preferred over long-lived user keys for services.

IAM Group β€” collection of users sharing policies. Not an identity β€” cannot authenticate directly. Cannot contain other groups.

CloudTrail β€” complete audit log of every IAM decision: authenticated, authorized, allowed, or denied.

Diagram 2 β€” AWS: IAM as the Central Authority Core
AWS Diagram β€” IAM Controls All Identities β†’ All Services (Global Β· Free Β· Default Deny)
AWS ACCOUNT 123456789 πŸ‘€ IAM User Console Β· CLI Β· SDK πŸ‘₯ IAM Group Developers Β· DevOps Β· ReadOnly 🎭 IAM Role EC2 Β· Lambda Β· Cross-Account 🌐 Federated Identity SSO Β· SAML Β· OIDC 🚫 Root Account Unrestricted β€” Never use daily IDENTITIES AWS IAM β‘  Authenticate identity β‘‘ Evaluate all policies β‘’ Render Allow / Deny Global Β· Free Β· Default DENY all API calls Amazon S3 Object Storage Amazon EC2 Compute AWS Lambda Serverless Compute DynamoDB NoSQL Database + 200 More Services RDS Β· VPC Β· CloudWatch … RESOURCES if ALLOWED β†’
IAM is the universal gatekeeper β€” all identity types funnel through it before any service is touched.
IAM is Global β€” Not Regional Core

Most AWS services are regional β€” an RDS database in us-east-1 doesn't exist in eu-west-1. IAM is fundamentally different: it is global.

🌍

Global Scope

  • Create user "alice" once β€” works in ALL regions
  • Policies apply globally across all services
  • No concept of "deploy IAM to a region"
  • Console shows no region selector for IAM
⏱️

Eventual Consistency

  • Changes propagate globally in seconds
  • Not instantaneous across all regions
  • Automation may need retry logic
  • Relevant for high-velocity deployments
πŸ’Έ

IAM is Free

  • Zero cost for users, groups, roles, policies
  • No charge for policy evaluation API calls
  • Pay only for resources accessed, not IAM itself
  • No reason to be stingy with permissions design
What Happens on Every API Call β€” Step-by-Step Deep Dive

When a developer runs aws s3 ls s3://my-bucket, here is exactly what AWS does, in order:

  1. Request arrives at AWS endpoint (signed)
    The CLI signs the request using the configured credentials (access key ID + secret access key β†’ HMAC-SHA256 / SigV4 signature). The signed request is sent to the S3 regional endpoint.
  2. IAM verifies the signature β€” Authentication
    AWS extracts the access key ID, finds the corresponding secret key in IAM, and re-derives the expected signature. Match β†’ identity confirmed. No match β†’ 401 Unauthorized. Stops here. Authorization never runs.
  3. IAM determines the principal's full context
    Who is this principal? User, role, federated identity? Which account? What type of credentials (permanent, temporary)? What session policies? IAM collects all applicable policies: identity-based, resource-based, boundaries, SCPs.
  4. IAM evaluates all policies β€” Authorization
    Is there an explicit Deny anywhere? (If yes β†’ 403, stop). Is there an explicit Allow in any applicable policy? (If yes β†’ proceed). Neither? β†’ Default Deny β†’ 403. All conditions (IP, MFA, time, region) are also evaluated here.
  5. Decision rendered β€” Action executes or is blocked
    Allowed: S3 service executes ListBucket and returns the response. Denied: AccessDenied (403) returned. The action never executes. CloudTrail logs the attempt and outcome either way.
⚠️ Critical: The "Default Deny" Rule

AWS begins every authorization evaluation in a DENY state. It only changes to ALLOW if a policy explicitly grants it. You cannot "accidentally" allow something. "Not denied" β‰  allowed. Silence = Deny. Access must be explicitly granted β€” it is never implied by absence of a deny statement.

Diagram 3 β€” Architecture: Real-World Permission Setup Professional
Architecture Diagram β€” Multi-Team Least-Privilege Permission Structure
AWS ACCOUNT 123456789 πŸ‘₯ DevOps Group πŸ‘€ alice πŸ‘€ bob πŸ“œ EC2FullAccess πŸ“œ Lambda:Deploy βœ— No S3 write Β· No DDB πŸ‘₯ Data Team πŸ‘€ carol πŸ‘€ dave πŸ“œ S3:Read data/* πŸ“œ DDB:Read *-analytics βœ— No EC2 Β· No Lambda invoke πŸ‘₯ ReadOnly Group πŸ‘€ eve (auditor) πŸ‘€ frank πŸ“œ ViewOnlyAccess πŸ“œ CloudTrail:ReadOnly βœ— No writes anywhere 🎭 Service Roles 🎭 EC2-S3-WriteRole 🎭 Lambda-DDB-ReadWrite πŸ“œ Least-privilege scoped βœ“ Temp creds Β· No keys AWS IAM β€” Policy Evaluation Engine Default DENY β†’ Check Explicit Deny β†’ Check Explicit Allow β†’ FINAL DECISION (per identity, per action, per resource) EC2 Instances DevOps: Start/Stop/SSH ReadOnly: Describe only DataTeam: No Access Role: Assumed by instance S3 Buckets DataTeam: Read data/* EC2-Role: Write logs/* DevOps: No Write ReadOnly: List only Lambda Functions DevOps: Deploy/Update Lambda-Role: Self-invoke DataTeam: No Access ReadOnly: View config DynamoDB Tables Lambda-Role: Read+Write DataTeam: Read *-analytics DevOps: No Access ReadOnly: Describe only Each identity gets exactly the permissions they need. Nothing more. IAM enforces every boundary. Service roles (EC2, Lambda) use temporary credentials β€” no hardcoded access keys anywhere. This is the Least Privilege Principle β€” the cornerstone of AWS security design.
Real-world multi-team setup. Each team and each service gets precisely scoped access. IAM evaluates and enforces every boundary automatically.
IAM Key Properties β€” Quick Reference Professional
PropertyDetailWhy It Matters
Global ServiceNot region-specific. IAM entities work in all regions.Exam Console shows no region. Created once, works everywhere.
FreeNo charge for IAM itself. Unlimited users, roles, policies.Exam No cost reason to avoid IAM best practices.
Default DenyEvery authorization starts as DENY. Must explicitly Allow.Critical Silence = Deny. "Not denied" β‰  allowed.
Eventual ConsistencyPolicy changes replicate globally in seconds (not instant).Exam Automation may need retry logic immediately after changes.
Max IAM Users5,000 users per accountExam Large orgs use federation instead of individual IAM users.
Max Groups300 groups per accountOrganize by team, function, or access level.
Max Roles1,000 roles per account (soft limit)One role per service/application for fine-grained control.
Access Keys per UserMax 2 active keys per IAM userDesign Two keys allow zero-downtime rotation: create new β†’ update apps β†’ delete old.
Temp Cred Duration15 minutes to 12 hours (role-dependent, STS)Exam Short-lived, auto-expiring, no manual revocation needed.
MFA TypesVirtual (TOTP app), Hardware (U2F / Yubikey)Always enable MFA on root. Recommended for all privileged users.
IAM in Exam Context Professional
πŸŽ“ Exam Tips β€” Chapter 01: What is IAM
  • IAM = Global service β€” no region in console. One set of users/roles works everywhere, always.
  • IAM = Free β€” no cost. Never a budget reason to avoid security best practices.
  • Default Deny β€” every evaluation starts as DENY. Must have explicit Allow. "Not denied" β‰  allowed. Silence = Deny.
  • 401 vs 403 β€” 401 = bad credentials (AuthN fail). 403 = good credentials, no permission (AuthZ fail). Different fixes entirely.
  • Root account β€” cannot be restricted by SCPs or permission boundaries. Unrestricted. Secure with MFA + lockbox. Never use daily.
  • Every API call goes through IAM β€” console, CLI, SDK, CloudFormation, service-to-service. No exceptions, no bypass.
  • IAM eventual consistency β€” changes can take seconds to minutes to propagate globally. Not instantaneous.
  • AuthN before AuthZ β€” strict sequence. Authentication always runs first. If auth fails, authorization never runs.
  • Users = maximum 5,000 per account. At scale, use IAM Identity Center + federation, not individual IAM users.
πŸ“‹ Chapter 01 Summary β€” What is IAM
  • IAM = Identity and Access Management. The universal security enforcement layer for every action in AWS.
  • Two-phase security: Authentication ("who are you?" β†’ credentials check) β†’ Authorization ("what can you do?" β†’ policy evaluation).
  • Every API call passes through IAM β€” Console, CLI, SDK, service-to-service. No bypass, no exceptions, no shortcuts.
  • Default Deny: nothing is allowed unless a policy explicitly grants Allow. "Silence = Deny" is the fundamental rule.
  • Global service: IAM entities (users, groups, roles, policies) work across all AWS regions. Not region-specific. Free.
  • Mental model: Corporate building security β€” badges (credentials), access levels (policies), visitor passes (roles), master key in safe (root).
  • Four control dimensions: WHO (principal) Β· WHAT (action) Β· WHICH (resource) Β· WHEN/HOW (condition).
  • 401 = bad credentials (authentication failure) Β· 403 = no permission (authorization failure). Critical debugging distinction.
  • Least privilege principle: grant only what is needed, nothing more. IAM makes this enforceable at every level.
  • Roles beat keys: temporary credentials (IAM Roles) are always preferred over long-lived access keys for services.
Chapter 01 β€” The Single Most Important Idea

IAM is the single point of security enforcement for every action in AWS. Default deny. Explicit allow required. Without IAM, there is no cloud security β€” it IS the security. Master IAM, and everything else in AWS security becomes an extension of what you already understand.

02
Chapter Two

Core Components: Users, Groups, Roles & Policies

The Four Building Blocks of IAM Introductory

IAM has four core entity types. Mastering how they relate β€” and when to use each β€” is the foundation of every AWS security design. The mental mistake most beginners make is treating Users and Roles as interchangeable. They are not.

πŸ‘€

IAM Users β€” Permanent Identities

  • A long-lived identity tied to one specific person or application
  • Has a fixed set of credentials: password (console) and/or access keys (CLI/SDK)
  • Access keys never expire automatically β€” must be rotated manually
  • Policies attached directly to user OR inherited through Groups
  • Max 5,000 per account β€” not suitable for large orgs at scale
  • Best for: individual developers, break-glass accounts, legacy apps that can't use roles
🎭

IAM Roles β€” Temporary Identities

  • An identity that is assumed temporarily and returns short-lived credentials
  • No password, no permanent access keys β€” credentials expire automatically
  • Can be assumed by: EC2, Lambda, ECS, other services, users in same/other accounts, federated identities
  • Preferred over Users for machine-to-machine access β€” no long-lived secrets to leak
  • Has two policy types: Trust Policy (who can assume) + Permission Policy (what they can do)
  • Best for: all AWS services, cross-account access, CI/CD, federation
πŸ‘₯

IAM Groups β€” Organizing Users

  • A collection of IAM Users that share the same policies
  • Not an identity β€” a Group cannot authenticate or assume a role
  • Makes management easy: add user to group β†’ inherits all group policies instantly
  • Groups can have multiple policies attached; users can be in multiple groups
  • Cannot be nested β€” a group cannot contain other groups
  • Best for: organizing by job function (Developers, DevOps, ReadOnly, Billing)
πŸ“œ

IAM Policies β€” Permission Documents

  • JSON documents that define what is allowed or denied
  • Attached to Users, Groups, or Roles β€” they have no effect alone
  • Two main types: Identity-based (attached to identity) and Resource-based (attached to resource)
  • Managed policies (reusable) vs Inline policies (embedded, one-to-one)
  • Evaluated together β€” IAM checks all attached policies to make a single decision
  • Deep dive: Chapter 03
The Root Account β€” The Master Key Core

The root account is created when you first sign up for AWS using an email + password. It has unrestricted, irrevocable access to everything in the account β€” it cannot be limited by any IAM policy, permission boundary, or SCP.

🚫

What Root CAN'T Be Restricted By

  • IAM policies β€” root ignores all identity-based policies
  • Permission boundaries β€” do not apply to root
  • SCPs (Service Control Policies) β€” do not apply to the management account's root user
  • There is no "deny root" policy β€” it literally cannot be locked down via IAM
πŸ”’

Root-Only Actions (Must Use Root)

  • Change account name, email, or root password
  • Enable IAM billing access for non-root users
  • Close the AWS account
  • Restore IAM user permissions after accidental lockout
  • Subscribe/unsubscribe from some AWS support plans
  • Register as seller in the Reserved Instance Marketplace
⚠️ Root Account Security β€” Non-Negotiable

Immediately after creating an AWS account: (1) Enable MFA on root. (2) Create an admin IAM user for daily work. (3) Store root credentials in a password manager. (4) Never use root for any daily operation β€” not even "just this once." A compromised root account = complete account takeover with no recovery path.

IAM Users β€” Credential Types & Lifecycle Core
Credential TypeUsed ForDetailsBest Practice
Username + Password AWS Management Console login Set by admin. User can change it. Password policy enforced account-wide. Require MFA for all console users. Set minimum length + complexity.
Access Key ID + Secret CLI, SDK, API calls (programmatic) The secret is shown ONCE at creation. Max 2 keys per user. Never expire automatically. Rotate every 90 days. Delete unused keys. Prefer roles over long-lived keys.
SSH Keys AWS CodeCommit (Git over SSH) Separate from other IAM credentials. Attached to user for CodeCommit access only. Use HTTPS + credential helper instead. SSH keys are per-user.
Service-specific credentials CodeCommit HTTPS, Keyspaces (Cassandra) Auto-generated credentials for specific services. Not AWS-wide API keys. Generate only when needed. Delete after use.
πŸ’‘ Access Key Rotation β€” Zero Downtime Pattern

IAM allows max 2 access keys per user precisely for rotation: (1) Create new key β†’ (2) Update all apps/scripts to use new key β†’ (3) Verify new key works β†’ (4) Deactivate (not delete) old key β†’ (5) Wait and confirm nothing broke β†’ (6) Delete old key. Never delete first, replace second β€” that causes downtime.

IAM Groups β€” Organization & Policy Inheritance Core

Groups solve a management problem: when you have 50 developers and need to give all of them the same permissions, you don't attach 50 individual policies. You create a Developers group, attach one policy to it, and add all 50 users to it. Change the policy once β€” all 50 users get the update instantly.

Policy Inheritance
A user in a group automatically inherits all of the group's policies. A user in multiple groups inherits policies from ALL groups. All inherited policies are evaluated together during authorization.
Group Limits
Max 300 groups per account. A user can be in max 10 groups. Groups cannot contain other groups (no nesting). IAM does not support group hierarchy.
Groups are NOT identities
A group is purely an organizational tool. You cannot use a group as a principal in a policy. You cannot "log in as a group". You cannot assume a group like a role. Groups exist only to simplify user management.
Common Group Patterns
Administrators β€” AdministratorAccess policy Β· Developers β€” dev service permissions Β· DevOps β€” deploy + infra permissions Β· ReadOnly β€” ViewOnlyAccess Β· Billing β€” billing console access only
IAM Roles β€” Temporary Credentials & Trust Deep Dive

Roles are the most important IAM entity for modern AWS architecture. Any time a service, application, or external identity needs to act in AWS, it should use a role β€” not an IAM user with hardcoded keys.

A role has two policy layers that must both allow the interaction:

🀝

Trust Policy β€” "Who Can Assume Me?"

Defines which principal is allowed to call sts:AssumeRole on this role. Without trust, nobody can use the role.

  • AWS services: "Service": "ec2.amazonaws.com"
  • Another AWS account: "AWS": "arn:aws:iam::123456789:root"
  • Federated identity: "Federated": "cognito-identity.amazonaws.com"
  • Specific IAM user: "AWS": "arn:aws:iam::123:user/alice"
  • This is a resource-based policy on the role itself
πŸ“œ

Permission Policy β€” "What Can This Role Do?"

Standard IAM policies defining what actions the role can perform. Evaluated after AssumeRole succeeds.

  • Identical structure to user/group policies
  • Can attach multiple managed + inline policies
  • Defines the scope of temporary credential permissions
  • Can also be limited further by session policies at assume time
  • Best practice: scope tightly to only what the service needs
Role Assumption Flow β€” Step by Step Deep Dive
  1. Principal requests temporary credentials
    An EC2 instance (or AWS service, user, or external identity) calls sts:AssumeRole with the role ARN. If it's an EC2 instance with an instance profile, this happens automatically β€” the EC2 metadata service handles it transparently for the SDK.
  2. STS validates the Trust Policy
    AWS Security Token Service (STS) checks the role's Trust Policy. Is the requesting principal listed as a trusted entity? If not β†’ denied. If yes β†’ proceed. Conditions in the trust policy are also evaluated (e.g., require MFA, require specific ExternalId for cross-account).
  3. STS issues temporary credentials
    STS returns three values: AccessKeyId, SecretAccessKey, and SessionToken. These expire after the configured duration (default 1 hour, max 12 hours for most roles). The caller must use all three together β€” the session token proves the credentials are temporary.
  4. Caller uses temporary credentials
    The caller signs requests with the temporary creds. AWS IAM validates the session token and evaluates the role's permission policies. The original caller's identity is not used β€” they are now acting AS the role. All CloudTrail logs show the role ARN + the original principal (AssumedRoleUser).
  5. Credentials expire β€” automatically revoked
    When the TTL expires, the credentials become invalid. No manual cleanup needed. If the role's policies change, new sessions get new permissions. To revoke active sessions before expiry: use Revoke Sessions in the IAM console (adds an explicit deny policy with a time condition) or update the permission policy.
Common Role Types & When to Use Them Core
Role TypeTrust PrincipalUse CaseExam Keyword
Service Role AWS service (ec2, lambda, ecs…) EC2 accessing S3, Lambda writing to DynamoDB, ECS pulling from ECR "EC2 instance profile", "execution role"
Cross-Account Role Another AWS account ID Production access from dev account, central logging account, shared services "cross-account access", "ExternalId"
Federated Role Identity provider (SAML, OIDC) Corporate SSO, GitHub Actions CI/CD, Cognito web app login "web identity federation", "SAML 2.0", "OIDC"
Service-Linked Role Specific AWS service (managed by AWS) Auto-created by services like EKS, RDS, ElastiCache β€” you don't manage trust "AWSServiceRoleFor…", cannot delete if service uses it
Instance Profile ec2.amazonaws.com Container for a service role that gets attached to an EC2 instance. Not a separate IAM entity type β€” a wrapper that links a role to EC2. "instance profile", "IMDS metadata"
⚑ Instance Profile vs Role β€” The Exam Trap

An EC2 instance cannot directly use an IAM Role. The role must be wrapped in an Instance Profile and the instance profile is attached to the EC2 instance. The AWS Console does this automatically, so most people never see the distinction. But the exam knows: iam:CreateInstanceProfile is a separate permission from iam:CreateRole. The SDK reads credentials from the EC2 Instance Metadata Service (IMDS) at http://169.254.169.254/latest/meta-data/iam/security-credentials/.

Diagram 4 β€” Concept: IAM Entity Hierarchy & Relationships Introductory
Concept Diagram β€” How Users, Groups, Roles, and Policies Connect
🚫 ROOT ACCOUNT πŸ‘₯ GROUPS Admins Β· Developers DevOps Β· ReadOnly Not an identity πŸ‘€ USERS alice Β· bob Β· ci-bot Permanent identity Long-lived credentials 🎭 ROLES EC2-S3-Role Β· Lambda-DDB Temporary identity Auto-expiring creds πŸ“œ POLICIES JSON documents Effect Β· Action Resource Β· Condition member attached to 🀝 TRUST POLICY Who can assume this role? Service / User / App calls sts:AssumeRole STS β†’ Temp creds (15min–12hr) Users/Groups = permanent Β· Roles = temporary Β· Policies = permission rules attached to any identity
The four entities and their exact relationships. Policies are documents β€” they do nothing until attached. Groups cannot authenticate β€” only users can.
Users vs Roles β€” The Critical Design Decision Core
DimensionIAM UserIAM Role
Credential TypePermanent (password, access keys)Temporary (STS-issued, 15min–12hr)
ExpiryNever expire β€” must manually rotate/deleteAutomatically expire β€” self-cleaning
Leak RiskHigh β€” if key leaks, attacker has persistent accessLow β€” leaked temp creds expire automatically
For AWS Services❌ Anti-pattern β€” hardcoding keys in codeβœ… Correct β€” instance profiles, execution roles
For CI/CD⚠️ Avoid β€” storing keys in GitHub secretsβœ… Use OIDC role assumption (keyless)
For Humansβœ… OK for console access with MFAβœ… Better with IAM Identity Center + federation
Cross-Account❌ Must share credentials across account boundaryβœ… Assume role from other account β€” clean separation
Audit TrailLogs show usernameLogs show role ARN + original principal (AssumedRoleUser)
Best PracticeUse for: console admins, break-glass, legacy apps onlyUse for: everything else β€” services, CI/CD, cross-account, federation
Diagram 5 β€” AWS: Core Entities in Action Core
AWS Diagram β€” Users/Groups/Roles/Policies Working Together
AWS ACCOUNT AWS IAM πŸ‘₯ Developers Group πŸ‘€ alice πŸ‘€ bob πŸ“œ DeveloperAccess policy Inherits policy on group attach πŸ‘€ User: ci-bot πŸ“œ Inline policy (CI-specific) Access key β†’ expires manually 🎭 EC2-App-Role Trust: ec2.amazonaws.com πŸ“œ S3ReadOnly policy STS β†’ temp creds to instance πŸ”‘ STS Issues temporary credentials AccessKey Β· SecretKey Β· Token EC2 Instance Assumes EC2-App-Role via Instance Profile SDK reads from IMDS auto Lambda Function Uses Execution Role Trust: lambda.amazonaws.com STS auto-injected S3 Bucket Resource-based bucket policy defines who can access regardless of identity policies AssumeRole temp creds β†’ access
Users authenticate through IAM. Roles are assumed via STS. Services (EC2, Lambda) use roles automatically β€” never hardcoded keys.
Diagram 6 β€” Architecture: Real-World Team & Service Structure Professional
Architecture Diagram β€” Users in Groups + Service Roles + Cross-Account
PRODUCTION ACCOUNT (111111111) πŸ‘₯ DevOps alice Β· bob πŸ“œ EC2FullAccess πŸ“œ LambdaDeploy MFA required πŸ‘₯ DataTeam carol Β· dave πŸ“œ S3ReadOnly πŸ“œ AthenaReadOnly IP condition (VPN only) 🎭 EC2-App-Role Trust: ec2.amazonaws.com πŸ“œ S3:GetObject logs/* πŸ“œ Secrets:GetSecret Least privilege scoped 🎭 Lambda-Role Trust: lambda.amazonaws.com πŸ“œ DDB:PutItem orders πŸ“œ CloudWatch:PutLogs Nothing else allowed IAM Policy Evaluation β€” Deny by default Β· Evaluate all applicable policies Β· Explicit Allow required Every API call checked: identity-based + resource-based + SCPs + permission boundaries EC2 DevOps: Full Others: None S3 DataTeam: Read EC2Role: Write logs Lambda DevOps: Deploy Role: Execute DynamoDB Lambda: Read+Write Others: None Secrets Mgr EC2Role: Get secret Others: None DEV ACCOUNT (222222222) β€” Cross-Account Role Assumption πŸ‘€ Dev Team Users Call sts:AssumeRole with role ARN from Production Account 🎭 CrossAccountDeployRole Trust: arn:aws:iam::222222222:root πŸ“œ Deploy permissions (prod) ← Both accounts must trust each other for cross-account to work
Two-account setup: production resources protected by groups + service roles. Dev team crosses account boundary using role assumption.
πŸ“‹ Chapter 02 Summary β€” Core Components
  • 4 IAM entities: Users (permanent people), Groups (user collections), Roles (temp identities), Policies (permission docs).
  • Root account β€” unrestricted, cannot be IAM-restricted. Use only for account-level tasks. Lock with MFA + offsite storage.
  • Users have two credential types: console password AND/OR programmatic access keys. Keys never auto-expire.
  • Groups are NOT identities β€” they cannot log in, cannot assume roles. Only a tool for organizing users and sharing policies.
  • Roles are the correct approach for services β€” EC2, Lambda, ECS, EKS all use roles. Never hardcode access keys in code.
  • Roles have two policy layers: Trust Policy (who can assume) + Permission Policy (what they can do). Both must allow.
  • STS issues temporary credentials (AccessKey + SecretKey + SessionToken). All three required. Expire automatically.
  • Instance Profile β€” not a separate entity, it's a container that wraps a role for attachment to EC2. SDK reads auto from IMDS.
  • Cross-account access β€” both accounts must trust each other: role's trust policy must allow the external account, and the user in the external account must have sts:AssumeRole permission.
  • Access key rotation β€” create new β†’ update apps β†’ verify β†’ deactivate old β†’ delete old. Max 2 keys per user for zero-downtime.
Chapter 02 β€” The Core Principle

Roles over Users, always, for machine-to-machine access. Long-lived access keys are a security liability β€” temporary credentials expire by design. Build everything on roles and you eliminate an entire class of credential leak vulnerabilities.

πŸŽ“ Exam Tips β€” Chapter 02: Core Components
  • EC2 uses Instance Profile (not "attach a role directly"). One instance profile per EC2 at a time. Profile wraps a role.
  • Groups cannot assume roles β€” only users, services, or other roles can assume roles.
  • Cross-account role assumption β€” needs trust policy on the role (allows external account) AND permission on the caller (sts:AssumeRole).
  • STS session = 3 values: AccessKeyId + SecretAccessKey + SessionToken. All three required to sign API calls.
  • Service-Linked Role β€” AWS creates/manages it. Tied to specific service. Cannot delete while service uses it.
  • Root-only actions β€” closing account, restoring IAM admin lockout, changing account email. No root = blocked.
  • Users in multiple groups β€” inherits ALL policies from all groups. Policies are additive (except explicit Deny wins).
  • Max access keys per user = 2 β€” designed for zero-downtime rotation, not for sharing with 2 apps.
03
Chapter Three

Policies Deep Dive β€” The Language of Permissions

What is an IAM Policy? Introductory

An IAM policy is a JSON document that defines permissions. It specifies what actions are allowed or denied, on what resources, under what conditions. Policies are the fundamental unit of authorization in AWS β€” without a policy granting access, nothing is allowed.

⚑ The Key Rule

Policies are inert by themselves. A policy document sitting in IAM does nothing until it is attached to an identity (user, group, role) or a resource (S3 bucket, KMS key, Lambda function). A policy attached to a user defines what that user can do. A policy attached to an S3 bucket defines who can access that bucket β€” regardless of their identity policies.

Policy JSON Anatomy β€” Every Field Explained Core

A policy document contains a Version and a list of Statement objects. Each statement is one permission rule:

πŸ“‹ Sample Policy β€” S3 Read with Conditions

{ "Version": "2012-10-17", "Statement": [ { "Sid": "AllowS3ReadWithMFA", "Effect": "Allow", "Action": [ "s3:GetObject", "s3:ListBucket" ], "Resource": [ "arn:aws:s3:::my-data-bucket", "arn:aws:s3:::my-data-bucket/*" ], "Condition": { "Bool": { "aws:MultiFactorAuthPresent": "true" }, "IpAddress": { "aws:SourceIp": "203.0.113.0/24" } } } ] }

Version
Always "2012-10-17". This is not the date you created the policy β€” it's the policy language version. Using an older version "2008-10-17" disables policy variables like ${aws:username}. Always use 2012-10-17.
Statement (array)
A list of individual permission rules. One policy can have many statements. All statements are evaluated together. Multiple statements are OR'd together for Allow, but any explicit Deny anywhere wins.
Sid (optional)
Statement ID β€” a human-readable label for the statement. Useful for documentation and programmatic management. Must be unique within a policy. Has no effect on evaluation.
Effect
"Allow" or "Deny". The only two options. An explicit Deny overrides any Allow β€” including from other policies. This is the most powerful type of statement in IAM.
Action
What API call(s) to allow/deny. Format: service:ApiName. Examples: s3:GetObject, ec2:StartInstances, iam:CreateUser. Use * or s3:* for wildcards. Actions are case-insensitive.
Resource
Which AWS resource(s) the statement applies to. Always an ARN or *. For S3 buckets, you often need both the bucket ARN AND the bucket/* ARN together. Some actions are not resource-specific and require "Resource": "*" (e.g., iam:ListUsers).
Principal (resource-based only)
WHO this statement applies to. Only used in resource-based policies (S3 bucket policies, KMS key policies, trust policies). Not present in identity-based policies. Can be: AWS account, IAM user, IAM role, AWS service, anonymous (*).
Condition (optional)
When this rule applies. Key-value pairs of condition operators and context keys. Multiple conditions in one block are AND'd. Multiple values for one key are OR'd. Common keys: aws:SourceIp, aws:MultiFactorAuthPresent, aws:RequestedRegion, s3:prefix, aws:CurrentTime.
Policy Types β€” The Six Types You Must Know Core
πŸ‘€

Identity-Based Policies

  • Attached to a User, Group, or Role
  • Defines what that identity is allowed/denied to do
  • Most common type β€” 90% of IAM policies are identity-based
  • Can be Managed (reusable) or Inline (embedded)
  • Example: Allow developer to ec2:Describe* on all resources
  • No Principal field β€” it's implied by who it's attached to
πŸ—‚οΈ

Resource-Based Policies

  • Attached to the AWS resource itself (S3 bucket, KMS key, Lambda, SQS, SNS)
  • Always inline β€” cannot be managed or reused
  • Has a Principal field β€” defines who the policy applies to
  • Allows cross-account access without role assumption (for supported services)
  • Example: S3 bucket policy granting another account read access
  • Evaluated in addition to identity-based policies, not instead
🏒

Service Control Policies (SCPs)

  • AWS Organizations feature β€” apply to OUs or entire accounts
  • Not standalone permissions β€” they restrict what identity-based policies can allow
  • SCPs cannot grant permissions, only limit them
  • Applied before identity-based policies β€” SCP must allow + identity must allow for access
  • Do NOT apply to root user of management account
  • Example: Prevent any action outside approved regions across all accounts
πŸ”’

Permission Boundaries

  • Set maximum permissions a user or role can ever have
  • Identity MUST have permission in both boundary AND identity policy
  • Intersection: boundary ∩ identity policy = effective permissions
  • Used to delegate permission management safely (developers create roles but can't exceed boundary)
  • Not a grant β€” does not give permissions by itself
  • Example: Allow devs to create roles, but those roles can never exceed S3FullAccess
βš™οΈ

Session Policies

  • Passed inline during sts:AssumeRole or sts:GetFederationToken
  • Further restricts what the session can do (cannot expand role permissions)
  • Intersection: session policy ∩ role policy = effective session permissions
  • Useful: give a role broad permissions but restrict specific sessions to narrow tasks
  • Example: CI/CD job assumes a deploy role but session policy limits to one Lambda only
πŸ“Œ

IAM Access Control Tags (ABAC)

  • Attribute-Based Access Control β€” use AWS tags in conditions
  • Grant access based on matching tags between user and resource
  • Example: dev can access any EC2 instance tagged Env=dev if their user also has that tag
  • Scales better than RBAC for large teams
  • Key: aws:ResourceTag/key, aws:PrincipalTag/key
Managed Policies vs Inline Policies Core
DimensionAWS Managed PolicyCustomer Managed PolicyInline Policy
Created byAWS β€” pre-built, maintained by AWSYou β€” custom JSON, your ownershipYou β€” embedded in one identity
ReusabilityAttach to multiple users/roles/groupsAttach to multiple identitiesOne-to-one β€” single identity only
VersioningAWS updates automatically (no control)You manage up to 5 versionsNo versioning β€” edit in place
VisibilityVisible in all accountsVisible in your account onlyPart of the identity β€” not separate
DeletionCan't delete β€” only detachDeletes independently; detaches from allDeleted when its identity is deleted
Exam keyword"AWS managed" β€” AdministratorAccess, ReadOnlyAccess"customer managed" β€” your org's policies"inline" β€” strict 1:1 relationship
Best forCommon access patterns (Admin, PowerUser, ReadOnly)Custom org-specific permissions at scaleSpecial case β€” strict 1:1 binding, unusual
Identity-Based vs Resource-Based β€” Cross-Account Impact Deep Dive

When a principal in Account A tries to access a resource in Account B, the interaction of policy types determines access. This is where most cross-account errors happen:

Same Account Access

Identity policy OR resource policy is enough.

If Alice has an identity policy allowing s3:GetObject on bucket B, she can access it β€” even if bucket B has no bucket policy.

If bucket B's policy allows Alice, she can access it β€” even if Alice has no identity policy for S3.

Either side granting access = allowed (assuming no explicit deny anywhere).

Cross-Account Access

BOTH identity policy AND resource policy must allow.

If Alice in Account A wants bucket B in Account B:

  • Bucket B's policy must explicitly allow Account A's principal (or the whole account)
  • AND Alice's identity policy in Account A must allow s3:GetObject

One side alone is not enough. Both must explicitly allow. This prevents Account B from being accessed just because Account A's admin allows it.

Policy Conditions β€” Precise Access Control Deep Dive

Conditions are the most powerful (and most underused) part of IAM policies. They allow context-aware permissions β€” the same identity can have different effective access depending on how and where they connect.

Condition KeyWhat it checksExample Use
aws:SourceIpClient IP address of the requestRestrict S3 access to corporate network only
aws:MultiFactorAuthPresentWhether MFA was used for this sessionRequire MFA to delete critical resources
aws:RequestedRegionRegion where the API call was madePrevent creating resources outside approved regions
aws:PrincipalTag/keyTags on the requesting identityABAC: devs can only access their team's resources
aws:ResourceTag/keyTags on the target resourceABAC: team members access only matching-tagged resources
aws:CalledViaService that made the call on behalf of a principalAllow only CloudFormation to call DynamoDB (not direct user)
s3:prefixS3 object key prefixRestrict access to team/alice/ folder only
iam:PassedToServiceService a role is being passed toPrevent passing powerful roles to wrong services
aws:SecureTransportWhether HTTPS was usedDeny all S3 requests over HTTP (enforce encryption in transit)
aws:SourceVpc / aws:SourceVpceRequest came from specific VPC or VPC EndpointS3 bucket accessible only from within your VPC
NotAction and NotResource β€” The Exam Traps Deep Dive

NotAction and NotResource are powerful but dangerous keywords. They are often in exam questions because they behave counterintuitively.

⚠️

NotAction β€” "Everything EXCEPT these actions"

Allow with NotAction = allow everything EXCEPT listed actions.

  • "Effect": "Allow", "NotAction": ["iam:*", "organizations:*"], "Resource": "*"
  • This allows ALL AWS actions EXCEPT IAM and Organizations
  • Commonly used to grant full access except dangerous IAM/billing actions
  • Exam trap: Deny with NotAction = deny everything EXCEPT listed actions (i.e., allow only those actions)
  • Not the same as "deny these actions" β€” only affects what falls outside the NotAction list
⚠️

NotResource β€” "Everything EXCEPT this resource"

Allow with NotResource = allow actions on everything EXCEPT listed resources.

  • "Effect": "Allow", "Action": "s3:*", "NotResource": "arn:aws:s3:::prod-bucket/*"
  • Allows all S3 actions on EVERY bucket EXCEPT prod-bucket
  • Use when you want to broadly grant but protect specific sensitive resources
  • Exam trap: This does NOT deny access to prod-bucket β€” it just doesn't grant S3:* there. A separate Allow for prod-bucket could still exist.
  • To truly protect: add an explicit Deny for prod-bucket
Diagram 7 β€” Concept: Policy JSON Anatomy Introductory
Concept Diagram β€” Anatomy of an IAM Policy Statement
IAM POLICY DOCUMENT Version "2012-10-17" ← always this value Statement[ ... ] ← array of rules Single Statement Object Sid "MyRule123" β€” label (optional) Effect "Allow" | "Deny" ← REQUIRED Action ["s3:GetObject", "s3:ListBucket"] Resource "arn:aws:s3:::bucket" "arn:aws:s3:::bucket/*" Condition (optional) {"Bool": {"aws:MultiFactorAuthPresent": "true"}, "IpAddress": {"aws:SourceIp": "10.0.0.0/8"}} Multiple conditions in same block = AND Β· Multiple values in one key = OR always 2012-10-17 Deny wins over Allow
Every IAM action is controlled by these fields. Version is always 2012-10-17. Effect determines Allow/Deny. Condition adds context-aware rules.
Diagram 8 β€” AWS: Policy Types & Where They Live Core
AWS Diagram β€” The Six Policy Types and Their Attachment Points
AWS Organizations (OU / Account) πŸ“œ SCP β€” limits maximum allowed actions AWS IAM Evaluates ALL applicable policies together IDENTITY SIDE πŸ“œ Identity-Based Policy πŸ”’ Permission Boundary βš™οΈ Session Policy (at assume) Attached to: User / Group / Role No Principal field RESOURCE SIDE πŸ—‚οΈ Resource-Based Policy Attached to: S3 bucket, KMS key, Lambda, SQS, SNS, trust policy HAS Principal field Always inline (not managed) EVALUATION ORDER 1. Explicit DENY anywhere? β†’ DENY 2. SCP allows? β†’ must pass 3. Boundary + identity + resource β†’ allow? ❌ 403 Denied βœ… Allowed no allow all pass
IAM evaluates all applicable policy types together. SCP filters first, then identity + resource policies determine final access.
Diagram 9 β€” Architecture: Multiple Policy Types in Action Professional
Architecture Diagram β€” SCP + Permission Boundary + Identity + Resource Policies Together
AWS ORGANIZATIONS β€” SCP: DenyChinaRegions + DenyIAMWrite (applied to all accounts) AWS ACCOUNT 123456789 PERMISSION BOUNDARY: S3FullAccess + LambdaBasicExecution (max ceiling for dev-created roles) πŸ‘€ Dev User: alice πŸ“œ Identity Policy: S3:* on dev-bucket/* Lambda:InvokeFunction EC2:Describe* (view only) Effective = Identity ∩ Boundary ∩ SCP (intersection of all three) ❌ EC2 blocked by boundary ceiling 🎭 Lambda-ProcessRole Trust: lambda.amazonaws.com πŸ“œ Permission Policy: S3:GetObject dev-bucket/* DDB:PutItem orders-table Logs:CreateLogGroup Created by alice (bounded by LambdaBasicExecution max) IAM EVALUATION: SCP ∩ Boundary ∩ Identity-Policy ∩ Resource-Policy = Final Decision Explicit Deny anywhere stops evaluation. If any layer blocks it β€” DENIED. S3: dev-bucket Bucket Policy: Allow alice + Lambda βœ… alice can S3:* (all layers pass) DynamoDB: orders No resource policy Lambda role allows PutItem βœ… Lambda: allowed (identity policy) Lambda Resource policy: alice invoke allowed βœ… alice: identity + resource pass EC2 Instances alice: Describe* in identity policy BUT ❌ Boundary blocks EC2 access
Real org setup: SCP limits whole account β†’ Boundary limits what devs can create β†’ Identity policy defines specific permissions β†’ Resource policy can also contribute. They all intersect.
AWS Global Condition Context Keys In-Depth

These condition keys are available in every AWS policy regardless of service. They appear constantly on AWS certification exams.

KeyWhat It ChecksExam Scenario
aws:SourceIpClient IP address"Restrict API access to corporate network"
aws:MultiFactorAuthPresentMFA active in session"Require MFA to delete S3 objects"
aws:RequestedRegionRegion of the API call"Prevent resource creation outside us-east-1"
aws:PrincipalOrgIDAWS Organization ID"Only allow access from my organization"
aws:PrincipalTag/<key>Tags on the calling identity"Developer can access only their team's resources"
aws:ResourceTag/<key>Tags on the target resource"Only allow access to resources tagged Env=dev"
aws:CurrentTimeCurrent timestamp"Allow access only during business hours"
aws:SourceVpcVPC ID of the request"S3 bucket accessible only from specific VPC"
aws:SourceVpceVPC endpoint ID"Restrict access to traffic through a specific endpoint"
aws:CalledViaService that made the call on behalf of principal"Allow only if called via CloudFormation"
Exam Tip

When a question says "restrict access to only…" β€” think Condition block + the appropriate global key.

SCP β€” Allow List Strategy In-Depth

SCPs are typically used as deny lists (deny specific actions). But the allow list strategy is more restrictive and is a common exam pattern:

SCP β€” Allow List (Whitelist)

{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Action": [
      "s3:Get*",
      "s3:List*",
      "cloudwatch:Get*",
      "cloudwatch:List*"
    ],
    "Resource": "*"
  }]
}

With only this Allow statement in the SCP, all other actions are implicitly denied β€” even ec2:DescribeInstances. This locks accounts to an exact set of services.

Deny List (Default)

Start with AWS default FullAWSAccess SCP, then add explicit denies for what you want to block.

Use when: You want broad access with specific restrictions.

Allow List (Restrictive)

Remove the default SCP, then explicitly allow only the services you want.

Use when: You want strict control β€” sandbox or compliance-locked accounts.

Exam Pattern

"SCP restricts account to only read S3 and CloudWatch" β†’ Allow list SCP, not deny list.

Permission Boundary β€” Delegated Admin Pattern In-Depth

The most common real-world use case for permission boundaries:

Scenario: Safe IAM Delegation

You want junior developers to create IAM roles for their Lambda functions, but you don't want them to accidentally create admin roles.

Solution:

  • Create a boundary policy that limits max permissions to LambdaBasicExecution + S3ReadOnly
  • Give developers iam:CreateRole + iam:AttachRolePolicy in their identity policy
  • Require them to attach the boundary when creating roles: iam:CreateRole with condition iam:PermissionsBoundary = arn:aws:iam::...:policy/DevBoundary
  • Result: They can create roles, but no role they create can exceed the boundary ceiling
Exam Keyword

"Delegate IAM role creation safely" or "prevent privilege escalation" β†’ Permission Boundary.

IAM Policy Simulator Core

What It Does

  • Test IAM policies before deploying them
  • Enter user/role ARN, actions, and resources
  • Shows allow/deny and explains WHY
  • Tests against all attached policies + boundaries

When to Use

  • Debugging "AccessDenied" errors
  • Testing condition logic
  • Understanding evaluation order
  • Validating least-privilege policies before rollout

Access: https://policysim.aws.amazon.com β€” separate from the main AWS Console.

πŸ“‹ Chapter 03 Summary β€” Policies Deep Dive
  • Policy = JSON document with Version, Statement (array of: Sid, Effect, Action, Resource, Condition). Version is always 2012-10-17.
  • Effect is Allow or Deny β€” explicit Deny always wins over any Allow from any policy.
  • 6 policy types: Identity-based Β· Resource-based Β· SCPs Β· Permission Boundaries Β· Session Policies Β· ABAC tags.
  • Identity-based β€” attached to user/group/role, no Principal field. Most common type.
  • Resource-based β€” attached to resource, HAS Principal field, always inline, enables cross-account access without role assumption (for S3, KMS, Lambda, SQS, SNS).
  • SCPs β€” Organizations-level, cannot grant permissions, only restrict. Do not apply to root of management account.
  • Permission Boundaries β€” set maximum permissions ceiling. Identity MUST have the action in BOTH boundary AND identity policy (intersection).
  • Managed vs Inline: AWS managed (AWS maintains), Customer managed (you own, reusable), Inline (1:1 binding, cannot reuse).
  • Same-account: either identity OR resource policy can grant access. Cross-account: BOTH must allow.
  • NotAction β€” allow everything EXCEPT listed actions. NotResource β€” allow actions on everything EXCEPT listed resources. High exam frequency.
  • Conditions β€” context-aware rules. Multiple in same block = AND. Multiple values = OR. Key exam condition keys: aws:MultiFactorAuthPresent, aws:SourceIp, aws:RequestedRegion.
Chapter 03 β€” The Core Principle

Policies are not just Allow/Deny lists β€” they are contextual, layered, and intersecting. Add conditions to make permissions context-aware. Layer SCPs, boundaries, and identity policies to build defense-in-depth. An explicit Deny is absolute β€” it cannot be overridden by any Allow, anywhere.

πŸŽ“ Exam Tips β€” Chapter 03: Policies Deep Dive
  • Version must be 2012-10-17 β€” older version disables policy variables. Always use this.
  • Explicit Deny always wins β€” regardless of how many Allows exist in other policies. One Deny = blocked.
  • Cross-account = both policies must allow β€” identity policy in requester's account + resource policy in target account.
  • SCP cannot grant, only restrict β€” even AdministratorAccess user in an OU with restrictive SCP cannot exceed the SCP.
  • Permission boundary β‰  grant β€” it's a ceiling, not a floor. Identity policy still needs to explicitly allow.
  • Resource-based policy has Principal field β€” identity-based does not. Resource-based = always inline.
  • NotAction with Allow = allow everything EXCEPT listed. Very common exam scenario. Different from "Deny these actions."
  • S3 bucket needs BOTH bucket ARN and bucket/* ARN β€” s3:ListBucket applies to the bucket, s3:GetObject applies to objects (bucket/*).
  • Condition evaluation: multiple conditions = AND. Multiple values in one condition = OR.
04
Chapter Four

Roles & Trust Relationships

Why Roles Exist Introductory

IAM Users solve human access. IAM Roles solve everything else: service-to-service access, temporary elevated access, federation, and cross-account operations. A role is an identity you become temporarily - not one you permanently own.

🎭

Role = Temporary Identity

  • No permanent password and no long-lived access key pair
  • Assumed via STS to get temporary credentials
  • Credentials auto-expire (15 min to 12 hours)
  • Used by AWS services, users, external IdPs, and other accounts
  • Reduces key leakage risk dramatically
🀝

Trust Relationship = Entry Gate

  • Defines who is allowed to assume the role
  • Implemented as the role's trust policy
  • Without trust, assume-role request is denied immediately
  • Can restrict assumption with conditions (MFA, ExternalId, source account)
  • Permission policy is checked only after trust is passed
Key Formula

A role can be used only when Trust Policy allows assumption AND Permission Policy allows the action. Trust decides who can become the role. Permission decides what that role can do after assumption.

Role Anatomy: 2 Policies, 1 Session Core
ComponentQuestion it AnswersWhere it LivesCommon Misunderstanding
Trust Policy "Who can assume this role?" On the role itself (resource-based policy) People think this grants resource access. It does not.
Permission Policy "What can this role do after assumption?" Attached to role (identity-based policy) People think this controls who can assume. It does not.
STS Session "What temporary credentials are issued?" Generated by STS on assume-role People forget SessionToken is mandatory.
Session Policy (optional) "Further restrict this one session?" Passed at assume time People assume it can expand role permissions. It cannot.
Diagram 10 β€” Concept: Role Assumption Decision Path Introductory
Concept Diagram - Caller -> Trust Check -> STS Session -> Permission Evaluation
CALLER User / Service or External IdP AssumeRole TRUST POLICY CHECK Principal allowed? Conditions pass? (MFA / ExternalId / etc) STS ISSUES Temp Credentials ASSUME DENIED No session created IAM Role Permission Policy Eval Only after trust succeeds does permission evaluation begin. Temporary credentials include AccessKey, SecretKey, and SessionToken.
Trust Policy Patterns Core
βš™οΈ

Service Trust

  • Principal: AWS service
  • Example: EC2, Lambda, ECS, API Gateway
  • Used by service roles and execution roles
  • Most common pattern in production
🏒

Cross-Account Trust

  • Principal: external AWS account or role ARN
  • Use ExternalId to prevent confused deputy risk
  • Common for shared services and central security accounts
  • Requires caller-side sts:AssumeRole permission too
🌐

Federation Trust

  • Principal: SAML or OIDC provider
  • Used by IAM Identity Center and CI/CD OIDC flows
  • Session duration and audience restrictions are critical
  • No long-lived IAM user keys required
Diagram 11 β€” AWS: Service Roles, Execution Roles, and Cross-Account Role Core
AWS Diagram - Trust Relationship Examples with Services
AWS ACCOUNT IAM ROLE LAYER EC2-APP-ROLE Trust: ec2.amazonaws.com Perm: s3:GetObject logs/* Perm: kms:Decrypt key/app Identity: Role LAMBDA-EXECUTION-ROLE Trust: lambda.amazonaws.com Perm: dynamodb:PutItem orders Perm: logs:PutLogEvents Identity: Role CROSS-ACCOUNT-OPS-ROLE Trust: arn:aws:iam::2222:role/CICD Condition: ExternalId required Perm: cloudformation:Deploy Identity: Role EC2 in VPC Assumes EC2-APP-ROLE via instance profile Gets STS temp creds automatically No hardcoded keys Lambda + API Gateway Function runs using execution role Role permissions control downstream access Policy-scoped DynamoDB writes Deployer in External Account Assumes CROSS-ACCOUNT-OPS-ROLE ExternalId + trust policy must pass Temporary deployment session Identity = role, Policy = permissions, Trust = who may assume, STS = temporary credentials.
Temporary Credentials Deep Dive Deep Dive
  1. Caller requests role assumption
    Caller invokes STS API such as AssumeRole, AssumeRoleWithSAML, or AssumeRoleWithWebIdentity.
  2. Trust policy evaluated first
    If caller principal and conditions do not match trust policy, request fails immediately and no credentials are issued.
  3. STS returns credential triplet
    Session credentials include AccessKeyId, SecretAccessKey, and SessionToken, plus expiration timestamp.
  4. APIs execute with role identity
    Requests are signed with temporary credentials. IAM evaluates role permissions (and other policy layers) for every API action.
  5. Session expires automatically
    After TTL, credentials are invalid by design. This is why roles are safer than long-lived user keys.
Role Types and Real Usage Core
Role TypeTrusted PrincipalTypical PermissionsReal Scenario
EC2 Service Role ec2.amazonaws.com S3 read, Secrets Manager read, CloudWatch put logs Web app on EC2 reads config secrets and writes app logs
Lambda Execution Role lambda.amazonaws.com DynamoDB write, SQS send, CloudWatch logs Serverless API writes orders to DynamoDB
ECS Task Role ecs-tasks.amazonaws.com S3 read, KMS decrypt, X-Ray tracing Containerized microservice accesses encrypted payloads
Cross-Account Ops Role External account or specific role ARN Deploy/update resources in target account Central CI/CD account deploys to production account
Federated Workforce Role SAML/OIDC provider Console and API rights based on job function Corporate SSO users assume admin/read-only roles
Diagram 12 β€” Architecture: Cross-Account Deployment with Guardrails Professional
Architecture Diagram - CI/CD Account Assuming Deployment Role in Prod Account
CI/CD ACCOUNT (222222222) PRODUCTION ACCOUNT (111111111) OIDC PRINCIPAL (GitHub / GitLab / IdP) Assumes CICD-ROLE in CI account (no static keys) Session is short-lived and job-scoped Identity CICD-ROLE (SOURCE) Perm: sts:AssumeRole on target deploy role Condition: repo, branch, and audience checks Policy Resource target: Deploy role ARN sts:AssumeRole PROD-DEPLOY-ROLE (TARGET) Trust: source CICD role ARN + ExternalId Perm: CloudFormation deploy + Lambda update Identity + Policy Resource target: production stack PRODUCTION RESOURCES Updated only through assumed deploy role Resource Least privilege deployment actions DENY PATH (Trust or Condition fails) No session issued. Deployment blocked before any API action. Cross-account role usage is secure when trust policy, caller permissions, and guardrail conditions all align.
Cross-Account Role Assumption β€” Complete Prerequisites In-Depth

Both sides must be configured correctly. Missing either side = AccessDenied.

SideRequirementExample
Source Account (Caller)Identity policy allowing sts:AssumeRole on the target role ARN"Action": "sts:AssumeRole", "Resource": "arn:aws:iam::111111111111:role/TargetRole"
Target Account (Role Owner)Trust policy allowing source account principal"Principal": { "AWS": "arn:aws:iam::222222222222:root" }
Both (Optional)Conditions: MFA, ExternalId, time, source IP"Condition": { "StringEquals": { "sts:ExternalId": "abc123" } }
πŸ”‘

Source Must Have

sts:AssumeRole permission pointing at the target role ARN

🀝

Target Must Trust

Trust policy listing the source account/role/user as Principal

πŸ›‘οΈ

Guardrails Apply

SCPs on both accounts can block the assumption even if policies allow it

Exam Pattern

"Cross-account access denied" β†’ Check: (1) Caller has sts:AssumeRole, (2) Trust policy lists caller, (3) No SCP blocking on either side.

Chapter 04 Summary β€” Roles & Trust Relationships
  • Role = temporary identity, not permanent credentials. STS issues short-lived sessions.
  • Trust policy controls who may assume a role. Permission policy controls what assumed role may do.
  • Assume-role succeeds only when trust passes; then normal authorization evaluation starts.
  • Service roles and execution roles are the standard pattern for EC2, Lambda, and other AWS services.
  • Cross-account roles require both sides: caller permission to assume + target role trust allowing caller.
  • Temporary credentials always include SessionToken and expire automatically.
  • Use conditions in trust policies (MFA, ExternalId, audience, source constraints) as security guardrails.
  • Prefer roles over long-lived user access keys for services and CI/CD.
Exam Tips β€” Chapter 04
  • Trust policy answers "who can assume"; permission policy answers "what can be done."
  • EC2 uses instance profile to supply role credentials; Lambda uses execution role automatically.
  • Cross-account assume role needs caller-side sts:AssumeRole and target-side trust allow.
  • ExternalId in trust policy mitigates confused deputy in third-party access scenarios.
  • Session policies can only reduce role permissions, never expand them.
  • Missing SessionToken with temporary creds causes auth failures even with correct key/secret.
05
Chapter Five

Permission Evaluation Logic

Why This Chapter is CRITICAL Deep Dive

Every AWS API call goes through IAM's permission evaluation engine. Understanding this decision logic is the single most important skill for IAM mastery. The exam tests it heavily. Misunderstanding one step leads to accidental over-permissioning or mysterious access denials.

The Golden Rule of IAM Evaluation

Explicit Deny ALWAYS wins. No combination of Allows from any policy type can override an explicit Deny statement anywhere. One Deny in any applicable policy = request denied, period.

The Complete Evaluation Flow Core

When an API request arrives, IAM evaluates it through this exact sequence. The order matters:

  1. Step 1: Start with implicit DENY
    Every request begins in DENY state. This is not a policy decision - it is the system default. Nothing is allowed until explicitly permitted. "Silence = Deny."
  2. Step 2: Evaluate all applicable policies
    IAM collects all policies that apply: identity-based, resource-based, SCPs, permission boundaries, and session policies. All are evaluated together - not sequentially.
  3. Step 3: Check for explicit DENY
    If ANY policy has an explicit Deny that matches the action, resource, and conditions - evaluation stops immediately. Result: DENIED. No further checks happen.
  4. Step 4: Check Organizations SCP (if applicable)
    If the account is in an AWS Organization, the SCP must allow the action. SCPs cannot grant access - they only filter. If SCP does not explicitly allow it, result: DENIED (implicit deny from SCP).
  5. Step 5: Check Permission Boundary (if set)
    If a permission boundary is attached to the identity, it must allow the action. Like SCPs, boundaries filter - they never grant. Not in boundary = DENIED.
  6. Step 6: Check Session Policy (if present)
    If session policies were passed during AssumeRole or GetFederationToken, the action must be in the session policy. If not = DENIED.
  7. Step 7: Check for explicit ALLOW
    Finally, check identity-based and/or resource-based policies for an Allow. Same-account: either one can grant. Cross-account: both must grant. If no Allow found = DENIED (implicit deny).
Diagram 13 β€” Concept: The Evaluation Flowchart Introductory
Concept Diagram - Permission Evaluation Decision Path
API REQUEST ARRIVES DEFAULT STATE: DENY EXPLICIT DENY ANYWHERE? YES DENIED NO SCP ALLOWS? NO DENIED YES PERM BOUNDARY ALLOWS? NO DENIED YES SESSION POLICY ALLOWS? NO DENIED YES EXPLICIT ALLOW FOUND? NO DENIED YES ALLOWED
The ONLY path to ALLOWED is: no explicit deny + SCP allows + boundary allows + session allows + explicit allow found. Every other path is DENIED.
Same-Account vs Cross-Account Evaluation Deep Dive
Same-Account Access

Identity-based OR resource-based policy can grant.

  • If Alice's identity policy allows s3:GetObject on bucket B, she can access it even if the bucket has no bucket policy.
  • If bucket B's policy allows Alice, she can access even without an identity policy.
  • Either one granting = ALLOWED (assuming no explicit deny).

Union of permissions.

Cross-Account Access

Both identity-based AND resource-based MUST allow.

  • Account A caller needs identity policy granting the action.
  • Account B resource needs resource policy allowing Account A.
  • One side alone is NOT enough. Both must explicitly allow.

Intersection of permissions.

Exception: if caller uses a role in target account, only role permission policy applies (caller ID is now the role).

Effective Permissions Formula Professional
ScenarioEffective Permissions FormulaKey Insight
User with policies only Identity policies (union of all attached) All Allow statements across all policies merge additively.
User with permission boundary Identity policies INTERSECT boundary Only actions in BOTH the boundary AND identity policy are allowed.
User in Organization SCP INTERSECT identity policies SCP is a ceiling applied to all non-root identities in the account.
Role session with session policy Role policy INTERSECT session policy Session further restricts. Cannot expand beyond role permissions.
Full stack (Org + Boundary + Session) SCP INTERSECT Boundary INTERSECT Identity INTERSECT Session Tightest constraint wins. All layers must pass.
Cross-account S3 access (Source identity policy) INTERSECT (Bucket policy Principal allow) Both accounts must independently grant. Neither alone is enough.
Diagram 14 β€” AWS: Policy Layers in Permission Evaluation Core
AWS Diagram - Multiple Policy Layers Filtering Access
API REQUEST EXPLICIT DENY CHECK Any policy SCP FILTER Org ceiling PERM BOUNDARY Identity cap EXPLICIT ALLOW FOUND? Identity or resource OK Request passes through each filter in sequence. If ANY filter blocks = DENIED. Only the final "ALLOW" step is additive. All others are subtractive filters. Explicit Deny at any stage = immediate termination, no recovery. IAM evaluates all policies in parallel, not sequentially β€” this is a logical model.
Evaluation is a series of filters. Each filter can only block. Only the final Allow check can grant. Deny at any stage is final.
Diagram 15 β€” Architecture: Real Evaluation Across Org + Account + Identity Professional
Architecture Diagram - Full Stack Evaluation with SCP, Boundary, and Identity Layers
AWS ORG SCP: Allow ec2:*, s3:*, lambda:*, logs:* (DenyAllOutsideEU) PROD ACCOUNT Identity: alice Identity Policy: s3:*, ec2:* Boundary: S3FullAccess only Effective: s3:* only (boundary blocks ec2:*) SCP allows s3:* in EU - PASS SCP denies outside EU - BLOCK Role: LambdaExec Perm: dynamodb:PutItem, logs:* No boundary set Effective: dynamodb:PutItem, logs:* SCP allows (actions in list) No boundary = no extra filter FULL role permissions effective Deny Override SCP: Allow s3:* Identity: Allow s3:* Bucket policy: Deny s3:Delete* Result: s3:Delete* is DENIED (Explicit deny in resource policy overrides all identity Allows) IAM EVALUATION ENGINE Collects ALL applicable policies, checks Deny first, then filters, then Allow S3 in EU alice: ALLOWED (all pass) alice outside EU: DENIED (SCP) DynamoDB Lambda role: PutItem ALLOWED Lambda role: DeleteItem DENIED S3 Delete DENIED even with s3:* Allow Explicit Deny is absolute
Three different scenarios evaluated through the same engine with different outcomes based on SCP, boundary, and explicit deny.
Common Evaluation Traps Deep Dive
❌

Trap: "I have Allow so I'm good"

  • An Allow in identity policy means nothing if SCP does not allow it.
  • An Allow in identity means nothing if Boundary does not include it.
  • An Allow is overridden by any explicit Deny anywhere in any policy.
  • Allow is necessary but not sufficient without all layers passing.
❌

Trap: "No Deny means allowed"

  • Absence of Deny is NOT presence of Allow.
  • If no policy has an explicit Allow for the action, it stays in default DENY.
  • The system does not auto-allow if no deny exists. It auto-denies if no allow exists.
  • "Not denied" does NOT mean "allowed."
⚠️

Trap: "Deny on bucket policy blocks my admin"

  • A Deny on a bucket policy blocks even AdministratorAccess users.
  • Only root account user of the owning account can bypass resource policy deny.
  • Be careful with broad Deny statements in resource policies.
  • Resource-based Deny is as absolute as identity-based Deny.
⚠️

Trap: "Cross-account just needs bucket policy"

  • Bucket policy granting Account A is necessary but not sufficient.
  • Account A must also have identity policy allowing s3:GetObject.
  • Only exception: role assumption in the target account merges identity.
  • Both sides must explicitly allow for cross-account resource access.
Quick Decision Table β€” Policy Evaluation Scenarios In-Depth

Use this table to instantly determine the final access decision for any scenario:

ScenarioExplicit Deny?SCP Allows?Boundary Allows?Session Policy?Explicit Allow?Final Decision
No policies attachedNoYesN/AN/ANo❌ DENIED
Identity allowsNoYesN/AN/AYesβœ… ALLOWED
Deny + Allow both presentYesYesN/AN/AYes❌ DENIED
SCP blocks the actionNoNoN/AN/AYes❌ DENIED
Boundary blocks actionNoYesNoN/AYes❌ DENIED
Session policy restrictsNoYesYesNoYes❌ DENIED
All layers passNoYesYesYesYesβœ… ALLOWED
The Rule

A single "No" anywhere in any layer = DENIED. Access is allowed ONLY when every applicable layer says yes AND no explicit deny exists.

Chapter 05 Summary β€” Permission Evaluation Logic
  • Default state = DENY. Every request starts denied. Must be explicitly allowed.
  • Explicit Deny is absolute. It overrides all Allows from all policy types. No recovery.
  • Evaluation checks: Explicit Deny > SCP > Boundary > Session > Explicit Allow.
  • All layers must pass. It is an intersection of SCP, boundary, session, and identity/resource policies.
  • Same-account: identity OR resource policy can grant (union). Cross-account: both MUST grant (intersection).
  • SCPs and boundaries cannot grant. They can only restrict what identity policies allow.
  • No Deny does NOT mean allowed. Absence of Allow = implicit deny (the default).
  • Resource-based explicit Deny blocks even admin users (only root bypasses).
Chapter 05 β€” The Core Principle

IAM evaluation is a chain of filters: every filter can block, but only one check can grant. Build your mental model as: "denied by default, must pass ALL gates to get through." An explicit Deny at any stage is the end of the story.

Exam Tips β€” Chapter 05: Permission Evaluation
  • Explicit Deny always wins β€” this is the #1 tested concept in IAM.
  • Cross-account: both sides must allow. Identity in source + resource in target.
  • SCP does not apply to management account root. It applies to all other accounts.
  • Permission boundary = ceiling, not a grant. Identity must still explicitly allow.
  • "User got 403" β€” check: SCP, boundary, deny statements, then absent allow.
  • Session policies restrict but cannot expand. Passed at AssumeRole time.
06
Chapter Six

Security Best Practices

The Principle of Least Privilege Introductory

The most important security concept in IAM: grant only the minimum permissions required to perform a specific task. Nothing more. Start with zero access and add only what is needed. Never start with full access and try to remove.

The Mindset Shift

Most security breaches are not from sophisticated attacks - they are from over-permissioned identities. An IAM user with AdministratorAccess whose credentials leak gives an attacker full account control. An IAM user with s3:GetObject on one bucket limits blast radius to that one bucket.

Best Practices Checklist Core
πŸ”

Root Account Protection

  • Enable MFA on root immediately after account creation
  • Never use root for daily operations - create admin IAM user or use IAM Identity Center
  • Store root credentials in a hardware vault or offline password manager
  • Delete root access keys if they exist
  • Enable AWS CloudTrail to log any root usage
  • Set billing alarm for unexpected charges (root compromise indicator)
🎭

Use Roles Over Users

  • All AWS services should use roles, never hardcoded keys
  • CI/CD pipelines should use OIDC federation or role assumption
  • Cross-account access via role assumption, not shared credentials
  • Temporary credentials expire automatically - built-in safety
  • If you must use an IAM user, rotate access keys every 90 days maximum
  • Never embed access keys in source code or configuration files
πŸ“‹

Policy Design Principles

  • Start with zero permissions - add only what is needed
  • Scope to specific resources (ARN), not "Resource": "*"
  • Use conditions (IP, MFA, time, tags) to restrict context
  • Use permission boundaries for delegated admin scenarios
  • Prefer managed policies (version-controlled, reusable)
  • Review and remove unused permissions periodically (Access Analyzer)
πŸ›‘οΈ

MFA Everywhere

  • Root account: hardware MFA device (YubiKey or similar)
  • All privileged users: virtual MFA at minimum
  • Destructive operations: require MFA via policy condition
  • aws:MultiFactorAuthPresent: "true" in conditions
  • MFA for assuming sensitive cross-account roles
  • SMS MFA is discouraged - use TOTP or hardware tokens
🚫

Common Anti-Patterns to Avoid

  • Sharing IAM credentials between multiple team members
  • Using AdministratorAccess for daily operations
  • Embedding access keys in application code, Dockerfiles, or Git repos
  • Creating IAM users for services instead of roles
  • Setting overly broad resource targets (arn:aws:s3:::*)
  • Ignoring IAM Access Analyzer findings
πŸ“Š

Monitoring and Auditing

  • AWS CloudTrail: log all IAM API calls (create, delete, attach policy)
  • IAM Access Analyzer: identify resources shared externally
  • IAM Credential Report: find unused users and keys
  • Config Rules: enforce MFA, key rotation compliance
  • GuardDuty: detect anomalous IAM activity (unusual API calls)
  • Set alerts for root login, policy changes, and role creation
Diagram 16 β€” Concept: Defense-in-Depth IAM Layers Introductory
Concept Diagram - Defense-in-Depth Security Layers
LAYER 1: ORGANIZATION SCPs (account-wide guardrails) LAYER 2: PERMISSION BOUNDARIES (identity ceiling) LAYER 3: IDENTITY POLICIES (explicit grants) LAYER 4: RESOURCE POLICIES (resource-level gates) EFFECTIVE ACCESS Intersection of all 4 layers Each layer further restricts what the inner layers can grant. Effective = L1 AND L2 AND L3 AND L4 (all must pass).
Defense-in-depth: multiple concentric layers. The outermost layers set boundaries that inner layers cannot exceed.
Diagram 17 β€” AWS: IAM Security Tools & Monitoring Core
AWS Diagram - Security Monitoring and Compliance Tools
IAM Access Analyzer Find external access Generate least-priv policies Validate policy grammar Credential Report All users + key status Last used, rotation age MFA enabled status CloudTrail All API call logging Who did what, when Root login alerts GuardDuty Anomaly detection Unusual IAM operations Compromised creds alerts AWS Config Compliance rules (MFA, rotation) Drift detection Security Hub Centralized findings CIS benchmark checks Organizations Centralized SCPs Multi-account governance
IAM tools for continuous security: Analyzer for external access, Credential Report for hygiene, CloudTrail for audit, GuardDuty for threat detection.
Diagram 18 β€” Architecture: Secure Multi-Account IAM Design Professional
Architecture Diagram - Production-Ready Multi-Account IAM Setup
Management Account (Org Root) SCPs deployed to all OUs Root locked: MFA + no daily use CloudTrail org-wide enabled Dev Account Developers: IAM Identity Center Permission boundaries on roles SCP: DenyProdRegionActions Roles over users. No long-lived keys. Access Analyzer active Production Account Service roles only (EC2, Lambda, ECS) No IAM users. Zero human keys. SCP: DenyIAMUserCreate Cross-account deploy role only entrypoint GuardDuty + Config active Security Account Central CloudTrail log bucket Security Hub aggregation Break-glass admin role (MFA + approval) Read-only cross-account audit roles Credential report monitoring IAM Identity Center (SSO) Central identity source (IdP or built-in) Permission sets map to roles in accounts No IAM users needed for humans CI/CD (OIDC Federation) GitHub/GitLab assumes role via OIDC No static credentials stored anywhere Session scoped to repo + branch Zero long-lived credentials. Humans via SSO. Services via roles. CI via OIDC. Audit everything.
Production-ready setup: Org SCPs as guardrails, Identity Center for humans, OIDC for CI/CD, roles for services, Security account for audit.
IAM Access Analyzer β€” Automated Least Privilege Deep Dive
External Access Analysis
Continuously monitors resource policies (S3, KMS, SQS, Lambda, IAM roles) and alerts when a resource is shared with an external principal not in your zone of trust. Catches accidental public access or cross-account grants.
Unused Access Analysis
Identifies IAM roles, users, and access keys that have not been used within a specified period. Helps remove stale identities and reduce attack surface.
Policy Generation
Reviews CloudTrail logs to generate least-privilege policies based on actual usage. Create a role with broad permissions, let the workload run, then use Access Analyzer to generate a scoped policy.
Policy Validation
Checks policy JSON for grammar errors, security warnings, and best practice violations before you deploy. Catch overly-broad actions or missing resource scoping at authoring time.
Access Analyzer β€” Policy Generation Details In-Depth

One of the most powerful least-privilege tools: generate a policy from actual usage instead of guessing what permissions are needed.

InputOutput
CloudTrail logs (up to 90 days)Least-privilege policy based on actual API calls made
IAM user/role ARNPolicy scoped to exactly what that identity used
Time range selectionPolicies for specific audit windows (e.g., last 30 days)

Real-World Example

Start a Lambda role with s3:* + dynamodb:* (overly broad). Run it in production for 30 days. Then use Access Analyzer to generate a policy containing only the S3 and DynamoDB actions actually invoked. Replace the broad policy with the generated one.

Result: Perfect least-privilege without guessing.

Exam Keyword

"Reduce permissions to only what is needed based on actual usage" β†’ IAM Access Analyzer Policy Generation.

Chapter 06 Summary β€” Security Best Practices
  • Least privilege: start with zero, add only what is needed. Scope to specific resources and use conditions.
  • Root account: MFA, no daily use, no access keys, store offline. Monitor with CloudTrail alerts.
  • Roles over users: all services use roles. CI/CD uses OIDC. Cross-account uses role assumption. Never hardcode keys.
  • MFA: hardware for root, virtual for all privileged users. Require MFA in policy conditions for destructive ops.
  • Monitor: CloudTrail for audit trail, Access Analyzer for external access, GuardDuty for anomalies, Config for compliance.
  • Access Analyzer: generate least-priv policies from usage, validate policy grammar, and detect stale access.
  • Multi-account: Org SCPs as guardrails, IAM Identity Center for humans, separate security account for centralized audit.
  • Rotation: access keys 90-day max. Use credential report to identify stale keys. Prefer roles to eliminate rotation need.
Chapter 06 β€” The Core Principle

Security is not a one-time setup - it is continuous. Use automation: Access Analyzer for policy generation, Config for compliance checks, GuardDuty for threat detection. The goal is zero long-lived credentials, least-privilege policies, and complete audit visibility across every account.

Exam Tips β€” Chapter 06: Security Best Practices
  • Root account: enable MFA, no access keys, only for account-level tasks (billing, close account).
  • "EC2 needs S3 access" = use instance profile / role. Never access keys on the instance.
  • "Audit who did what" = CloudTrail. "Find external access" = Access Analyzer.
  • "Rotate credentials" = Credential Report + Config Rules. Automate with Lambda.
  • "Prevent creating resources outside eu-west-1" = SCP with aws:RequestedRegion condition.
07
Chapter Seven

Advanced Topics β€” Federation, STS & Cross-Account

AWS Security Token Service (STS) Core

STS is the engine behind all temporary credentials in AWS. Every time a role is assumed, a federation token is generated, or a session is created, STS is the service doing it. Understanding STS APIs is essential for advanced IAM work.

STS APIWho Uses ItWhat It ReturnsDuration
AssumeRole IAM users, roles, or services within or across accounts Temp creds (AccessKey + Secret + SessionToken) 15 min to 12 hours (default 1 hr)
AssumeRoleWithSAML Corporate IdP users via SAML 2.0 federation Temp creds mapped to federated identity 15 min to 12 hours
AssumeRoleWithWebIdentity Web/mobile app users via OIDC providers (Google, GitHub, Cognito) Temp creds for web identity 15 min to 12 hours
GetSessionToken IAM user requesting MFA-elevated session Temp creds with MFA context 15 min to 36 hours
GetFederationToken IAM user creating a federated session for downstream use Temp creds with optional session policy 15 min to 36 hours
GetCallerIdentity Any caller (debugging) Account ID, ARN, and UserId of the caller N/A (read-only, no credentials issued)
Role Chaining

A role can assume another role (role chaining). However, the maximum session duration for chained roles is capped at 1 hour regardless of individual role settings. This is an exam-tested limit. Also, aws:SourceIdentity propagates through the chain for audit purposes.

Identity Federation Deep Dive

Federation allows external identities to access AWS without creating IAM users. This is how enterprises with thousands of employees manage AWS access without 5,000 IAM users.

🏒

SAML 2.0 Federation

  • Enterprise IdP (Active Directory, Okta, Azure AD) authenticates user
  • IdP sends SAML assertion to AWS STS endpoint
  • STS validates assertion and issues temporary credentials
  • User assumes a role mapped to their SAML group/attribute
  • No IAM user created - identity lives in the corporate directory
  • Best for: large enterprises with existing IdP infrastructure
🌐

OIDC / Web Identity Federation

  • User authenticates with OIDC provider (Google, GitHub, Cognito)
  • App receives JWT token from the provider
  • App calls AssumeRoleWithWebIdentity with the JWT
  • Trust policy validates audience and subject claims
  • Best for: mobile apps, web apps, CI/CD (GitHub Actions OIDC)
  • Cognito Identity Pools simplify this for mobile/web apps
πŸ”‘

IAM Identity Center (SSO)

  • AWS-managed SSO service for multi-account access
  • Connects to corporate IdP or uses built-in directory
  • Permission sets map to IAM roles in target accounts
  • Single sign-on portal for all AWS accounts and apps
  • Replaces per-account IAM user management
  • Best for: any org with multiple AWS accounts
πŸ“±

Cognito (App Users)

  • User Pools: managed user directory with sign-up/sign-in
  • Identity Pools: exchange tokens for AWS temp credentials
  • Supports social login (Google, Facebook, Apple)
  • Maps authenticated/unauthenticated users to IAM roles
  • Fine-grained access control via identity pool role mapping
  • Best for: customer-facing apps needing AWS resource access
Cross-Account Access Patterns Deep Dive
PatternMechanismWhen to UseKey Consideration
Role Assumption Source account assumes role in target account via STS Most common. CI/CD, admin access, service access. Both sides must allow: trust policy + caller permission.
Resource-Based Policy Target resource policy grants access to source account principal S3 bucket sharing, KMS key sharing, Lambda invoke. Source identity policy ALSO needed (cross-account intersection).
IAM Identity Center Central SSO with permission sets across all accounts Human access to multiple accounts from single login. Creates roles in each account. Managed centrally.
AWS RAM (Resource Access Manager) Share specific resources across accounts without policies VPC subnets, Transit Gateways, License Manager configs. Limited to supported resource types.
Confused Deputy Problem Professional
What is the Confused Deputy?

When a third-party service (e.g., a monitoring SaaS) assumes a role in your account to access your resources, another customer of that SaaS could trick it into assuming YOUR role instead of theirs. The SaaS is the "deputy" being "confused" about which customer it is acting for. Solution: require ExternalId in the trust policy - a secret shared only between you and the legitimate third party.

Diagram 19 β€” Concept: Federation Flow Introductory
Concept Diagram - SAML and OIDC Federation Paths to AWS
Corporate User Corporate IdP (SAML Assertion) SAML AWS STS AssumeRoleWithSAML Validates assertion Temp Credentials Access AWS resources As assumed role App / CI/CD Pipeline OIDC Provider (JWT Token) OIDC AWS STS AssumeRoleWith WebIdentity Temp Credentials Scoped to role perms Short-lived session Human Developer IAM Identity Center (SSO) Permission Sets STS Role in target acct Auto-created by SSO Console + CLI Access any account No IAM users needed All paths end at STS. All produce temporary credentials. No long-lived secrets.
Three federation paths: SAML for enterprise, OIDC for apps/CI, IAM Identity Center for multi-account humans. All go through STS.
Diagram 20 β€” AWS: Cross-Account with ExternalId Core
AWS Diagram - Cross-Account Role with Confused Deputy Protection
THIRD-PARTY SaaS ACCOUNT YOUR ACCOUNT SaaS Service Role Calls sts:AssumeRole on YOUR role Passes ExternalId = "abc123-your-secret" AssumeRole + ExternalId MonitoringRole (Your Account) Trust: SaaS account ID Condition: ExternalId == "abc123-your-secret" Perm: cloudwatch:GetMetricData Only YOUR ExternalId passes trust check Attacker (Another SaaS Customer) Tricks SaaS into assuming YOUR role ARN BLOCKED (wrong ExternalId) ExternalId prevents confused deputy: only the legitimate SaaS with the correct secret can assume your role.
ExternalId is a shared secret in the trust policy condition. Attackers cannot guess it, so they cannot trick the SaaS into accessing your account.
Diagram 21 β€” Architecture: Enterprise Federation Setup Professional
Architecture Diagram - Enterprise SAML + Identity Center Multi-Account Access
Corporate IdP Active Directory / Okta Groups: Admins, Devs, Ops Source of truth SAML/SCIM IAM Identity Center Permission Sets: AdminAccess, DevAccess, ReadOnly Maps groups to permission sets Maps permission sets to accounts Central control plane Dev Account Auto-created role: DevAccess Permission set becomes role Staging Account Auto-created role: Ops + ReadOnly MFA condition enforced Production Account Auto-created role: AdminAccess (restricted) SCP limits even admin access GitHub Actions OIDC federation No static credentials Scoped to repo+branch AssumeRoleWithWebIdentity to Prod Deploy Role Humans via Identity Center (SSO). Machines via OIDC. Zero IAM users. All temp credentials. Corporate groups map to permission sets which become roles in each account.
Enterprise pattern: IdP groups map to permission sets, which auto-create roles in each account. CI/CD uses OIDC. No IAM users anywhere.
IAM Roles Anywhere In-Depth

A newer feature (2022) that extends IAM roles to workloads outside AWS β€” on-premises servers, Kubernetes clusters, IoT devices.

πŸ”

How It Works

  • Uses X.509 certificates instead of access keys
  • Register your Certificate Authority (CA) as a trust anchor
  • On-prem workload presents certificate β†’ gets temporary AWS credentials
  • Credentials expire (configurable session duration)
🏒

Use Cases

  • On-prem servers that need S3/DynamoDB access
  • Hybrid Kubernetes clusters
  • IoT devices calling AWS APIs
  • Migration: replace long-lived access keys with cert-based auth

Workflow: Register CA β†’ Create Trust Anchor β†’ Create Profile (maps to role) β†’ Workload presents cert β†’ Gets temp creds via rolesanywhere:CreateSession

Exam Keyword

"On-premises server needs AWS access without IAM user or access keys" β†’ IAM Roles Anywhere.

IAM Database Authentication (RDS) In-Depth

Not strictly IAM core, but frequently tested alongside IAM on AWS certification exams:

IAM DB Auth β€” Key Facts

  • What: Authenticate to RDS (MySQL/PostgreSQL) using IAM credentials instead of database passwords
  • How: Generate auth token with aws rds generate-db-auth-token β†’ token valid for 15 minutes
  • Requires: RDS instance with IAM DB Auth enabled + IAM policy granting rds-db:connect
  • Use case: No database password in application code; use IAM role on EC2/Lambda instead
  • Limitation: Max ~200 connections/second (not for high-connection workloads)
  • Benefit: Credentials rotate automatically; no SecretManager needed for DB passwords
Exam Pattern

"RDS authentication without storing passwords" or "Lambda accessing RDS securely" β†’ IAM Database Authentication.

Chapter 07 Summary β€” Advanced Topics
  • STS is the engine behind all temporary credentials: AssumeRole, AssumeRoleWithSAML, AssumeRoleWithWebIdentity, GetSessionToken, GetFederationToken.
  • Role chaining caps session at 1 hour maximum regardless of individual role settings.
  • SAML 2.0 β€” enterprise federation via corporate IdP. User never has IAM credentials.
  • OIDC β€” web identity federation for apps and CI/CD (GitHub Actions, Cognito).
  • IAM Identity Center β€” AWS-managed SSO. Permission sets become roles. Best for multi-account human access.
  • Cognito β€” User Pools for auth, Identity Pools for AWS credential exchange. App users pattern.
  • Cross-account: role assumption (both sides allow) or resource-based policy (both sides allow).
  • ExternalId in trust policy prevents confused deputy attacks from third-party services.
Exam Tips β€” Chapter 07: Advanced Topics
  • Role chaining = 1 hour max session. Cannot extend via role settings.
  • "Corporate SSO to AWS" = IAM Identity Center or SAML 2.0 federation.
  • "Mobile app needs S3 access" = Cognito Identity Pools + IAM role.
  • "GitHub Actions deploy to AWS" = OIDC federation, no stored secrets.
  • "Third-party SaaS access" = cross-account role + ExternalId condition.
  • GetCallerIdentity = debug "who am I?" No permissions needed to call it.
08
Chapter Eight

Architecture Patterns & Real-World Scenarios

Pattern 1 β€” EC2 Instance with Role-Based Access Core
Scenario
A web application on EC2 needs to read objects from an S3 bucket and write logs to CloudWatch. No static keys should exist on the instance.
Solution
Create an IAM role with S3 GetObject and CloudWatch PutLogEvents permissions. Attach it to the EC2 instance via an instance profile. The AWS SDK auto-retrieves temporary credentials from the instance metadata service (IMDS).
Key Details
Use IMDSv2 (token-required) to prevent SSRF attacks reading metadata. Scope S3 permission to specific bucket ARN. Enable VPC endpoints for S3 and CloudWatch to avoid internet traffic.
Pattern 2 β€” Lambda with Least-Privilege Execution Role Core
Scenario
A Lambda function processes SQS messages and writes results to DynamoDB. It must not have access to any other service.
Solution
Create an execution role trusted by lambda.amazonaws.com. Attach policy with sqs:ReceiveMessage, sqs:DeleteMessage, dynamodb:PutItem on the specific table ARN, and logs:CreateLogGroup / logs:PutLogEvents.
Key Details
Never use AmazonDynamoDBFullAccess managed policy. Scope to table ARN and specific actions only. Use resource-based policy on SQS to allow Lambda invocation if using event source mapping.
Pattern 3 β€” S3 Bucket with Mixed Access Control Deep Dive
Scenario
An S3 bucket serves as data lake. Internal analysts need read access, a Lambda role writes to it, and an external partner account reads a specific prefix.
Solution
Use identity-based policy for analysts (same account). Use execution role for Lambda (same account). Use bucket policy with Principal from partner account for cross-account access, scoped to specific prefix with Condition on s3:prefix.
Key Details
Cross-account: partner also needs identity policy allowing s3:GetObject. Add Deny for non-TLS access using aws:SecureTransport: false. Use S3 Block Public Access as safety net.
Pattern 4 β€” Cross-Account CI/CD Deployment Deep Dive
Scenario
GitHub Actions in a CI/CD account deploys CloudFormation stacks to a production account. No static credentials should exist.
Solution
Configure OIDC provider in CI account for GitHub. CI role assumes target deploy role in prod account. Target trust policy validates repo name, branch, and audience from OIDC token.
Key Details
Use ExternalId or OIDC conditions to prevent malicious repos from assuming the deploy role. Session is scoped to the specific deployment actions. Least-privilege: only CloudFormation and the specific resources being deployed.
Pattern 5 β€” Break-Glass Emergency Access Professional
Scenario
Normal access is via IAM Identity Center. But if IdP is down, engineers need emergency access to fix critical production issues.
Solution
Create break-glass IAM user in a separate security account. User has no policies except sts:AssumeRole on a specific emergency role. Emergency role requires hardware MFA. Credentials stored in physical vault (not digital).
Key Details
CloudTrail alert triggers on any break-glass login. Auto-notify security team. All actions during break-glass session are fully audited. Review and rotate credentials after each use. Test the process quarterly.
Diagram 22 β€” Concept: Pattern Decision Guide Introductory
Concept Diagram - Which IAM Pattern to Use Based on Scenario
WHO NEEDS ACCESS? AWS SERVICE EC2, Lambda, ECS Use: Service Role HUMAN USER Developer, Admin Use: Identity Center EXTERNAL Other account, SaaS, CI Use: Cross-Account Role Instance Profile (EC2) Execution Role (Lambda) Task Role (ECS) SSO (multi-account) Federation (SAML/OIDC) IAM User only if no other option Role + ExternalId (SaaS) OIDC (GitHub/GitLab) Resource policy (S3/KMS share) Every scenario has a role-based answer. IAM Users are the last resort, not the default.
Decision guide: service = service role, human = Identity Center, external = cross-account role. Always prefer temporary credentials.
Diagram 23 β€” AWS: Full Production Architecture IAM Layout Core
AWS Diagram - Complete Production IAM Architecture
PRODUCTION ACCOUNT VPC EC2 (App Server) Instance Profile: EC2-App-Role s3:Get, secrets:Get kms:Decrypt IMDSv2 enforced Lambda (API) Execution Role: Lambda-Orders-Role ddb:PutItem orders sqs:SendMessage Least privilege scoped ECS (Workers) Task Role: ECS-Worker-Role s3:PutObject results/ xray:PutSegments Separate task + execution role Resources S3 (data + logs) DynamoDB (orders) KMS (encryption) Secrets Manager Resource policies where needed IAM: Roles + Permission Boundary + SCP enforcement Every service uses a role. No human has direct access. CI/CD via OIDC only. Human Access (SSO) IAM Identity Center ReadOnly permission set No write access in prod Audit-only for engineers CI/CD (OIDC) GitHub Actions OIDC role Deploy permission only Branch + repo condition Zero stored secrets Break-Glass Security account IAM user MFA + manual approval Full admin when IdP is down Alert on any usage
Complete production IAM: services use roles, humans use SSO (read-only), CI uses OIDC, break-glass for emergencies. Zero long-lived credentials.
Diagram 24 β€” Architecture: Multi-Account IAM Strategy Professional
Architecture Diagram - Full Organization IAM Strategy
AWS ORGANIZATION - SCPs: DenyRootKeys, DenyOutsideRegions, RequireIMDSv2 Management Account Org admin + billing only Root: MFA + locked Dev Account Developers (SSO) Permissive boundaries Broad access OK Low blast radius Staging Ops + Dev (SSO) Tighter boundaries CI/CD deploy role Prod-like restrictions Production Services (roles only) No human IAM users SCP: DenyIAMUserCreate Maximum restriction Security CloudTrail central GuardDuty delegated Break-glass user Audit + emergency only Shared Svc DNS, VPN, images Cross-account roles for consuming accounts Shared resources via RAM IAM STRATEGY PRINCIPLES 1. Org SCPs enforce account-level guardrails (region, service, and action restrictions) 2. Identity Center for all human access. OIDC for all CI/CD. Roles for all services. 3. Zero IAM users in prod. Zero long-lived keys anywhere. Audit everything with CloudTrail.
Complete org strategy: management account governs via SCPs, each workload account has purpose-specific IAM patterns, security account centralizes audit.
Chapter 08 Summary β€” Architecture Patterns
  • EC2: instance profile + service role. IMDSv2 enforced. No keys on disk.
  • Lambda: execution role scoped to exact table/queue ARNs and actions needed.
  • S3 mixed access: identity-based for same-account, bucket policy for cross-account, conditions for prefix isolation.
  • CI/CD: OIDC federation (GitHub/GitLab). Cross-account deploy role with branch/repo conditions.
  • Break-glass: separate security account, hardware MFA, alert on use, review after each incident.
  • Multi-account strategy: Org SCPs as guardrails, Identity Center for humans, roles for services, security account for audit.
  • Zero IAM users in production. All access via roles, SSO, or OIDC.
Chapter 08 β€” The Core Principle

Production IAM is not about individual policies - it is about architecture. The right pattern eliminates entire classes of vulnerabilities. Use roles everywhere, federate humans, scope machines, guard with SCPs, and audit everything. The goal is zero long-lived credentials across all accounts.

Exam Tips β€” Chapter 08: Architecture Patterns
  • "EC2 needs S3 access without keys" = instance profile + service role.
  • "Lambda writes to DynamoDB" = execution role with PutItem on specific table ARN.
  • "Share S3 with another account" = bucket policy + caller identity policy (both required).
  • "Deploy from GitHub without secrets" = OIDC provider + cross-account role.
  • "Emergency access when SSO is down" = break-glass IAM user in security account + MFA.
  • "Prevent any human from creating IAM users in prod" = SCP DenyIAMUserCreate on prod OU.
← KMS Secrets Manager β†’