examhub .cc The most efficient path to the most valuable certifications.
Vol. I
In this note ≈ 38 min

Authentication Iam Identitycenter Cognito

7,600 words · ≈ 38 min read

AWS authentication on the SCS-C02 Specialty exam is no longer "create an IAM user and hand over an access key". The security engineer is expected to design defence-in-depth identity across human users, federated workforces, application clients, and end-user customers — and then prove they did it correctly when a sign-in fails or an audit asks "who exactly accessed this resource at 03:42 UTC". Domain 4 of SCS-C02 (Identity and Access Management, 16 percent of the exam) opens with task statement 4.1 — "Design, implement, and troubleshoot authentication for AWS resources" — and that single sentence covers IAM users vs roles, SAML 2.0 and OIDC federation, IAM Identity Center for workforce SSO, Amazon Cognito for customer identity, MFA enforcement patterns, the AWS STS API surface, session duration tuning, role chaining caveats, and the troubleshooting toolkit of CloudTrail, IAM Access Advisor, and IAM Policy Simulator. This guide walks the entire authentication design surface from the angle a security engineer is graded on: blast-radius minimization, audit fidelity, MFA correctness, and the failure modes that actually appear in CloudTrail.

This deep dive complements the authorization policies guide, which covers what an authenticated principal can then do. Here we focus on proving who the principal is in the first place.

Authentication Surface on SCS-C02 — What You Are Graded On

The exam guide for AWS Certified Security Specialty (SCS-C02) calls out task statement 4.1 with explicit knowledge requirements: methods and services for authenticating both AWS principals and end users, federation with SAML and OIDC providers, IAM Identity Center for human SSO, Amazon Cognito for application sign-in, MFA configuration and enforcement, AWS STS temporary credential APIs, and the troubleshooting tools for diagnosing failed authentication. Skills tested include configuring IAM Identity Center, integrating with third-party IdPs, designing authentication flows for applications, enforcing MFA, and reading CloudTrail to figure out why a sign-in failed.

What the exam does not test under 4.1 is what a principal can do once authenticated (that is task 4.2 — authorization, covered in the authorization-policies guide). Keep the boundary clear when you read scenarios: "the user could not sign in" is authentication; "the user signed in but got AccessDenied on s3:GetObject" is authorization. Distractor patterns frequently scramble the two.

  • IAM user: a long-lived AWS-internal identity with an access key, optional console password, and optional MFA device. Pre-2018 default; now reserved for break-glass and a shrinking list of legitimate uses.
  • IAM role: a short-term identity that any trusted principal can assume via STS to receive temporary credentials.
  • IAM Identity Center user: a workforce user managed through AWS Organizations, federated from an external IdP or built-in directory, accessing AWS via permission sets.
  • Cognito user pool user: an end-user identity in your application's user directory, authenticated via Cognito to receive ID and access tokens (OAuth 2.0 / OpenID Connect).
  • Cognito identity pool identity: a federated identity (from a user pool, a social IdP, or a SAML IdP) exchanged via Cognito for short-term AWS STS credentials to call AWS services from a mobile or web app.
  • Federated principal: any external IdP user (SAML 2.0 or OIDC) that has assumed an AWS IAM role.
  • Reference: https://docs.aws.amazon.com/IAM/latest/UserGuide/introduction.html

Plain-Language Explanation: AWS Authentication

Before we drown in SAML assertions and STS APIs, three mental models from very different domains cover every authentication concept SCS-C02 will test.

Analogy 1: The Office Building's Security Desk and Door Locks

Imagine your company occupies a 50-floor office building. IAM users with long-term access keys are like permanent magnetic keycards handed to staff — convenient, but if one is dropped on the street, anyone can swipe in until you remember to deactivate it. The security team hates them.

IAM roles assumed via STS are like the front-desk system that hands every visitor a single-use temporary pass valid for 1 to 12 hours. The pass can never be photocopied because it expires; if it leaks, the blast radius is at most a session. AWS STS AssumeRole is the receptionist printing the pass; AssumeRoleWithSAML is the receptionist accepting your corporate ID card from another building and printing a pass; AssumeRoleWithWebIdentity is the receptionist accepting a Google or Apple sign-in.

IAM Identity Center is the unified front desk for a campus of 50 buildings — one badge swipe at the kiosk, then the kiosk decides which buildings and which floors you can enter today. Amazon Cognito is the separate visitor centre built for the public — customers walk up, prove who they are with their own email and password (or via Google), and receive a wristband to use the customer-facing amenities like the café and the gift shop. The wristband never opens employee-only doors.

MFA is the two-step door at the data centre on floor 50: badge first, then biometric scan. The CloudTrail log book is the receptionist writing down every swipe — successful and refused — with timestamp, who tried, what door, and the outcome.

Analogy 2: The Airport with Many Counters

