AWS Authentication Strategies: MFA, STS, and Federation
Authentication on AWS is the discipline of proving who a principal is and issuing it credentials — ideally short-lived ones minted by AWS STS rather than static access keys. Task 4.1 of the SCS-C03 exam tests whether you can design that discipline end to end: enforcing MFA with deny-based policy patterns, locking down the root user, replacing long-term keys with roles, choosing the right STS API for each federation shape, and wiring workforce identity through IAM Identity Center or SAML while workloads authenticate through OIDC, instance profiles, or IAM Roles Anywhere. It also tests whether you can diagnose the failures: an AssumeRole call rejected by a trust policy, a SAML assertion that maps no role, an external ID that does not match. This lesson covers proving identity and issuing credentials; what an authenticated principal is then allowed to do is Task 4.2's territory.
On this page8 sections
- Strong authentication baselines: MFA everywhere
- Root user protection and centralized root access
- Credential hygiene: eliminating long-term keys
- STS in depth: choosing the right API
- Trust policies and the external ID defense: a worked scenario
- Workforce federation: IAM Identity Center vs direct SAML
- Application and workload identity: Cognito, instance roles, Roles Anywhere
- Troubleshooting authentication failures
- Enforce MFA across an account with deny-based policies and protect the root user, including centralized root access management
- Replace long-term access keys with IAM roles and audit residual keys using the credential report and last-used data
- Choose the correct AWS STS API for each scenario and control session duration, session policies, and session tags
- Design role trust policies that defend against the confused deputy problem with sts:ExternalId and MFA conditions
- Compare IAM Identity Center, direct SAML 2.0 federation, OIDC workload federation, and Amazon Cognito for each identity population
- Troubleshoot AssumeRole AccessDenied errors, federation failures, and invalid or expired token errors
Strong authentication baselines: MFA everywhere
A Specialty-level MFA strategy distinguishes authenticator strength. FIDO2 security keys (hardware keys and passkeys) are phishing-resistant: the credential is origin-bound, so a lookalike sign-in page cannot replay it. Virtual TOTP authenticator apps are better than nothing but phishable — a proxied login page can capture and immediately use a six-digit code. For privileged human identities, the exam expects you to prefer FIDO2. AWS lets you register multiple MFA devices per user, so a hardware key plus a backup is the standard pattern for administrators.
Enforcement is a policy problem, not a checkbox. The canonical pattern is an explicit deny attached to identities (or applied as a guardrail) that blocks everything when MFA is absent:
{
"Effect": "Deny",
"Action": "*",
"Resource": "*",
"Condition": {
"BoolIfExists": { "aws:MultiFactorAuthPresent": "false" }
}
}The operator choice is the exam trap. aws:MultiFactorAuthPresent is only present in the request context when the call is made with temporary credentials; requests signed with long-term access keys omit the key entirely. BoolIfExists treats a missing key as a match, so the deny also blocks long-term-key requests — which is exactly what you want, because an access key can never carry MFA context on its own. Using plain Bool would silently exempt access-key traffic. You typically carve out the handful of actions a user needs to bootstrap MFA (viewing their user, enabling a device) with a NotAction element in the same statement, and you can pair the deny with aws:MultiFactorAuthAge to force re-authentication for sensitive actions after a time window.
Root user protection and centralized root access
The root user bypasses all IAM policies in its own account, so its protection is procedural: enable MFA (ideally FIDO2), delete any root access keys, use a monitored group email address, and never use root for daily work. AWS reserves a short list of tasks that genuinely require root — closing the account, changing certain account settings, restoring access when an S3 bucket policy or SQS queue policy locks out every principal including administrators. Everything else belongs to IAM roles. At the organization level, SCPs are one of the few controls that do constrain member-account root users, which is why a deny-based SCP guardrail is the standard defense against root misuse in member accounts.
The SCS-C03 guide explicitly calls out centralized root access management. With this AWS Organizations feature, you remove root user credentials from member accounts entirely — no root password, no root MFA to manage per account — and the management account (or a delegated administrator) can perform the remaining root-only tasks through short-lived, task-scoped privileged root sessions, such as deleting a misconfigured bucket policy that has locked everyone out. This shrinks the attack surface dramatically: a credential that does not exist cannot be phished. The exam pairs this with break-glass procedures: a documented, tested path for emergency privileged access, with credentials sealed away, alarms on any use (a CloudWatch alarm on root sign-in events via CloudTrail is the classic detective control), and a post-use rotation step. When a scenario mentions dozens of member accounts and the operational pain of tracking root MFA devices, centralized root access management is the intended answer.
Credential hygiene: eliminating long-term keys
The strongest credential strategy is to have as few long-term credentials as possible. Every place an access key lives — a developer laptop, a CI runner, an EC2 user-data script — is a place it can leak, and a leaked key is valid until someone notices. The design answer is roles everywhere: humans federate through IAM Identity Center, applications use instance profiles, task roles, or OIDC federation, and on-premises workloads use IAM Roles Anywhere. Temporary credentials expire on their own; revocation is a property of the design rather than an incident-response scramble.
For the keys you cannot yet eliminate, the exam expects you to know the audit tooling by name. The IAM credential report is a downloadable, account-wide CSV listing every user with the age and status of their passwords, access keys, and MFA devices — the fastest way to answer "which users still have keys older than 90 days?". Access key last used data (visible in the console and via GetAccessKeyLastUsed) tells you whether a key is actually in use before you deactivate it. IAM access advisor (service last accessed data) shows which services a user or role actually called, which drives least-privilege pruning — but note that is an authorization concern that Task 4.2 picks up. Where rotation is unavoidable, follow the two-key dance: create the second key, deploy it, confirm the old key shows no recent use, deactivate it, observe, then delete. Deactivation is reversible; deletion is not — the exam rewards the sequence that never causes an outage.
STS in depth: choosing the right API
AWS STS is the mint for temporary credentials, and the exam repeatedly tests which API fits which caller. The chooser:
| API | Caller authenticates with | Typical use |
|---|---|---|
AssumeRole | Existing AWS credentials | Cross-account access, privilege switching, workload roles, third-party access with external ID |
AssumeRoleWithSAML | SAML 2.0 assertion from a corporate IdP | Direct workforce federation to IAM without pre-existing AWS credentials |
AssumeRoleWithWebIdentity | OIDC token (web identity provider) | CI pipelines such as GitHub Actions, mobile apps, Kubernetes service accounts |
GetSessionToken | IAM user long-term credentials + MFA code | Minting an MFA-bearing session so MFA-gated actions succeed |
GetFederationToken | IAM user (a proxy/broker app) | Legacy custom identity broker handing scoped credentials to app users |
Session mechanics matter as much as the chooser. AssumeRole sessions default to 1 hour and can extend to the role's configured maximum session duration, up to 12 hours — but role chaining (using an assumed role's credentials to assume another role) is capped at 1 hour regardless. GetSessionToken for an IAM user defaults to 12 hours and can reach 36; a root user is capped at 1 hour. A session policy passed at assume time can only intersect — never expand — the role's permissions, which makes it the tool for handing a broad role to a caller in a narrowed form. Session tags travel with the session and feed ABAC decisions via aws:PrincipalTag; a tag can be marked transitive so it survives role chaining.
Trust policies and the external ID defense: a worked scenario
A role has two policy halves: the permissions policy (what the session can do — Task 4.2) and the trust policy (who may become the role). The trust policy is a resource-based policy whose Principal names the trusted account, role, service, or federated provider, and whose Condition block is where authentication controls live: sts:ExternalId for third parties, aws:MultiFactorAuthPresent to require that the assuming identity carries MFA, source conditions for service principals.
Walk the classic scenario. A monitoring vendor operates from its own AWS account and needs read access to your account, and to hundreds of other customers' accounts. You create a role trusting the vendor's account. The danger is the confused deputy: a malicious customer of the same vendor, knowing or guessing your role's ARN, asks the vendor's platform to connect to your role. The vendor — a deputy acting with its own credentials, which your trust policy accepts — would succeed. The defense is an external ID. The vendor assigns you a unique opaque value, and your trust policy requires it:
"Condition": {
"StringEquals": { "sts:ExternalId": "vendor-assigned-unique-id" }
}The vendor's platform passes each customer's own external ID on every AssumeRole call and — critically — refuses to let customers choose or edit that value. The attacker can name your role ARN, but the vendor will attach the attacker's external ID, the StringEquals fails, and STS returns AccessDenied. The external ID is not a secret credential; it is a binding between the vendor's customer record and your role. When an exam stem says "a third party accesses your account on behalf of multiple customers," the answer is the external ID.
Workforce federation: IAM Identity Center vs direct SAML
IAM Identity Center is AWS's recommended workforce answer, built for multi-account organizations. Its unit of authorization is the permission set — a template that Identity Center materializes as an IAM role in every account where a user or group is assigned. Assign one group a ReadOnly permission set across 40 accounts and Identity Center provisions and maintains 40 roles; users get a single access portal and short-lived credentials everywhere. Identity Center brings its own directory, or connects to an external IdP such as Entra ID or Okta over SAML 2.0 for authentication with SCIM for automated provisioning — SCIM keeps users and group memberships synchronized, so disabling a user at the IdP propagates without manual cleanup. That joiner-mover-leaver automation is a security control, not a convenience.
Direct SAML 2.0 federation to IAM predates Identity Center: you create a SAML identity provider entity in IAM, define roles trusting it, and users obtain credentials via AssumeRoleWithSAML. The IdP's assertion carries the role attribute mapping the user to one or more role/provider ARN pairs. Choose it when the question signals legacy constraints, a single account, or a broker that must call STS directly; otherwise Identity Center is the default answer for workforce access at scale.
OIDC federation covers non-human workforce adjacents such as CI. A GitHub Actions pipeline presents a short-lived OIDC token to AssumeRoleWithWebIdentity; the role trusts the OIDC provider and — at concept level — conditions on the token's aud (intended audience) and sub (repository and branch) claims so only the intended repo and branch can deploy. Scoping sub tightly is the difference between "this pipeline can deploy" and "anyone on GitHub can."
Application and workload identity: Cognito, instance roles, Roles Anywhere
Amazon Cognito handles customer identity, and the exam expects you to keep its two halves straight. A user pool is a user directory and OIDC authorization server: it authenticates your app's end users (with password policies, MFA, and social or SAML sign-in) and issues three JWTs — an ID token (identity claims), an access token (authorizes calls to your APIs), and a refresh token. A user pool alone grants no AWS access. An identity pool exchanges a token from a user pool or other provider for temporary AWS credentials, mapping authenticated (and optionally guest) identities to IAM roles. At mention level: the enhanced flow (GetCredentialsForIdentity) is the default and lets Cognito resolve the role server-side; the basic flow has the client call AssumeRoleWithWebIdentity itself with a role it names — more flexible, larger attack surface, disabled by default.
Compute workloads never store keys: EC2 uses instance profiles (credentials delivered and rotated via the metadata service — require IMDSv2), ECS tasks use task roles scoped per task definition, and EKS pods use IRSA, which is OIDC federation under the hood — covered in the compute domain, so a brief cross-reference suffices here. IAM Roles Anywhere extends the same model to on-premises servers: you register a certificate authority as a trust anchor, the workload authenticates with an X.509 client certificate, and a credential helper exchanges the certificate for temporary role credentials. Finally, S3 presigned URLs delegate authentication itself: the URL embeds a signature from the creator's credentials, so anyone holding it acts as the signer until expiry — and it never outlives the signing credentials, a subtlety the exam likes when the signer was a short-lived role session.
Troubleshooting authentication failures
Work AssumeRole AccessDenied as a two-sided problem, because both sides must independently allow. Side one: does the caller's identity-based policy allow sts:AssumeRole on the target role's ARN (and does no SCP or boundary deny it)? Side two: does the target role's trust policy name this caller — or its account — as a Principal, and are all trust conditions met? The condition failures are the exam's favorites: the vendor passed no ExternalId or the wrong one; the trust policy requires aws:MultiFactorAuthPresent but the caller's session was minted without MFA (fix: GetSessionToken with an MFA code, then assume); a sts:SourceIdentity or session-tag condition the caller did not set. CloudTrail is your evidence: the AssumeRole event records the caller, the role, and the error, and failed trust evaluation surfaces as AccessDenied — not as a missing event.
Federation failures cluster into three groups. Assertion and mapping problems: the SAML assertion's role attribute maps to no role ARN, the audience or issuer does not match the IAM identity provider, or an attribute your trust policy conditions on is absent. Clock skew, at mention level: SAML assertions and OIDC tokens carry validity windows, and a drifted IdP clock yields inexplicable "expired" rejections. Duration conflicts: requesting a DurationSeconds (or SAML SessionDuration) beyond the role's maximum session duration fails — align the IdP's requested duration with the role's configured cap. Separately, InvalidClientTokenId means the credentials themselves are not recognized: a deactivated or deleted access key, or an STS token presented in a Region whose STS endpoint is deactivated for that account. ExpiredToken means exactly that — the session outlived its duration; re-authenticate rather than retry.
Tip. Expect scenario stems that hinge on one authentication detail. "A third party accesses your account on behalf of many customers" points to sts:ExternalId in the trust policy; "MFA policy blocks users with access keys" points to BoolIfExists vs Bool on aws:MultiFactorAuthPresent. "Hundreds of member accounts and root credentials to manage" points to centralized root access management, and "CI pipeline deploys without stored keys" points to OIDC federation with aud and sub conditions. Troubleshooting stems test the two-sided AssumeRole check — caller permission and trust policy must both allow — and duration errors where the requested session exceeds the role's maximum.
- Enforce MFA with an explicit deny on aws:MultiFactorAuthPresent using BoolIfExists — plain Bool exempts long-term access-key requests because the key is absent from their context.
- Prefer phishing-resistant FIDO2 keys for privileged users; protect root with MFA and no access keys, and use centralized root access management to remove member-account root credentials entirely.
- Design for roles everywhere: temporary STS credentials expire on their own, while every long-term access key is a standing liability audited via the credential report and last-used data.
- Choose the STS API by caller: AssumeRole for AWS principals, AssumeRoleWithSAML for IdP assertions, AssumeRoleWithWebIdentity for OIDC tokens, GetSessionToken to mint MFA-bearing sessions.
- Third-party cross-account access requires sts:ExternalId in the trust policy — it binds the vendor's customer record to your role and defeats the confused deputy.
- IAM Identity Center with permission sets and SCIM provisioning is the default workforce answer at multi-account scale; direct SAML federation to IAM is the legacy/single-account pattern.
- Cognito user pools authenticate app users and issue JWTs; identity pools exchange those tokens for temporary AWS credentials — one without the other grants no AWS access.
- AssumeRole AccessDenied is two-sided: the caller's policy must allow sts:AssumeRole and the role's trust policy must match the caller and every condition, including external ID and MFA.
Frequently asked questions
How do you enforce MFA for all IAM users in AWS?
Attach an explicit deny policy that blocks all actions when aws:MultiFactorAuthPresent is false, using the BoolIfExists operator so requests signed with long-term access keys — whose context omits the key entirely — are also denied. Carve out only the actions needed to enroll an MFA device. For workforce users at scale, the cleaner answer is federating through IAM Identity Center and enforcing MFA at the identity provider.
What is the difference between AssumeRole, AssumeRoleWithSAML, and AssumeRoleWithWebIdentity?
All three return temporary credentials for a role, but they authenticate differently. AssumeRole requires the caller to already hold AWS credentials and is the tool for cross-account and third-party access. AssumeRoleWithSAML accepts a SAML 2.0 assertion from a corporate identity provider, and AssumeRoleWithWebIdentity accepts an OIDC token from providers like GitHub Actions or Cognito — neither requires pre-existing AWS credentials.
What is an external ID and when do you need one?
An external ID is a value a third party includes in its sts:ExternalId request parameter when assuming a role in your account, matched by a StringEquals condition in your role's trust policy. You need one whenever a third party assumes roles across many customers' accounts: it prevents the confused deputy attack, where one customer tricks the vendor into using its trusted position against another customer's role.
What is the maximum session duration for AWS STS temporary credentials?
An AssumeRole session defaults to 1 hour and can be extended up to the role's configured maximum of 12 hours, but role chaining — assuming a role from an already-assumed role — is capped at 1 hour. GetSessionToken for an IAM user defaults to 12 hours with a 36-hour maximum, while the root user is limited to 1 hour.
Why does AssumeRole fail with AccessDenied even though my policy allows it?
Because role assumption must be allowed on both sides. Your identity-based policy must allow sts:AssumeRole on the role's ARN, and the role's trust policy must name you (or your account) as a principal with every condition satisfied. The usual culprits are a missing or mismatched external ID, an unmet aws:MultiFactorAuthPresent condition, or an SCP deny — check the AssumeRole event in CloudTrail for the failing side.
Should I use IAM Identity Center or SAML federation directly to IAM?
Default to IAM Identity Center for workforce access: permission sets provision and maintain roles across every account in the organization, SCIM keeps users and groups synchronized with your identity provider, and users get one portal with short-lived credentials. Direct SAML 2.0 federation to IAM remains valid for legacy setups or single-account brokers that must call AssumeRoleWithSAML themselves.
Sign up free to mark lessons complete, bookmark topics and track your exam readiness.