IAM is the heaviest domain of SCS-C03 at 20%. Most questions hand you a few policies and a failing or over-permissive request, then ask what to change. You need to evaluate policies by hand, know which control applies where, and pick the right identity service for each kind of user.
Authentication: who is the caller
Choosing an identity solution
| Population | Use |
|---|---|
| Workforce in many AWS accounts and apps | IAM Identity Center connected to an external IdP (Microsoft Entra ID, Okta, others) or its built-in directory |
| Customers of your web or mobile app | Amazon Cognito user pools (sign-up/sign-in) and identity pools (AWS credentials) |
| Applications and services in AWS | IAM roles (instance profiles, execution roles, task roles) |
| Servers and workloads outside AWS | IAM Roles Anywhere (X.509), or STS with a web identity |
| Workloads in Kubernetes | IAM roles for service accounts or EKS Pod Identity |
| CI/CD (GitHub Actions and similar) | OIDC federation into a role (no stored keys) |
| Existing Active Directory | AWS Directory Service: AWS Managed Microsoft AD, AD Connector, Simple AD |
| Single account, few users | IAM users are discouraged; use Identity Center anyway |
IAM Identity Center
- Organization-level service (one instance; can be an organization instance or an account instance for a single app). Home Region fixed at setup.
- Permission sets are templates (managed policies, inline policy, permissions boundary, session duration); assigning one to a user or group in an account creates a role in that account (
AWSReservedSSO_...). Users sign in to the AWS access portal and get short-lived credentials. - Identity source: Identity Center directory, external IdP via SAML 2.0 with SCIM provisioning, or Active Directory (through Directory Service). Delegated administration is supported.
- Attributes for access control pass user attributes as session tags, which enables ABAC.
- Trusted identity propagation carries the user’s identity through to services such as Redshift, S3 Access Grants and Athena so access and audit are per person.
- MFA is set in Identity Center (context-aware, always on, or per sign-in); it supports authenticator apps, passkeys/security keys.
- Troubleshoot: a missing role in an account usually means the permission set isn’t provisioned/assigned; check permission set changes were re-provisioned and look at the SCP.
Amazon Cognito
| User pool | Identity pool | |
|---|---|---|
| Purpose | Directory and authentication; issues JWTs (ID, access, refresh) | Authorisation: swaps a token for temporary AWS credentials |
| Federation | Social (Google, Apple, Facebook), SAML, OIDC | Accepts user pool, social, SAML, OIDC, developer-authenticated, and guest identities |
| Features | MFA (SMS, TOTP, passkeys), password policy, adaptive authentication, hosted UI, Lambda triggers, groups with IAM roles | Roles for authenticated and guest users, role mapping by claim or rule |
- A user pool with an ALB or API Gateway authoriser protects an API; Cognito authoriser uses the access token.
- Identity pool credentials come from STS
AssumeRoleWithWebIdentity. - Advanced security features detect compromised credentials and risky sign-ins.
MFA
- MFA types for IAM and root: passkeys/FIDO2 security keys, virtual authenticator apps (TOTP), hardware TOTP tokens. SMS MFA is not supported for IAM. Root users and IAM users should have MFA; AWS now requires it for root users.
- Enforce MFA with a policy denying everything but self-service MFA actions when
aws:MultiFactorAuthPresentis false (useBoolIfExists). For API calls with MFA, callsts:GetSessionTokenorAssumeRolewith serial number and token. A role trust policy can require MFA with the same key. - Keys are present only for sessions created with MFA, so long-term access key calls lack it. Use
BoolIfExistscarefully.
Directory Service
| Option | Use |
|---|---|
| AWS Managed Microsoft AD | Real AD in AWS; trust with on-premises AD (one- or two-way, forest or external); supports Kerberos, LDAP, group policy |
| AD Connector | Proxy to existing on-premises AD; no data stored in AWS; needs network connectivity |
| Simple AD | Basic Samba-based directory (limited) |
Troubleshooting: trust failures usually come from security groups, DNS conditional forwarders, or Kerberos time skew.
Temporary credentials: STS and presigned URLs
STS issues credentials with an access key, secret key and session token.
| API | Caller | Use |
|---|---|---|
AssumeRole |
IAM principal | Cross-account and role switching; 1 hour default, up to the role’s max (12 hours); role chaining is capped at 1 hour |
AssumeRoleWithSAML |
SAML response | Federated enterprise users |
AssumeRoleWithWebIdentity |
OIDC token | Web/mobile (prefer Cognito) and OIDC workloads |
GetSessionToken |
IAM user | Temporary credentials with MFA |
GetFederationToken |
IAM user | Proxy-style federation; limited by caller permissions |
- Regional STS endpoints reduce latency and improve resilience; the global endpoint is single-homed.
- Session tags, source identity (
sts:SourceIdentity, persists through role chaining and shows in CloudTrail) and external ID (confused deputy protection for third parties) are tested. - S3 presigned URLs grant temporary access to one object for GET or PUT. They are valid until they expire or the signer’s credentials expire, whichever is first (up to 7 days with an IAM user, but a role session limits it). They carry the signer’s permissions; if the signer loses permission, the URL stops working. Alternatives: S3 Access Grants, CloudFront signed URLs.
- Revoking temporary credentials: attach a deny policy with a
aws:TokenIssueTimecondition, since the credentials otherwise live until expiry.
Troubleshooting authentication
- CloudTrail records
ConsoleLogin,AssumeRole*,GetSessionTokenand failures with anerrorMessage. Look forAccessDeniedonsts:AssumeRole(trust policy or caller permission missing) andInvalidIdentityToken. - SAML: check the assertion’s
Roleattribute, audience, clock skew and certificate expiry. - Cognito: token expired, wrong app client, wrong callback URL, a Lambda trigger failing, or role mapping not matching.
- Identity Center: missing assignment, permission set not provisioned, SCP blocking, or session duration.
- Directory Service: network paths, DNS, trust direction.
Authorisation: what may they do
Policy types
| Type | Attached to | Grants? | Notes |
|---|---|---|---|
| Identity-based | User, group, role | Yes | Managed (AWS or customer) or inline |
| Resource-based | S3, KMS, SQS, SNS, Lambda, ECR, Secrets Manager and others | Yes | Names a Principal; can grant cross-account alone |
| Role trust policy | Role | Who may assume it | A resource-based policy for roles |
| Permissions boundary | User, role | No, limits | Maximum for identity-based permissions |
| SCP | Org, OU, account | No, limits | Doesn’t affect the management account or service-linked roles |
| RCP (resource control policy) | Org, OU, account | No, limits | Caps access to resources in member accounts, including from outside principals |
| Session policy | AssumeRole call |
No, limits | Further narrows the session |
| VPC endpoint policy | Endpoint | No, limits | What goes through the endpoint |
| ACLs | S3, VPC | Yes | Legacy; use bucket owner enforced to disable S3 ACLs |
Evaluation logic
- Everything starts as implicit deny (except the account root user).
- Explicit deny in any applicable policy wins.
- Within one account, access is allowed if an identity-based policy or a resource-based policy allows it (for same-account principals the resource policy can grant on its own, with the exception of principals named as a specific user or role session).
- SCPs, RCPs, permission boundaries, session policies and endpoint policies must all also allow it. They filter; they never add.
- Cross-account: both sides must allow. The caller’s identity policy and the target’s resource policy. Exception: a role’s trust policy plus the caller’s
sts:AssumeRole. - A resource policy that names a role or user ARN as principal grants without a boundary check on that identity, but an SCP still applies.
Working example: user in account A, role in account B. A’s SCP blocks the action: denied. B’s role allows it: irrelevant. A’s SCP and A’s identity policy must allow sts:AssumeRole, and B’s trust policy must trust A.
Cross-account patterns
- Role assumption: preferred; the caller gives up the original identity temporarily and logs show the session.
- Resource policy (S3 bucket policy, KMS key policy): the caller keeps its identity. Needs its own identity policy as well unless the policy names its specific ARN in the same account.
- Resource Access Manager shares subnets, Transit Gateway, Route 53 rules and so on.
- KMS: cross-account use needs both the key policy and an IAM policy (key policy
kms:*to the account root enables IAM policies). - Use
aws:PrincipalOrgIDin resource policies to allow “anyone in my organization” without listing accounts.
Conditions you must know
aws:PrincipalOrgID / aws:PrincipalOrgPaths, aws:SourceIp, aws:SourceVpc, aws:SourceVpce, aws:RequestedRegion, aws:PrincipalTag/*, aws:ResourceTag/*, aws:RequestTag/*, aws:TagKeys, aws:MultiFactorAuthPresent, aws:MultiFactorAuthAge, aws:SecureTransport, aws:CalledVia, aws:ViaAWSService, aws:SourceArn / aws:SourceAccount (confused-deputy protection for service principals), aws:PrincipalIsAWSService, aws:TokenIssueTime, sts:ExternalId, iam:PassedToService, iam:PermissionsBoundary. Operators: StringEquals, StringLike, ArnLike, IpAddress, Bool, Null, and ForAnyValue/ForAllValues set modifiers; IfExists suffix.
Deny with StringNotEquals is true when the key is absent; use Null or IfExists carefully to avoid locking out.
Paths
IAM paths (/engineering/) organise users, roles and policies into hierarchies and let policies use ARN wildcards (arn:aws:iam::111122223333:role/engineering/*). A path is not a security boundary on its own, but it is useful for scoping delegated administration or a SCP.
Amazon Verified Permissions
Managed authorisation for your own applications. You write Cedar policies, define a schema, and the app calls IsAuthorized with principal, action, resource and context. Supports RBAC and ABAC, policy templates for sharing, integrates with Cognito or OIDC identity sources, and keeps decisions separate from application code. Pick it for “fine-grained, application-level authorisation without custom code”, not for AWS API permissions.
IAM Roles Anywhere
Gives workloads outside AWS temporary credentials: a trust anchor (your CA or AWS Private CA), a profile (roles, session policy), a certificate on the workload, and the signing helper. Condition keys include certificate attributes (aws:PrincipalTag from the cert subject). No long-term keys.
RBAC and ABAC
- RBAC: permissions grouped by job function in roles. Simple but creates many roles at scale.
- ABAC: permissions based on tags. One policy: allow actions where
aws:ResourceTag/projectequals${aws:PrincipalTag/project}. Scales as resources grow without policy updates. Requirements: consistent tagging, control who can change tags (restrictTagResource, tag edits on principals), and watch services that don’t support tag-based conditions. - In Identity Center, ABAC works through attributes passed from the IdP; for SAML federation, session tags in the assertion; with Cognito, claims mapped to principal tags.
- Protect tags: deny changes to the
projecttag except for administrators, and use SCPs to require tags on creation.
Least privilege tools
| Tool | Use |
|---|---|
| Permissions boundary | Allows delegated admins to create roles without escalation (require iam:PermissionsBoundary on CreateRole) |
| Session policy | Cut a session down at assume time (for example per-tenant access with AssumeRole) |
| Access Analyzer policy generation | Builds a policy from CloudTrail activity |
| Access Analyzer unused access | Finds unused roles, keys, passwords and permissions |
| Access Analyzer custom policy checks | CheckNoNewAccess, CheckAccessNotGranted for pipelines |
| Policy validation | Syntax, best-practice and security warnings |
| Service last accessed data | Which services a principal used, to prune |
| iam:PassRole | Scope to specific roles with iam:PassedToService |
Permission boundary vs SCP: a boundary caps one user or role; an SCP caps all principals in an account/OU. Boundary on a role limits what an identity policy can grant, but does not limit resource-based policies that name the role directly.
Analyse failures and unintended access
- IAM Policy Simulator tests policies against actions and resources (identity policies, boundaries, SCPs, and resource policies you supply) and shows which statement caused the result. It evaluates what you give it, not real traffic.
- CloudTrail
errorCodeanderrorMessageshow AccessDenied with reasons such as “explicit deny in a service control policy” or “no identity-based policy allows”. The message tells you which policy type denied. - Access Analyzer external access findings show resources shared with principals outside the zone of trust (account or organization): S3 buckets, IAM roles, KMS keys, Lambda, SQS, Secrets Manager, EBS snapshots, and others. Archive intended ones, fix the rest. Internal access findings (for specified critical resources) are available too. Unused access findings need a paid analyzer.
- Access Analyzer uses automated reasoning (Zelkova) to prove access paths rather than sampling.
- IAM credential report lists users, key age, MFA status; IAM access advisor shows last-accessed.
- Fix the cause, not the symptom: remove a public principal from a resource policy, tighten a role trust policy (
Principal: *without a condition is a red flag), delete unused keys, and prevent recurrence with an SCP/RCP or Config rule.
Confused deputy
When a service acts for you, use aws:SourceArn and aws:SourceAccount in the resource policy (for example the S3 bucket for CloudTrail or SNS), and sts:ExternalId for third-party roles.
Common traps
- A permissions boundary or SCP never grants access; it only caps.
- SCPs don’t restrict the management account and don’t affect service-linked roles.
- A resource policy can grant within the account without the identity policy (not true across accounts).
- Role chaining limits the session to 1 hour.
- Deleting an IAM user doesn’t kill temporary credentials already issued.
NotActionwith Allow grants everything else; easily overbroad.- Presigned URLs from a role session die when the session ends.
- Cognito user pool authenticates; identity pool issues AWS credentials.
- Policy Simulator isn’t a log of what happened; CloudTrail is.
Exam checklist
- Pick the identity solution: Identity Center, Cognito, Directory Service, Roles Anywhere, OIDC federation.
- Evaluate policy sets: explicit deny, SCP/RCP, boundary, session policy, identity, resource, cross-account both sides.
- STS API choice, session tags, source identity, external ID, role chaining 1 hour.
- Trust policy vs permission policy;
iam:PassRole. - ABAC with tags and
${aws:PrincipalTag}; protect the tags. - Access Analyzer: external, internal, unused access, policy generation, custom checks.
- Policy Simulator, CloudTrail error messages for troubleshooting.
- Verified Permissions with Cedar for application authorisation.