You are travelling internationally. The check-in counter verifies your passport and issues a boarding pass — that is AssumeRole minting STS credentials. Your boarding pass has an expiry stamp (session duration) and lists exactly which gates you can pass through (the role's permissions). At security, MFA is the second factor — passport plus the QR code from the airline app.

SAML federation is the frequent-flyer alliance: you have status with one home airline, walk into a partner airline's terminal, present your home airline's card, and the partner airline's check-in agent issues you a partner boarding pass — AssumeRoleWithSAML. OIDC federation with web identity is when you log in to a kiosk with Google or Apple and the kiosk prints you a partner pass — AssumeRoleWithWebIdentity.

IAM Identity Center is the alliance hub airport that prints boarding passes for every member airline at one super-counter. Amazon Cognito user pools is the frequent-flyer programme database for one airline — sign-up, password reset, MFA enrolment. Cognito identity pools is the desk that converts a frequent-flyer card into a temporary one-day boarding pass for partner-airline lounges.

Role chaining is when you take your domestic boarding pass, walk through the connection corridor, and trade it for a different international boarding pass — but each chain step subtracts from the total time you can travel before re-checking in.

Analogy 3: The Hospital's Wristbands

A hospital issues coloured wristbands to people in the building. Long-term IAM access keys are like permanent staff badges — they should never be carried by visitors. IAM roles via STS are the disposable wristbands handed at the registration desk; they expire when the appointment ends. MFA is the second piece of ID checked when you receive a wristband for a controlled ward.

IAM Identity Center is the central staff badge office that any hospital department can request wristbands from. Amazon Cognito user pools is the patient portal sign-in — patients have their own email and password, separate from staff identity. Cognito identity pools is the kiosk where a patient's portal login is exchanged for a short-lived wristband that lets the patient's mobile app fetch their lab results from a specific bucket.

CloudTrail is the central nurse station logbook: every wristband issued, every door tried, every refusal recorded. IAM Access Advisor is the annual review that flags wristbands that have not been used in 90 days. IAM Policy Simulator is the trial run where the security nurse simulates "if a patient with this wristband tried that door, would it open?" without anyone actually approaching the door.

When a SCS-C02 question describes "workforce humans with corporate IdP", picture the alliance airport hub. When it describes "mobile or web app sign-in for customers", picture the hospital patient portal. When it describes "temporary access for visitors that expires automatically", picture the disposable wristband or boarding pass. Reference: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp.html

IAM Users vs IAM Roles — Why Roles Are the SCS-C02 Default

The first authentication choice is the most consequential. SCS-C02 grades you heavily on understanding when each is appropriate.

IAM users — long-lived, riskier, increasingly rare

An IAM user is an AWS-internal principal stored in a specific AWS account. It has a unique ARN, can have a console password, can have up to two access key pairs (AKIA... plus secret), and can be assigned MFA. The credential lifetime is indefinite unless you rotate or delete — and that is the core security problem. A leaked access key in a public Git repository is the classic SCS-C02 incident scenario.

Legitimate uses of IAM users in 2026 are narrow:

  • A break-glass user in the AWS Organizations management account, used only when IAM Identity Center or the IdP is unreachable, with a hardware MFA token stored in a sealed envelope and CloudTrail alerts on every sign-in.
  • A handful of service accounts for legacy systems that cannot use roles (rare and shrinking).
  • Specific third-party SaaS integrations that require AWS access keys (most modern integrations now support sts:AssumeRole with an external ID).

For everything else — workforce engineers, applications running on EC2, Lambda, ECS, EKS, on-prem workloads, third-party SaaS integrations — IAM roles are the answer.

IAM roles — short-lived, auditable, blast-radius bounded

An IAM role has a trust policy (who can assume it) and identity-based policies (what it can do once assumed). Anyone the trust policy permits can call AWS STS to obtain temporary credentials (an access key, secret key, and session token) that expire after a configurable duration. Roles cover four major use cases:

  • Cross-account access — a role in account B trusts a principal in account A.
  • Service roles — Lambda execution roles, EC2 instance profiles, ECS task roles, EKS pod identity, where AWS services assume a role on behalf of your workload.
  • Federation — SAML 2.0 IdPs (AssumeRoleWithSAML) or OIDC IdPs (AssumeRoleWithWebIdentity) trade an external identity assertion for AWS credentials.
  • IAM Identity Center permission sets — under the hood, every permission set materializes as an IAM role with a AWSReservedSSO_* prefix in each assigned account.

SCS-C02 expects you to treat IAM users as a security exception requiring justification. Any scenario asking "best practice for granting a CI/CD pipeline access" answers with OIDC federation between the CI/CD provider (GitHub Actions, GitLab) and an IAM role, never with an IAM user and access keys. Any scenario asking "best practice for an EC2 instance to call AWS APIs" answers with EC2 instance profile, never with embedding an access key in user data. Reference: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles.html

Trust policy precision

A role's trust policy is half the security model. Sloppy trust policies are an interview favourite and an SCS-C02 favourite. Three pitfalls:

  • Principal: "*" without conditions — anyone in any AWS account can assume the role. Always scope to a specific principal ARN, account ID, or use service principals.
  • Missing sts:ExternalId for third-party SaaS integrations — without an external ID, the third-party SaaS becomes a "confused deputy" that other tenants of the SaaS could exploit. The ExternalId must be a unique, non-guessable string per tenant.
  • Missing aws:SourceIdentity enforcement for chained assume-role scenarios — without sts:SetSourceIdentity in the trust policy of the chained role, you lose attribution of the original principal in CloudTrail.

AWS STS Deep Dive — AssumeRole, AssumeRoleWithSAML, AssumeRoleWithWebIdentity

AWS Security Token Service (STS) is the API behind every short-term credential in AWS. SCS-C02 expects fluency in three flagship APIs and a handful of supporting ones.

AssumeRole — the workhorse

sts:AssumeRole is called by an AWS principal (an IAM user, another role, or a service) to assume a target IAM role. Inputs include the target role ARN, a session name (logged to CloudTrail; pick something identifying the human or job), an optional duration (default 1 hour, max governed by the role's MaxSessionDuration, which can be 1-12 hours), optional session tags for ABAC, optional transitive tag keys for role chaining, and an optional ExternalId if the trust policy requires it.

The output is an AccessKeyId (ASIA... prefix indicates a temporary key), a SecretAccessKey, a SessionToken (must be sent on every API call alongside the access key), and an expiration timestamp.

AssumeRoleWithSAML — workforce SAML 2.0 federation

sts:AssumeRoleWithSAML is called by an anonymous caller (no AWS credentials yet — that is the whole point of federation) presenting a base64-encoded SAML 2.0 response signed by a SAML IdP whose metadata is registered as a samlProvider in the target AWS account. The SAML response must contain attribute statements that map a SAML-asserted role and the SAML provider ARN, plus a session duration up to the role's MaxSessionDuration.

This API is what raw "SAML to IAM" federation uses — typically configured before IAM Identity Center existed. Most workforce identity in 2026 has moved to IAM Identity Center, which still uses this primitive under the hood but hides it behind permission sets.

AssumeRoleWithWebIdentity — OIDC federation

sts:AssumeRoleWithWebIdentity is called by an anonymous caller presenting an OIDC ID token signed by an OIDC IdP whose issuer URL is registered as an OIDC provider in the AWS account. The IdP can be a public one (Google, Apple, Facebook, Login with Amazon), an enterprise one (GitHub Actions, GitLab CI, CircleCI for CI/CD federation), or a Cognito user pool, or any IdP that emits standards-compliant OIDC tokens.

This is the API behind:

  • Mobile and web app sign-in via Cognito identity pools.
  • CI/CD short-term credentials for GitHub Actions, GitLab pipelines, etc.
  • EKS service account IAM roles (IRSA) — where the kubelet exchanges a Kubernetes service account JWT for AWS credentials.
  • EKS Pod Identity — newer simplified version of IRSA.
  • AssumeRole — caller is an AWS principal; input is role ARN + session name + optional ExternalId.
  • AssumeRoleWithSAML — caller is anonymous; input is SAML 2.0 response + SAML provider ARN + role ARN.
  • AssumeRoleWithWebIdentity — caller is anonymous; input is OIDC JWT + OIDC provider ARN + role ARN.
  • GetSessionToken — caller is an IAM user; returns short-term credentials with the same permissions as the user (used for MFA-required APIs from a long-term key).
  • GetFederationToken — proxy federation pattern; an IAM user trades its credentials for a more limited federated session.
  • All return AccessKeyId (ASIA prefix), SecretAccessKey, SessionToken, Expiration.
  • Reference: https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html

Session duration limits and role chaining

The maximum session duration is set per role via MaxSessionDuration (1-12 hours; default 1 hour). For SAML federation, the SAML response can request a duration up to that maximum via the SessionDuration attribute. For OIDC federation, the duration is requested in the API call.

Role chaining is when one role's session calls sts:AssumeRole to assume a second role. AWS imposes a hard cap of 1 hour on chained sessions, regardless of either role's MaxSessionDuration. This is a frequent SCS-C02 trap — scenarios describe a long-running batch job that fails after 1 hour because it chained from one role to another.

Source identity preservation

sts:SourceIdentity is the modern way to preserve attribution of the original human or principal across role chains and service-to-service calls. The trust policy of a downstream role can require sts:SetSourceIdentity, and CloudTrail records sourceIdentity in every event. Without it, a long chain of assume-role calls obscures who actually triggered the action.

A scenario describes "a 4-hour batch job that assumes a role then assumes a downstream role for cross-account data access — the job fails at the 1-hour mark with ExpiredToken". Distractor: "increase MaxSessionDuration on both roles". Correct answer: role chaining is hard-capped at 1 hour by STS regardless of role settings; redesign to either skip the chain (assume the downstream role directly from the original principal) or refresh credentials before each hour boundary. Reference: https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html

SAML 2.0 vs OIDC Federation — When Each Wins

Workforce federation to AWS IAM uses one of two protocols. SCS-C02 expects you to pick the right one.

SAML 2.0 federation

SAML is the older, XML-based, browser-redirect protocol used by most enterprise IdPs (Okta, Microsoft Entra ID, ADFS, PingFederate, Ping Identity, OneLogin). The IdP emits a SAML response signed with its private key; AWS verifies the signature against the public certificate registered in the SAML provider configuration. SAML federation pairs naturally with IAM Identity Center workforce SSO, and with the legacy AssumeRoleWithSAML per-account pattern.

Use SAML federation when:

  • The IdP is a traditional enterprise SSO product configured for SAML.
  • The use case is interactive workforce sign-in to the AWS Management Console.
  • You need fine-grained role mapping based on SAML attributes (group membership, department, etc.).

OIDC federation

OIDC (OpenID Connect) is the modern, JSON-based, REST-friendly protocol that runs on top of OAuth 2.0. The IdP emits a signed JWT (the ID token); AWS verifies it against the IdP's JWKS endpoint. Use OIDC when:

  • The use case is non-interactive — a CI/CD pipeline, a Kubernetes pod, a server workload calling AWS APIs.
  • The IdP natively emits JWTs (GitHub Actions, GitLab, EKS, Cognito user pools as IdPs).
  • You need fine-grained subject-claim conditions in the role trust policy (e.g., only allow this specific GitHub repo's main branch to assume the role).

For any scenario about "GitHub Actions deploying to AWS" or "GitLab pipeline assuming an AWS role" or "Kubernetes pod accessing S3", the answer is OIDC federation: register the CI/CD or EKS provider's OIDC issuer URL as an OIDC provider in IAM, write a role trust policy that conditions on the sub (subject) claim — like repo:my-org/my-repo:ref:refs/heads/main — and the pipeline calls AssumeRoleWithWebIdentity. Never embed long-term IAM access keys in CI secrets. Reference: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_create_oidc.html

OIDC trust policy condition keys

Modern OIDC trust policies use claim-based conditions to tightly scope who can assume the role:

{
  "Effect": "Allow",
  "Principal": {
    "Federated": "arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com"
  },
  "Action": "sts:AssumeRoleWithWebIdentity",
  "Condition": {
    "StringEquals": {
      "token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
    },
    "StringLike": {
      "token.actions.githubusercontent.com:sub": "repo:my-org/my-repo:ref:refs/heads/main"
    }
  }
}

Without the sub condition, any GitHub Actions workflow in any repo could assume the role — a public-internet-wide privilege escalation.

IAM Identity Center for Workforce Authentication

IAM Identity Center (renamed from AWS Single Sign-On in July 2022) is the AWS-native workforce SSO service that sits on top of AWS Organizations. It is the SCS-C02 default for "human authentication across many AWS accounts".

Identity sources

IAM Identity Center supports three identity sources:

  • Built-in directory — IAM Identity Center stores users and groups itself; suitable for small teams without an existing IdP.
  • Active Directory integration — AWS Managed Microsoft AD or AD Connector to on-premises AD; native AD group visibility.
  • External SAML 2.0 IdP — Okta, Microsoft Entra ID (Azure AD), Google Workspace, JumpCloud, Ping; SCIM 2.0 auto-provisioning syncs users and groups.

For SCS-C02, the default answer for any "modern workforce, existing corporate IdP" scenario is external SAML IdP plus SCIM auto-provisioning, with built-in directory reserved for very small teams or air-gapped environments.

Permission sets and materialized roles

A permission set is a template referencing AWS-managed policies, customer-managed policies, an inline policy, an optional permissions boundary, and a session duration (1 to 12 hours). When assigned to an AWS account, IAM Identity Center materializes the permission set as an IAM role named AWSReservedSSO_<permission-set-name>_<random-suffix> inside that account. The trust policy of the materialized role only trusts the IAM Identity Center service principal — direct AssumeRole from an IAM user is impossible.

MFA in IAM Identity Center

When IAM Identity Center authenticates with the built-in directory or AD, MFA is configured inside IAM Identity Center: choose between always-required, context-aware (require MFA when the source IP, browser, or device is new), or never (not recommended). Supported authenticators include security keys (FIDO2 / WebAuthn / Passkey), virtual authenticator apps (TOTP), and built-in platform authenticators (Touch ID, Face ID, Windows Hello).

When IAM Identity Center federates to an external SAML IdP, MFA is enforced at the IdP (Okta MFA, Entra ID Conditional Access, Google 2-Step). IAM Identity Center trusts the IdP's authentication assertion and does not re-prompt. The security engineer's job is to ensure the IdP's MFA policies are watertight — for example, Conditional Access in Entra ID requiring phishing-resistant MFA for any sign-in to the IAM Identity Center application.

SCS-C02 grades phishing-resistance heavily. TOTP (virtual MFA app codes) and SMS are vulnerable to phishing and SIM swap. FIDO2/WebAuthn security keys (YubiKey, Titan, Passkey) bind authentication to the origin URL and are immune to phishing. For the AWS Organizations management account root user, for IAM Identity Center privileged permission sets, and for break-glass IAM users, mandate FIDO2 hardware tokens or platform Passkeys. Reference: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa.html

Amazon Cognito — Customer Identity, User Pools and Identity Pools

While IAM Identity Center is for employees, Amazon Cognito is for your application's customers. SCS-C02 tests Cognito heavily because security engineers are routinely asked to design authentication for customer-facing mobile and web apps.

User pools — the customer directory

A Cognito user pool is a fully-managed user directory and authentication service for your application. It handles sign-up, sign-in, password reset, email/SMS verification, MFA, account recovery, and federated sign-in (the user pool can itself act as an OIDC service provider that delegates to social IdPs like Google or Apple, or to enterprise SAML IdPs). On successful sign-in, the user pool emits three JWTs:

  • ID token — claims about the user (sub, email, custom attributes); consumed by the application to display profile info.
  • Access token — short-lived authorization token; sent with API calls to your application or to API Gateway.
  • Refresh token — long-lived; used to obtain fresh ID and access tokens without re-prompting the user.

User pool features tested on SCS-C02:

  • MFA enforcement — optional, required, or adaptive (risk-based). Supports SMS, TOTP authenticator apps, and email OTP (newer). Note: SMS MFA is vulnerable to SIM swap; for high-assurance applications use TOTP or WebAuthn (Cognito user pools added Passkey/WebAuthn support).
  • Advanced security features (ASF) — paid tier that adds adaptive authentication (risk scoring on sign-in attempts, blocking suspicious IPs, requiring MFA when risk is elevated), compromised credential detection (checks against breached-password lists), and account takeover protection.
  • Lambda triggers — Pre Sign-up, Pre Authentication, Post Authentication, Pre Token Generation, Custom Message, Custom Authentication Challenge — let you inject custom logic, custom claims, or multi-step authentication flows.
  • App clients — define which clients (web app, mobile app, machine-to-machine) can call the user pool, with allowed OAuth flows (authorization code grant, implicit, client credentials) and scopes.

Identity pools — federated AWS credentials for app users

A Cognito identity pool (formerly "federated identities") is a separate service from user pools, despite the shared brand name. It does one thing: trade an authenticated identity (from a user pool, a social IdP, a SAML IdP, or a developer-authenticated identity) for short-term AWS STS credentials that the mobile or web app can use to call AWS services directly (S3 GetObject, DynamoDB Query, etc.).

The exchange uses AssumeRoleWithWebIdentity under the hood. The identity pool is configured with:

  • One or more identity providers trusted to authenticate users.
  • An authenticated IAM role assumed for users who signed in via a trusted IdP.
  • An optional unauthenticated IAM role assumed for guest users (use sparingly; many SCS-C02 scenarios mark unauthenticated access as a misconfiguration).
  • Role mappings — rules that pick a specific IAM role based on the user's claims (e.g., "users with cognito:groups containing premium get the premium role").

When to combine user pool + identity pool

The typical pattern: the customer signs in to your app via the user pool (handles password, MFA, federation to Google). The app receives ID and access tokens, calls the user pool's profile endpoint or your application's API, and — if the app needs to call AWS services directly from the device (upload to S3, query DynamoDB) — passes the user pool's ID token to the identity pool, receives short-term AWS STS credentials, and calls AWS APIs directly.

For any SCS-C02 scenario describing "mobile app users uploading directly to S3 with per-user prefix isolation", the answer combines a Cognito user pool (for sign-in and MFA) with a Cognito identity pool (to trade the user pool ID token for STS credentials), and an IAM role policy that uses ${cognito-identity.amazonaws.com:sub} in the resource ARN to limit each user to their own S3 prefix. Reference: https://docs.aws.amazon.com/cognito/latest/developerguide/identity-pools.html

Cognito vs IAM Identity Center — scope boundary

These two services do not overlap in correct usage:

  • IAM Identity Center — your employees signing in to AWS tools (console, CLI, AWS-integrated SaaS).
  • Cognito user pools + identity pools — your customers signing in to your application that you built on AWS.

A SCS-C02 distractor: "use IAM Identity Center to authenticate the customers of our SaaS app". Wrong — IAM Identity Center is workforce-only and not designed for self-service sign-up at customer scale. The right answer is Cognito user pools.

MFA Enforcement Patterns — aws:MultiFactorAuthPresent, SCP, Hardware vs Virtual vs Passkey

MFA is the highest-leverage authentication control on SCS-C02. The exam tests three layers: configuring MFA, enforcing MFA via policy, and choosing the right MFA factor type.

Configuring MFA

  • IAM users — assign virtual MFA (TOTP), hardware MFA (YubiKey, Gemalto), or FIDO2 security key. The root user supports all three plus Passkey.
  • IAM Identity Center built-in directory — Passkey, security keys, TOTP, built-in platform authenticator.
  • External IdP federation — MFA is enforced at the IdP, not at AWS. The federated session inherits the IdP's MFA assertion.
  • Cognito user pools — SMS, TOTP authenticator app, WebAuthn / Passkey, optional adaptive (risk-based) MFA via Advanced Security Features.

Enforcing MFA via IAM policy — aws:MultiFactorAuthPresent

Configuration alone does not enforce MFA — a user can have MFA enrolled and still call APIs without it (for example, with a long-term access key). Enforcement uses the aws:MultiFactorAuthPresent condition key in IAM policies:

{
  "Sid": "DenySensitiveActionsWithoutMFA",
  "Effect": "Deny",
  "Action": [
    "iam:DeleteVirtualMFADevice",
    "kms:ScheduleKeyDeletion",
    "s3:DeleteBucket"
  ],
  "Resource": "*",
  "Condition": {
    "BoolIfExists": {
      "aws:MultiFactorAuthPresent": "false"
    }
  }
}

The BoolIfExists operator is critical. With Bool, requests that have no MFA context (such as service-linked role calls or service principal calls) would be incorrectly evaluated as "MFA absent". BoolIfExists returns false only when the key is present and false; when the key is absent (a service-to-service call), the condition is treated as not matching, so the deny does not apply. This avoids breaking AWS services that legitimately operate without MFA.

A common SCS-C02 distractor: a deny-without-MFA policy uses "Bool": {"aws:MultiFactorAuthPresent": "false"} and inadvertently blocks AWS service-linked roles or other non-human callers, causing service disruption. The fix is BoolIfExists, which only triggers the deny when MFA is explicitly absent in a context where it should be present. Reference: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_condition-keys.html

Enforcing MFA via SCP

A Service Control Policy (SCP) attached to an OU or account in AWS Organizations can enforce MFA org-wide for the most sensitive APIs:

{
  "Sid": "DenyDestructiveActionsWithoutMFA",
  "Effect": "Deny",
  "NotAction": [
    "iam:CreateVirtualMFADevice",
    "iam:EnableMFADevice",
    "iam:GetUser",
    "iam:ListMFADevices",
    "iam:ListVirtualMFADevices",
    "iam:ResyncMFADevice",
    "sts:GetSessionToken"
  ],
  "Resource": "*",
  "Condition": {
    "BoolIfExists": {
      "aws:MultiFactorAuthPresent": "false"
    }
  }
}

The NotAction carve-out is essential — without it, the policy denies the very APIs a user needs to enrol MFA in the first place, locking new users out.

Choosing MFA factor types — phishing resistance is the dimension that matters

Factor Phishing resistant SIM-swap risk SCS-C02 stance
SMS OTP No Yes (high) Acceptable as fallback only; NIST has deprecated for high-assurance
Email OTP No No Acceptable for low-assurance; weaker than TOTP
TOTP authenticator app No No Good baseline; vulnerable to real-time phishing
Hardware OTP token (Gemalto, RSA) No No Better than TOTP; still phishable in real time
FIDO2 security key (YubiKey, Titan) Yes No Best for high-privilege; mandatory for management account root
Passkey (platform-bound FIDO2) Yes No Best UX; equivalent assurance to FIDO2 keys

For the root user of every AWS account, mandate a hardware FIDO2 token (YubiKey, Titan) or Passkey. For IAM Identity Center privileged permission sets, require the IdP to enforce phishing-resistant MFA. For Cognito user pool customers, offer TOTP or Passkey as alternatives to SMS, and use Advanced Security Features to detect risky sign-ins.

Authentication Troubleshooting — CloudTrail, IAM Access Advisor, IAM Policy Simulator

When a sign-in fails, the security engineer is the person on call. SCS-C02 tests the troubleshooting toolkit deeply.

CloudTrail for sign-in events

CloudTrail records both management events (API calls including STS) and a special category of AWS Console sign-in events (event source signin.amazonaws.com). Key fields for diagnosing failed authentication:

  • eventNameConsoleLogin, AssumeRole, AssumeRoleWithSAML, AssumeRoleWithWebIdentity, GetSessionToken, ExitRole.
  • responseElements.ConsoleLoginSuccess or Failure.
  • errorCode and errorMessage — for failures, the code names the specific failure (Failed authentication, InvalidClientTokenId, AccessDenied, TokenRefreshRequired).
  • additionalEventData.MFAUsedYes or No for ConsoleLogin.
  • userIdentity — type (IAMUser, AssumedRole, AWSAccount, FederatedUser), principalId, ARN, and (for federated calls) sessionContext.attributes including mfaAuthenticated.
  • sourceIPAddress — the IP the sign-in came from; cross-reference against approved corporate ranges or VPN exit IPs.

For IAM Identity Center sign-in events, look at event source sso.amazonaws.com and sso-directory.amazonaws.com. For Cognito events, look at cognito-idp.amazonaws.com (user pools) and cognito-identity.amazonaws.com (identity pools).

For any SCS-C02 scenario that asks "find every failed sign-in attempt by user X in the past 30 days" or "determine whether MFA was used for the action Y", CloudTrail with Athena queries against an S3-archived trail is the authoritative answer. CloudTrail Lake (the AWS-managed event-data store) is the modern alternative for ad-hoc SQL queries without setting up Athena. Reference: https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-event-reference-aws-console-sign-in-events.html

IAM Access Advisor for last-used analysis

IAM Access Advisor shows when an IAM user, group, or role last used each AWS service it has permission to call. For authentication troubleshooting and cleanup:

  • Detect dormant principals — an IAM user with no service activity in 90+ days is a candidate for deactivation.
  • Right-size permission sets — for an IAM Identity Center permission set's materialized role, Access Advisor reveals which services were never touched, suggesting the AWS-managed policies attached are too broad.
  • Identify abandoned roles — federated roles created during a project and never used since.

Access Advisor for organizations (org-wide) covers SCPs and lets you see when a service was last used by anyone in an OU — input to right-sizing SCPs.

IAM Policy Simulator for what-if testing

IAM Policy Simulator evaluates whether a hypothetical request by a principal would be allowed or denied without actually making the call. Inputs: principal ARN (user or role), action, resource, optional context keys (including aws:MultiFactorAuthPresent, aws:SourceIp, session tags). Outputs: Allow / Deny / Implicit Deny, plus the specific statement that drove the result.

When a user reports "I can't access the S3 bucket but I think I should be able to":

  1. Open Policy Simulator with the user's ARN.
  2. Enter the action (s3:GetObject) and the resource (the bucket ARN).
  3. Set context keys matching the user's actual session — particularly aws:MultiFactorAuthPresent, source IP, and any session tags from federation.
  4. Run the simulation and inspect which statement drives the outcome.

Policy Simulator evaluates identity-based policies, resource-based policies, permissions boundaries, and SCPs. Limitation: it does not evaluate session policies passed at AssumeRole time and does not catch resource-based policies on every service (it covers the well-known ones — S3, KMS, Lambda, SNS, SQS).

Putting the troubleshooting toolkit together

A typical SCS-C02 scenario: "a user reports they cannot sign in to the AWS Management Console after enrolling a new MFA device". The diagnostic flow:

  1. CloudTrail: filter signin.amazonaws.com, eventName ConsoleLogin, with the user's ARN. Check errorMessage — common values include Failed authentication (wrong password), MFA required (user did not present MFA), MFA invalid (wrong code or unsynchronised TOTP clock).
  2. If MFA-related, check the user's MFA device list (aws iam list-mfa-devices) and compare with what the user is presenting. Newly-enrolled virtual MFA devices need clock sync; hardware tokens need correct serial number registration.
  3. If the failure is AccessDenied post-sign-in (a permissions issue, not an auth issue), pivot to IAM Policy Simulator to identify the denying statement.
  4. If the user's IAM principal looks correct but they say "I have no permission to anything", check IAM Access Advisor to see whether services they expect to use have ever been accessed under their ARN.

Authentication Architecture Patterns — End-to-End Examples

Pattern 1: Workforce engineer accessing 50 AWS accounts

Identity source: Microsoft Entra ID with Conditional Access requiring phishing-resistant MFA. Federation: SAML 2.0 from Entra ID into AWS IAM Identity Center as identity source. Provisioning: SCIM 2.0 from Entra ID syncs users and groups (engineers, admins, auditors). Permission sets: job-function-based (DataEngineer, NetworkAdmin, ReadOnlyAuditor) with session duration 4 hours for engineers and 1 hour for admin permission sets, customer-managed policies for per-account variation. MFA enforcement: at Entra ID via Conditional Access; AWS-side aws:MultiFactorAuthPresent deny in SCP for destructive actions. Audit: CloudTrail org-wide trail to a central S3 bucket; Athena queries for ad-hoc audit; quarterly Access Advisor review.

Pattern 2: Mobile app with customer sign-in

Identity source: Cognito user pool with WebAuthn / Passkey MFA, Advanced Security Features for risk-based authentication, Lambda triggers for custom claims. Federation: optional social sign-in via Google and Apple as user pool IdPs. AWS access from device: Cognito identity pool trades the user pool ID token for STS credentials via AssumeRoleWithWebIdentity; the assumed IAM role's S3 policy uses ${cognito-identity.amazonaws.com:sub} to scope each user to their own bucket prefix. Audit: CloudTrail captures cognito-idp.amazonaws.com and cognito-identity.amazonaws.com events; the user pool's CloudWatch Logs export tracks sign-in success/failure metrics.

Pattern 3: GitHub Actions deploying to AWS

Identity source: GitHub Actions OIDC issuer (token.actions.githubusercontent.com), registered as an OIDC provider in the AWS account. Federation: workflow calls AssumeRoleWithWebIdentity presenting the GitHub-issued OIDC JWT. Trust policy condition: scopes to a specific repo and branch via token.actions.githubusercontent.com:sub claim — no long-term IAM access keys in GitHub secrets. Session duration: 1 hour, refreshed each pipeline run. Audit: CloudTrail AssumeRoleWithWebIdentity events with userIdentity.principalId showing the OIDC subject; correlate with GitHub workflow run IDs.

Pattern 4: On-premises server calling AWS APIs

Identity source: your private CA issuing X.509 certificates to on-prem servers. Federation: AWS IAM Roles Anywhere with the private CA registered as a Trust Anchor; the server's certificate is presented in mutual TLS to the IAM Roles Anywhere endpoint, exchanged for short-term credentials via CreateSession. Audit: CloudTrail records rolesanywhere.amazonaws.com events; cross-reference certificate serial number with on-prem inventory.

Authentication Key Numbers and Limits

  • STS AssumeRole session duration: 1-12 hours (default 1h), capped by role's MaxSessionDuration.
  • Role chaining session duration: hard-capped at 1 hour by STS, regardless of role settings.
  • STS GetFederationToken duration: 15 minutes to 36 hours; for IAM users only.
  • Cognito user pool ID/access token TTL: 5 minutes to 24 hours (default 1 hour).
  • Cognito user pool refresh token TTL: 60 minutes to 10 years (default 30 days).
  • Cognito identity pool credential duration: 1 hour (fixed).
  • IAM Identity Center permission set session duration: 1-12 hours (default 1h).
  • IAM Identity Center access portal session: up to 7 days for the portal itself, 1-12 hours per role session.
  • MFA TOTP code window: 30 seconds; AWS accepts current and adjacent windows for clock skew.
  • Maximum IAM users per account: 5,000 (soft limit).
  • Maximum IAM roles per account: 1,000 (soft limit, increasable).
  • Maximum SAML providers per account: 100.
  • Maximum OIDC providers per account: 100.
  • Reference: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-quotas.html

Common Exam Traps — Authentication on SCS-C02

Trap 1: IAM user with long-term access key for a workload

Distractor: "create an IAM user, generate an access key, store it in EC2 user data". Correct: EC2 instance profile assumes a role automatically; no static credentials.

Trap 2: Bool instead of BoolIfExists for aws:MultiFactorAuthPresent

A deny policy with Bool: false blocks legitimate non-human callers. Always use BoolIfExists: false to deny only when MFA is explicitly absent in a context that should have it.

Trap 3: Role chaining hits the 1-hour cap

A 4-hour batch job that chains roles fails at hour 1. Fix: avoid chaining (assume the downstream role directly) or refresh credentials hourly.

Trap 4: Cognito user pool vs identity pool confusion

User pool authenticates customers and emits JWTs. Identity pool trades JWTs for AWS STS credentials. They are separate services that are commonly used together. SCS-C02 distractors swap the two — read carefully.

Trap 5: SMS MFA as the primary factor for high-privilege accounts

SMS is vulnerable to SIM swap. For root user and privileged permission sets, mandate FIDO2 / Passkey.

Trap 6: OIDC trust policy without sub claim condition

A GitHub Actions OIDC role trust policy with no sub condition allows any GitHub repo on the internet to assume the role. Always scope to specific repo and branch.

Trap 7: SAML response replay protection

SAML responses must include a NotOnOrAfter timestamp and a unique assertion ID. Without these, an intercepted response could be replayed. AWS rejects responses outside the validity window automatically — but the IdP must emit them correctly.

Trap 8: Cognito identity pool unauthenticated role with broad permissions

Granting the unauthenticated identity pool role s3:* on a bucket means anyone on the internet can call AWS APIs against that bucket. Either disable unauthenticated access or scope its role to a tightly-defined read-only resource set.

Trap 9: External ID missing on third-party SaaS role

Without sts:ExternalId in the trust policy, the third-party SaaS becomes a confused deputy. Always require a unique ExternalId per tenant.

Trap 10: MFA configured but not enforced

A user can be enrolled in MFA and still call APIs without presenting it (long-term access key, no MFA context). Enrolment is configuration; enforcement requires aws:MultiFactorAuthPresent conditions in IAM policies or SCPs.

Trap 11: Editing the AWSReservedSSO_* IAM role

These materialized roles are managed by IAM Identity Center; manual edits are reverted on next reconciliation. Modify the permission set, not the role.

Trap 12: Cognito access token used to authorize AWS service calls

Cognito user pool access tokens are for your application's API, not for AWS service APIs. Direct AWS API calls require STS credentials obtained from a Cognito identity pool exchange.

FAQ — AWS Authentication for SCS-C02

Q1: When should I use an IAM user vs an IAM role?

For SCS-C02 in 2026, default to IAM roles. The narrow legitimate cases for IAM users are: a break-glass user in the AWS Organizations management account (with hardware MFA stored in a sealed envelope and CloudTrail alerts on every sign-in), legacy systems that genuinely cannot federate, and a small number of third-party SaaS integrations that still require static AWS access keys (a shrinking list — most have moved to sts:AssumeRole with ExternalId). For workforce humans use IAM Identity Center; for AWS workloads use service roles (Lambda execution role, EC2 instance profile, ECS task role, EKS pod identity); for CI/CD use OIDC federation; for on-prem workloads use IAM Roles Anywhere; for application customers use Amazon Cognito.

Q2: How do I enforce MFA correctly without breaking service-linked roles?

Use the aws:MultiFactorAuthPresent condition key with the BoolIfExists operator, not Bool. BoolIfExists evaluates to "key absent, condition not matched" for callers like AWS service principals or service-linked roles that legitimately operate without MFA, so the deny does not fire on them. Apply the deny in an SCP at the OU level for org-wide protection of destructive actions (KMS key deletion, IAM user deletion, S3 bucket deletion), and in identity-based policies for less-broad enforcement. Always carve out the IAM APIs that users need to enrol MFA in the first place (iam:EnableMFADevice, iam:CreateVirtualMFADevice, sts:GetSessionToken, iam:ListMFADevices) — without the carve-out, new users who haven't enrolled cannot enrol.

Q3: What is the difference between AssumeRole, AssumeRoleWithSAML, and AssumeRoleWithWebIdentity?

AssumeRole is called by an AWS principal (IAM user, another role, or AWS service) to assume a target IAM role; inputs include role ARN, session name, and optional ExternalId. AssumeRoleWithSAML is called by an anonymous caller with a base64 SAML 2.0 response signed by an IdP whose metadata is registered as a SAML provider in IAM; used for workforce browser-based federation. AssumeRoleWithWebIdentity is called by an anonymous caller with an OIDC JWT signed by an IdP registered as an OIDC provider; used for non-interactive workloads (CI/CD pipelines via GitHub Actions, EKS service accounts via IRSA, mobile apps via Cognito identity pools). All three return short-term ASIA... credentials with an expiration timestamp; the role's MaxSessionDuration caps the lifetime, and role chaining is hard-capped at 1 hour regardless.

Q4: What is the difference between Cognito user pools and identity pools?

A user pool is a fully-managed customer directory and authentication service that handles sign-up, sign-in, password reset, MFA, and federated sign-in (supports OIDC and SAML IdPs as upstream providers). On successful authentication, the user pool emits ID, access, and refresh JWTs that your application validates and uses to call your application's API. An identity pool (a separate service despite the shared brand) takes an authenticated identity (from a user pool, a social IdP, a SAML IdP, or a developer-authenticated source) and trades it for AWS STS short-term credentials so a mobile or web app can call AWS service APIs directly (S3, DynamoDB, etc.). The combination is used together: user pool authenticates, identity pool federates to AWS. SCS-C02 distractors frequently swap the two — only user pools can authenticate users; only identity pools issue AWS credentials.

Q5: How do I troubleshoot a failed sign-in for an IAM Identity Center user?

Start with CloudTrail filtered to event source sso.amazonaws.com (and the identity source's events at sso-directory.amazonaws.com) plus signin.amazonaws.com if the user reached an AWS console federation step. The errorMessage field names the specific failure: Failed authentication (credentials wrong at IdP), MFA required (user did not complete MFA), assertion expired (SAML response timestamp out of window), principalNotFound (SCIM did not yet sync the user), or accessDenied (user has no assignment to the requested account). If the IdP is external, check the IdP's own audit logs for the upstream authentication outcome. For permission-related failures post-sign-in (the user signed in but got AccessDenied calling an API), pivot to IAM Policy Simulator with the materialized AWSReservedSSO_* role's ARN, the requested action and resource, and the user's expected session context (MFA present, source IP, session tags).

Q6: How do I federate GitHub Actions to AWS without long-term access keys?

Register the GitHub Actions OIDC issuer (https://token.actions.githubusercontent.com) as an OIDC provider in IAM. Create an IAM role whose trust policy lists the OIDC provider as Federated principal, action sts:AssumeRoleWithWebIdentity, and a condition that constrains the token.actions.githubusercontent.com:sub claim to a specific repo and branch — for example repo:my-org/my-repo:ref:refs/heads/main for production deploys, or repo:my-org/my-repo:environment:production for environment-scoped trust. The GitHub Actions workflow uses the official aws-actions/configure-aws-credentials action with role-to-assume, which calls AssumeRoleWithWebIdentity presenting the GitHub-issued JWT, receives short-term ASIA... credentials, and uses them for the rest of the workflow. No IAM user, no static access keys, no long-term secrets in GitHub. CloudTrail records the AssumeRoleWithWebIdentity event with the GitHub workflow as userIdentity.principalId.

Q7: How do I enforce phishing-resistant MFA at AWS?

Phishing-resistant MFA means FIDO2 / WebAuthn / Passkey — the credential is bound to the relying-party origin and cannot be relayed to a phishing site. For the root user of every AWS account, register a hardware FIDO2 token (YubiKey, Titan Security Key) or a Passkey; AWS now supports up to 8 MFA devices per root user, so register two for redundancy. For IAM users, register FIDO2 keys instead of TOTP. For IAM Identity Center with built-in directory, configure MFA to require security keys (FIDO2 / Passkey) and disable TOTP and SMS for high-privilege permission sets. For IAM Identity Center with external IdP, the IdP enforces MFA — configure Conditional Access (Entra ID), authentication policies (Okta), or session controls (Google Workspace) to require phishing-resistant factors for the IAM Identity Center application. For Cognito user pools, enable WebAuthn / Passkey as an MFA option and use Advanced Security Features to elevate to Passkey-required for risky sign-ins.

Q8: What does CloudTrail show for AssumeRole events, and how do I correlate them?

AssumeRole, AssumeRoleWithSAML, and AssumeRoleWithWebIdentity are all logged as management events from sts.amazonaws.com. Key fields: eventName (which API), userIdentity (the calling principal — for cross-account it is the source account's principal, for federation it is awsAccount with no IAM identity), requestParameters.roleArn (the role being assumed), requestParameters.roleSessionName (a label you control — make it identifying), responseElements.assumedRoleUser.assumedRoleId (the unique ID of the assumed-role session), and additionalEventData.MFAAuthenticated. Subsequent API calls from the assumed session show userIdentity.type=AssumedRole and the same assumedRoleId, so you can correlate every action back to the original sign-in. If sts:SourceIdentity was set, the original principal's identity is also recorded in every downstream event.

Q9: When should I use IAM Roles Anywhere?

IAM Roles Anywhere is for non-AWS workloads that need short-term AWS credentials without long-term access keys. The use case is on-premises servers, build agents, or non-AWS cloud workloads that have an existing PKI infrastructure (a private CA issuing X.509 certificates to each workload). You register the private CA's certificate as a Trust Anchor in IAM Roles Anywhere, define a Profile that maps trust anchor + IAM role + session policies, and the workload presents its certificate via mutual TLS to the IAM Roles Anywhere endpoint, which exchanges it for AssumeRole-equivalent credentials. CloudTrail records rolesanywhere.amazonaws.com events; the certificate's subject CN appears in the session name. For workloads running inside AWS, use instance profiles or pod identity instead.

Q10: Why is role chaining capped at 1 hour, and how do I work around it?

When an assumed-role session calls AssumeRole to assume another role, AWS STS hard-caps the second session at 1 hour, regardless of either role's MaxSessionDuration. This is a deliberate security control to prevent indefinite extension via repeated chaining. The CloudTrail event shows a normal AssumeRole call but the credentials returned have a 1-hour expiry. Workarounds: avoid chaining by giving the original principal the ability to assume the downstream role directly (modify the downstream role's trust policy); refresh credentials before each hour boundary in long-running jobs by re-calling AssumeRoleWithWebIdentity or AssumeRoleWithSAML from the original federation source; or restructure the workflow so the long-running step uses a service role (Lambda, ECS task, EC2 instance profile) that gets fresh credentials automatically. The 1-hour cap is the most-tested STS quirk on SCS-C02.

Q11: How do I distinguish authentication failures from authorization failures in CloudTrail?

Authentication failures appear as events with no successfully-issued credentials: signin.amazonaws.com ConsoleLogin with responseElements.ConsoleLogin=Failure, or STS AssumeRoleWithSAML / AssumeRoleWithWebIdentity with errorCode set and no responseElements.credentials. Authorization failures appear after authentication succeeded, as API events on the target service with errorCode=AccessDenied and errorMessage describing the policy outcome. The pivot point is whether the user successfully obtained credentials. SCS-C02 scenarios sometimes describe a problem ambiguously ("user can't access S3") — your job is to read the CloudTrail snippet, identify which class of failure occurred, and pick the matching diagnostic tool: IdP logs and IAM Identity Center sign-in logs for authentication, IAM Policy Simulator for authorization.

Further Reading

Official sources