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 covers three skills: designing identity solutions for human, application, and system authentication (IAM Identity Center, Amazon Cognito, MFA, and identity provider integration); configuring the mechanisms that issue temporary credentials (AWS STS and Amazon S3 presigned URLs); and troubleshooting authentication with evidence from CloudTrail, Cognito, Identity Center permission sets, and AWS Directory Service. This lesson works through each: how MFA is enforced and which factors resist phishing, how each STS API behaves and what its credentials can and cannot do, how session duration, session tags and source identity travel, how workforce federation and workload federation are wired, and how to read the failures when any of it breaks. Two neighbouring topics are deliberately left to their own lessons: root user credentials and centralized root access belong to Task 6.1 (AWS Organizations and multi-account security), and session policies and other permission ceilings belong to Task 4.2 (IAM policy evaluation and authorization).
On this page12 sections
- Strong authentication baselines: MFA everywhere
- Credential hygiene: eliminating long-term keys
- STS in depth: choosing the right API
- Session duration, role chaining, session tags, and source identity
- Trust policies and the external ID defense: a worked scenario
- Workforce federation: IAM Identity Center vs direct SAML
- IAM Identity Center identity sources, MFA, and SCIM provisioning
- Workload identity: CI pipelines, EKS, EC2, and servers outside AWS
- Amazon Cognito: user pools and identity pools
- Amazon S3 presigned URLs
- Troubleshooting authentication failures
- Troubleshooting federation, IAM Identity Center, Directory Service, and Cognito
- Enforce MFA with deny-based policies, let users self-enroll a device, and choose phishing-resistant factors
- Choose the correct AWS STS API for each caller and explain what GetSessionToken, GetFederationToken and AssumeRole credentials can and cannot do
- Control session duration, role chaining, session tags and source identity across federation and role chains
- Design trust policies that defeat the confused deputy with a vendor-generated external ID
- Integrate IAM Identity Center and direct SAML federation with external IdPs and AWS Directory Service, including MFA and SCIM provisioning
- Authenticate workloads with OIDC federation, EKS Pod Identity or IRSA, instance profiles, IAM Roles Anywhere, Amazon Cognito and S3 presigned URLs
- Troubleshoot STS errors, SAML and OIDC federation failures, Identity Center provisioning, directory connectivity and Cognito token problems using CloudTrail
Strong authentication baselines: MFA everywhere
MFA on AWS is enforced by policy, and its strength depends on the factor you choose. IAM supports three factor types for IAM users and the root user: FIDO2 security keys and passkeys, virtual authenticator apps (TOTP), and hardware TOTP tokens. SMS is not an IAM MFA option. Each IAM user can register up to eight MFA devices of any mix of supported types, which is how you give an administrator a backup.
| Factor | How it proves presence | Real-time phishing proxy |
|---|---|---|
| FIDO2 security key or passkey | Signs a challenge bound to the sign-in origin | Resists it: a lookalike domain gets a signature that AWS will not accept |
| Virtual authenticator app (TOTP) | User types a six-digit code | Vulnerable: the proxy relays the typed code within its validity window |
| Hardware TOTP token | User types a code from a key fob or card | Vulnerable for the same reason — the code is typed, so it can be relayed |
The distinction that matters is not hardware versus software but origin-bound signature versus typed code: any factor whose output a person types can be captured and replayed by a proxy page, so privileged users get FIDO2.
Enforcing MFA with an explicit deny
The standard pattern is an identity-based (or guardrail) deny that blocks everything when the request carries no MFA, with the enrollment actions carved out inside the same statement using NotAction:
{
"Sid": "DenyAllExceptMfaSetupWithoutMfa",
"Effect": "Deny",
"NotAction": [
"iam:CreateVirtualMFADevice",
"iam:EnableMFADevice",
"iam:GetUser",
"iam:ListMFADevices",
"iam:ResyncMFADevice",
"sts:GetSessionToken"
],
"Resource": "*",
"Condition": {
"BoolIfExists": { "aws:MultiFactorAuthPresent": "false" }
}
}The carve-out has to live in the deny. Policy evaluation lets an explicit deny override every allow, so a separate Allow statement for iam:EnableMFADevice cannot rescue a user caught by a deny on "Action": "*". The companion Allow statements then grant the self-service actions on the right resources: iam:CreateVirtualMFADevice targets an MFA device ARN (arn:aws:iam::*:mfa/*), while iam:EnableMFADevice, iam:ListMFADevices and iam:ResyncMFADevice target the user's own ARN (arn:aws:iam::*:user/${aws:username}). After enrolling, the user must sign out and back in: the session they enrolled from was authenticated without MFA and stays that way.
Choosing the condition operator
| Condition in the deny | Long-term access key request (key absent) | Session without MFA | Session with MFA |
|---|---|---|---|
Bool aws:MultiFactorAuthPresent = false | Not denied — a missing key never matches Bool | Denied | Allowed |
BoolIfExists aws:MultiFactorAuthPresent = false | Denied — IfExists treats a missing key as a match | Denied | Allowed |
Null aws:MultiFactorAuthAge = true | Denied — the age key exists only when MFA was used | Denied | Allowed |
aws:MultiFactorAuthPresent is never present on requests signed with long-term access keys, which is why plain Bool silently exempts them. aws:MultiFactorAuthAge holds the number of seconds since MFA authentication and is likewise absent for long-term keys; to force recent MFA for sensitive actions, deny with NumericGreaterThanIfExists on the age (for example 3600) so key-signed requests are also caught.
Keeping devices working
ResyncMFADevice needs two consecutive codes generated by the device itself. It fixes a TOTP device whose clock has drifted, but it cannot recover a lost device — the recovery path is a second registered device, or an administrator deactivating the lost one.
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 servers outside AWS use IAM Roles Anywhere. (Root user credentials are their own problem, handled organization-wide with centralized root access management in the Task 6.1 lesson.) 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 each API exists for a different kind of caller. The credentials they return are not interchangeable: some cannot call IAM, some cannot call STS again, and only some carry MFA context.
| API | Caller | Typical use |
|---|---|---|
AssumeRole | Any principal holding AWS credentials | Cross-account access, privilege switching, workload roles, third-party access with external ID; MFA can be supplied with SerialNumber + TokenCode |
AssumeRoleWithSAML | Anyone holding a SAML 2.0 assertion from a trusted IdP | Direct workforce federation to IAM roles without existing AWS credentials |
AssumeRoleWithWebIdentity | Anyone holding an OIDC token from a trusted provider | CI pipelines, EKS IRSA, Cognito basic flow |
GetSessionToken | An IAM user (or root) with long-term keys | Minting an MFA-bearing session from access keys |
GetFederationToken | An IAM user acting as a custom identity broker | Legacy broker issuing scoped credentials for a named federated user |
What GetSessionToken and GetFederationToken credentials can do
GetSessionToken | GetFederationToken | |
|---|---|---|
| Permissions | The calling IAM user's own permissions | Intersection of the IAM user's permissions and the session policy passed in the call; no session policy means no permissions |
| Session policy | Not accepted | Accepted (with a required Name for the federated user) |
| MFA | Accepts an MFA code, so the session carries MFA context | Cannot carry MFA context |
| IAM API calls | Only if MFA was supplied | None through the API or CLI |
| STS API calls | Only AssumeRole and GetCallerIdentity | Only GetCallerIdentity — so it cannot assume a role |
| Console sign-in via federation endpoint | No | Yes |
| Duration | 15 minutes to 36 hours (default 12 hours); root at most 1 hour | 15 minutes to 36 hours (default 12 hours); root at most 1 hour |
Two consequences follow. A user with long-term keys who must satisfy an MFA condition gets the MFA context from GetSessionToken (or from AssumeRole with an MFA code) — never from GetFederationToken. And a broker that needs role credentials cannot obtain them from a federation-token session, because that session cannot call AssumeRole.
On the command line, the mfa_serial setting in a profile takes effect when that profile also names a role_arn: the CLI prompts for the code and passes it on the AssumeRole call. A profile with only access keys and mfa_serial does not prompt; it needs an explicit aws sts get-session-token --serial-number … --token-code ….
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. (Designing trust policies as authorization controls — who should be trusted at all — is covered in the Task 4.2 lesson; here the focus is the authentication checks they perform.)
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. Your trust policy requires a value the vendor gives you:
"Condition": {
"StringEquals": { "sts:ExternalId": "vendor-generated-id-for-your-account" }
}The protection depends on who generates the value. The vendor generates a unique external ID for each customer, stores it with that customer's record, passes it on every AssumeRole call made for that customer, and never lets customers choose or edit it. The attacker can enter your role ARN, but the vendor attaches the attacker's own external ID, the StringEquals fails, and STS returns AccessDenied. If customers could pick the value, the attacker could simply type yours and the binding would be gone. The external ID is not a secret credential; it binds the vendor's customer record to your role.
Other conditions do not solve this problem. aws:PrincipalAccount, the vendor's role ARN or the vendor's source IP range all identify the vendor — and in a confused-deputy request the vendor is the caller, so the attacker's request passes them. Only a per-customer value that the vendor supplies separates one customer's request from another's.
Trust policies bind to unique IDs
When a trust policy (or any resource-based policy) names an IAM role or user, IAM stores that principal's unique ID behind the ARN. If the principal is deleted, the policy shows an ID beginning AROA (role) or AIDA (user) in place of the ARN, and a newly created principal with the same name does not match — it is a different principal. Re-enter the ARN in the policy to trust the new one. This is a security feature: recreating a deleted name cannot inherit its access.
Workforce federation: IAM Identity Center vs direct SAML
IAM Identity Center is AWS's recommended workforce answer for multi-account organizations. Its unit of authorization is the permission set — a template that Identity Center provisions as an IAM role (named AWSReservedSSO_…) 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 sign in once to the access portal and receive short-lived credentials in each account. The AWSReservedSSO_ roles belong to Identity Center: change the permission set, never the role.
Direct SAML 2.0 federation to IAM predates Identity Center. You create a SAML identity provider in IAM, create roles that trust it, and the IdP's assertion carries a Role attribute listing role-ARN/provider-ARN pairs; the sign-in endpoint then calls AssumeRoleWithSAML. An IAM SAML provider exists in one account only and cannot be shared (not through AWS RAM either), so federating directly into many accounts means a provider in each account, with each Role value pairing a role with the provider in that role's account. That per-account sprawl is the main reason Identity Center is the default at scale.
| IAM Identity Center | Direct SAML to IAM | |
|---|---|---|
| Scope | Every account in the organization from one place | One IAM SAML provider and set of roles per account |
| Authorization unit | Permission set assigned to users/groups per account | IAM roles, chosen through the assertion's Role attribute |
| User lifecycle | SCIM provisioning (external IdP) or directory sync | None in AWS — access follows what the IdP asserts |
| Fits | Workforce access across an organization | A single account, legacy integrations, or brokers that call STS themselves |
Workforce identities need MFA wherever they authenticate: at the external IdP when one is connected, or in Identity Center's own MFA settings when Identity Center or Active Directory is the identity source (next section).
IAM Identity Center identity sources, MFA, and SCIM provisioning
IAM Identity Center authenticates users against exactly one identity source at a time, and the source decides where users live, how they are provisioned and where MFA is enforced.
| Identity source | Users and groups come from | MFA configured in |
|---|---|---|
| Identity Center directory | Created in Identity Center | Identity Center MFA settings |
| Active Directory (AWS Managed Microsoft AD, or self-managed AD through AD Connector) | Synced from the directory | Identity Center MFA settings (or a RADIUS MFA on the directory) |
| External IdP (Entra ID, Okta, others) over SAML 2.0 | Provisioned by SCIM, or created manually with matching user names | The external IdP — Identity Center's MFA settings are not available |
External IdP: SAML for sign-in, SCIM for provisioning
With an external IdP, SAML authenticates the user, but the user must already exist in Identity Center: there is no just-in-time creation at first sign-in. SCIM automates that — creating, updating and deleting users and group memberships as the IdP changes, so disabling someone at the IdP removes their AWS access. Identity Center issues the SCIM access token the IdP uses, and it is valid for one year. When it expires, provisioning stops without any sign-in error: new hires never appear and leavers are never removed, while existing users keep signing in through SAML. Identity Center shows the expiry date in the console and sends expiry notifications, but nothing else fails, so track the expiry and rotate the token before it lapses.
MFA when Identity Center or AD is the source
Identity Center's MFA settings have three parts. The prompt mode is every sign-in (always-on) or only when the sign-in context changes (context-aware), or MFA can be disabled. The allowed MFA types are security keys and built-in authenticators (FIDO2/WebAuthn, including passkeys and platform authenticators) and authenticator apps (TOTP). The no-device behaviour decides what happens to a user without a registered device: require registration at sign-in, send a one-time password by email, block sign-in, or allow sign-in without MFA.
AWS Directory Service as the source
| AD Connector | AWS Managed Microsoft AD | |
|---|---|---|
| What it is | A proxy that forwards authentication to your on-premises AD; nothing is cached or stored in AWS | A real AD domain run by AWS |
| Domains | One domain | Multiple domains and forests through trusts |
| Identity Center requirement | Network reachability to the domain controllers and a working service account | To reach users in an on-premises forest, a two-way forest trust — a one-way trust does not work |
| Typical break | The service account's password changes in AD but not in Directory Service | Trust broken or one-way; DNS or network path to the on-premises forest |
Simple AD is not a supported Identity Center identity source, and SCIM applies only to external IdPs — directory sources sync through the directory connection.
Workload identity: CI pipelines, EKS, EC2, and servers outside AWS
Workloads should authenticate with credentials that are issued to them and expire, never with stored access keys. The mechanism depends on where the workload runs.
CI pipelines: OIDC federation
A GitHub Actions job presents a short-lived OIDC token to AssumeRoleWithWebIdentity. The account has an IAM OIDC provider for token.actions.githubusercontent.com, and the role's trust policy conditions on two claims: aud, which is sts.amazonaws.com for the official AWS credentials action, and sub, which identifies the repository and context. IAM rejects a trust policy for the GitHub provider whose sub condition is missing or is only a wildcard, because that would let any repository on GitHub assume the role.
| Job context | sub claim |
|---|---|
| Push to a branch | repo:<org>/<repo>:ref:refs/heads/<branch> |
| Job that references a GitHub environment | repo:<org>/<repo>:environment:<name> — replaces the ref form |
| Pull request | repo:<org>/<repo>:pull_request |
| Any context in one repository | repo:<org>/<repo>:* with StringLike |
Because an environment job's sub carries the environment instead of the branch, a trust policy written for a branch will not match a job that uses an environment.
Amazon EKS: IRSA versus EKS Pod Identity
| IAM roles for service accounts (IRSA) | EKS Pod Identity | |
|---|---|---|
| Mechanism | Per-cluster IAM OIDC provider; pod calls AssumeRoleWithWebIdentity | Pod Identity Agent on the node exchanges the pod's token; trust policy principal pods.eks.amazonaws.com |
| Trust policy | Names each cluster's OIDC provider and the service account in sub | Same trust policy for every cluster; the association maps role to service account |
| Reuse across clusters | Trust policy edited per cluster | Role reused without editing |
| Where it runs | EC2 nodes and Fargate | Linux EC2 nodes only (not Fargate) |
EC2, ECS and Lambda
EC2 uses instance profiles (credentials delivered and rotated through the instance metadata service — require IMDSv2), ECS tasks use task roles, and Lambda uses its execution role. All are role sessions, which is why a second AssumeRole from them is role chaining (see the session section).
Servers outside AWS
| Mechanism | Credential the server holds | What it gets |
|---|---|---|
| IAM Roles Anywhere | An X.509 certificate issued by a CA you registered as a trust anchor (AWS Private CA or your own CA bundle) | Temporary credentials for a role named in a profile, per workload |
| Systems Manager hybrid activation | An activation code/ID used once to register the server as a managed node | Credentials for the one IAM service role chosen for the activation, used by the SSM Agent |
| IAM user signing certificate | A long-term certificate attached to an IAM user | Long-term authentication for a few legacy APIs — not a workload-identity pattern |
Operating Roles Anywhere: the workload runs the AWS-supplied credential helper (aws_signing_helper) as a credential_process in its AWS config, so every SDK and the CLI pick up the credentials transparently. The role's trust policy names the rolesanywhere.amazonaws.com service principal and must allow sts:AssumeRole, sts:TagSession and sts:SetSourceIdentity; conditions on the certificate's attributes (for example its subject) scope which certificates may use the role. Roles Anywhere does not call OCSP or CRL distribution points: revoking a certificate means importing a CRL (ImportCrl). A CRL stops new sessions only — sessions already issued stay valid until they expire or are revoked at the role.
Amazon Cognito: user pools and identity pools
Amazon Cognito authenticates your application's end users, and its two halves do different jobs. A user pool is a user directory and OIDC provider: it signs users in (passwords, MFA, social or SAML sign-in) and issues JWTs — an ID token with identity claims, an access token with scopes for calling APIs, and a refresh token. A user pool by itself grants no AWS access. An identity pool exchanges a token from a user pool (or another provider) for temporary AWS credentials for an IAM role.
Identity pool roles and per-user scoping
- Authenticated and guest roles. An identity pool has a role for authenticated identities and, if guest access is enabled, a separate role for unauthenticated (guest) identities. A guest identity is not bound to any signed-in user, so the guest role must never grant per-user data access.
- Role selection. By default every authenticated identity gets the pool's authenticated role. User pool group roles (the
cognito:preferred_roleandcognito:rolesclaims) take effect only when the identity pool is set to choose role from token; rules-based mapping is the alternative. - Per-user scoping. To confine each user to their own S3 prefix or DynamoDB partition, use the policy variable
${cognito-identity.amazonaws.com:sub}, which resolves to the caller's identity ID.${aws:username}does not exist for role sessions, so a policy built on it matches nothing. - Trust policy. The identity pool roles trust
cognito-identity.amazonaws.comwith conditions oncognito-identity.amazonaws.com:aud(the identity pool ID) andcognito-identity.amazonaws.com:amr(authenticatedorunauthenticated). - Flows. The enhanced flow (
GetIdthenGetCredentialsForIdentity) is the default and lets Cognito choose and assume the role server-side; the basic flow has the client callAssumeRoleWithWebIdentityfor a role it names and is disabled unless you turn it on.
App clients
A browser or mobile app cannot keep a secret, so it uses a public app client with no client secret. If the app client has a secret, every user pool API call must include a SECRET_HASH computed from it, and a client-side app that omits it fails. Client-side apps therefore use a public app client, and the secret stays only in server-side (confidential) clients.
Amazon S3 presigned URLs
An S3 presigned URL is a request already signed with someone's credentials, so whoever holds the URL performs that one operation as the signer, with the signer's permissions, until it expires. Creating one needs no extra permission; using it succeeds only if the signer could perform the operation at the moment of use.
- Expiry. A SigV4 presigned URL can be valid for at most 7 days (the S3 console caps its own at 12 hours). It also stops working when the credentials that signed it expire, so a URL signed with a one-hour role session dies after that hour regardless of the expiry requested — sign with credentials that outlive the URL's intended life.
- Bucket-wide cap. A bucket policy can deny requests whose signature is older than a limit with the
s3:signatureAgecondition key, measured in milliseconds, regardless of what expiry the signer chose. - Encryption. For objects encrypted with SSE-KMS, the signer needs the KMS permissions too:
kms:GenerateDataKeyfor uploads andkms:Decryptfor downloads. - Choosing the signer. Sign with a dedicated identity that can do only what the URLs should allow (one prefix, one operation), so a leaked URL — or a bug in the code that generates URLs — cannot reach anything else.
Troubleshooting authentication failures
Authentication failures are diagnosed from the error code and from CloudTrail, which records STS calls — including failed ones — with the caller, the target role and the error.
| Error | Meaning | Typical fix |
|---|---|---|
AccessDenied on an AssumeRole* call | The caller is not allowed to call it, or the trust policy did not match the caller or a condition | Check both sides (below) |
InvalidClientTokenId | The access key ID or security token is not recognized — for example a deactivated or deleted access key | Use a valid, active credential |
ExpiredToken | The session outlived its duration | Re-authenticate or let the SDK refresh; retrying the same token never works |
RegionDisabledException | STS is deactivated in that Region for the account | Activate the Regional STS endpoint or call another Region's endpoint |
ValidationError on duration | The requested duration exceeds the role maximum or, when chaining, one hour | Request less, raise the role maximum, or remove the chain |
AssumeRole AccessDenied is two-sided
Side one: the caller's identity-based policy must allow sts:AssumeRole on the role's ARN, with no SCP or permissions boundary denying it. Side two: the role's trust policy must name the caller (or its account) as a Principal, and every condition must hold — the vendor's ExternalId, MFA present (fix: get an MFA session from GetSessionToken or pass the MFA code on AssumeRole), sts:TagSession or sts:SetSourceIdentity when tags or a source identity are passed. A trust policy that names a since-deleted role shows its unique ID and will not match a recreated role of the same name.
Tokens across Regions
Session tokens from a Regional STS endpoint are valid in every Region. Session tokens from the global endpoint are, by default (version 1), valid only in Regions enabled by default, so they are rejected in opt-in Regions. Either call a Regional endpoint, or set the account's global endpoint token version to version 2 (the IAM account setting, or SetSecurityTokenServicePreferences) — version 2 tokens are longer, so check any system that stores tokens.
Clock skew
SAML assertions and OIDC tokens carry validity windows; a drifted IdP clock produces rejections that look like expiry.
Troubleshooting federation, IAM Identity Center, Directory Service, and Cognito
Federation and directory failures leave different evidence depending on how far the sign-in got, so locate the failing step before changing anything.
SAML federation to IAM
| Symptom | Where the evidence is | Cause and fix |
|---|---|---|
Sign-in page rejects the response; no AssumeRoleWithSAML event in CloudTrail | The AWS sign-in endpoint's error page (and the IdP's logs) | The assertion is missing a required attribute — Role or RoleSessionName — or the Role value is malformed; fix the IdP's attribute mapping |
Failed AssumeRoleWithSAML events with AccessDenied | CloudTrail | The trust policy's conditions do not match — commonly SAML:aud not listing the sign-in endpoint the IdP posts to |
Failed AssumeRoleWithSAML on duration | CloudTrail | The SessionDuration attribute asks for more than the role's maximum session duration |
| Every user and every group fails at once | CloudTrail and the IdP | The IdP's signing certificate rolled over or expired and the IAM SAML provider still holds the old one; upload the IdP's new metadata |
For resiliency, an IdP can post to Regional sign-in endpoints (such as https://us-west-2.signin.aws.amazon.com/saml) as well as the global one. The trust policy's SAML:aud condition must list every endpoint the IdP uses, or sign-ins through the missing one fail. When tags are passed, a role without sts:TagSession in its trust policy fails for everyone who selects it.
IAM Identity Center
- Permission set changes not taking effect. Editing an assigned permission set in the console reprovisions it automatically. Changing it through the API (for example
PutInlinePolicyToPermissionSetor attaching a managed policy) updates only the template until you callProvisionPermissionSetto push it to the accounts. - Sessions too short or too long. The permission set's session duration (1 to 12 hours, default 1 hour) governs the account credentials; the access portal session is a separate setting. Do not edit the
AWSReservedSSO_role to change it — the change belongs on the permission set. - Delegated administrator cannot change a permission set. A delegated administrator cannot modify permission sets provisioned in the management account; those are managed from the management account.
- User cannot sign in with an external IdP. The user was never provisioned (SCIM not configured, the SCIM token expired, or the user is outside the synced groups), or the manually created user name does not match the IdP's.
- No AWS account shown in the portal. The user or group has no account assignment for any permission set.
AWS Directory Service
With AD Connector, authentication stops when the connector cannot reach the on-premises domain controllers (security groups, routing, DNS) or when the service account's password changed in AD but was not updated in Directory Service. With AWS Managed Microsoft AD, users from the on-premises forest cannot authenticate to Identity Center unless the forest trust is two-way.
Amazon Cognito
- API Gateway Cognito authorizer returns 401. With no authorization scopes on the method, the authorizer expects the ID token; with scopes configured, it expects an access token carrying one of them. Sending the other token type fails.
- Identity pool rejects a user pool token. Identity pool authentication providers are registered as a user pool ID plus app client ID; a token from an app client not listed there is treated as an unsupported provider.
- Credentials issued but role not assumed. Check the role's trust conditions on
cognito-identity.amazonaws.com:aud(the right identity pool ID) andamr. SECRET_HASHerrors. The app client has a secret that a public app cannot hold; use a public client.
Tip. Stems for this task usually turn on one precise authentication behaviour. Know which condition operator catches requests signed with long-term keys and why an MFA enrollment exemption must sit inside the deny; what each STS API's credentials can do (MFA context, IAM and STS calls, session policies, durations) and that chained role sessions are held to one hour; how session tags, transitive tags and source identity behave through a chain; who generates an external ID and why account or IP conditions do not stop a confused deputy; the claim formats an OIDC trust policy checks; how Identity Center's identity sources, SCIM provisioning and MFA settings interact; and how Cognito roles, policy variables and token types work. Troubleshooting stems give you an error code or a CloudTrail record and expect you to locate the failing step — caller policy, trust policy, assertion attribute, duration, provisioning, directory trust or token type.
- Enforce MFA with an explicit deny using BoolIfExists on aws:MultiFactorAuthPresent (or Null on aws:MultiFactorAuthAge) and put the enrollment carve-out inside the deny with NotAction — a separate Allow cannot beat an explicit deny.
- FIDO2 security keys and passkeys resist real-time phishing because they sign for the origin; any typed code, virtual or hardware TOTP, can be relayed. SMS is not an IAM MFA option, and each IAM user can register up to eight devices.
- Choose the STS API by caller: AssumeRole for AWS principals, AssumeRoleWithSAML and AssumeRoleWithWebIdentity for federation, GetSessionToken for an MFA session from access keys. GetFederationToken sessions carry no MFA, cannot call IAM, and cannot assume roles.
- Role chaining (including from EC2 instance profile credentials) is limited to one hour, and a chained request above 3,600 seconds fails rather than being shortened.
- Session tags need sts:TagSession in every reachable role's trust policy, transitive tags cannot be changed later in a chain, and source identity is set once and recorded in every CloudTrail event of the chain.
- The external ID works only because the vendor generates a unique value per customer and never lets customers choose it; account, role or IP conditions cannot stop a confused-deputy request.
- IAM Identity Center provisions permission sets as roles across accounts; with an external IdP, users must be provisioned (SCIM, token valid one year) before SAML sign-in, and MFA is enforced at the IdP.
- Workloads authenticate without stored keys: OIDC with a tight sub condition for CI, EKS Pod Identity or IRSA for pods, instance profiles on EC2, Roles Anywhere certificates for servers outside AWS, and Cognito identity pools for app users.
- Diagnose by evidence: a SAML response missing its Role attribute fails before any AssumeRoleWithSAML event, while trust-condition and duration problems show as failed AssumeRoleWithSAML events in CloudTrail.
Frequently asked questions
How do you enforce MFA for all IAM users in AWS?
Attach an explicit deny that blocks every action when aws:MultiFactorAuthPresent is false, using BoolIfExists so requests signed with long-term access keys (which never carry the key) are denied too. List the actions a user needs to enroll a device — such as iam:CreateVirtualMFADevice, iam:EnableMFADevice, iam:ListMFADevices, iam:ResyncMFADevice and iam:GetUser — in the deny's NotAction, because a separate Allow cannot override an explicit deny. For workforce users at scale, federate through IAM Identity Center and enforce MFA there or at the identity provider.
Which MFA types are phishing-resistant on AWS?
FIDO2 security keys and passkeys are phishing-resistant because the authenticator checks the website's origin before it signs, so a response produced for a lookalike domain is useless on the real AWS sign-in page. Virtual authenticator apps and hardware TOTP tokens both produce a code the user types, which a real-time phishing proxy can relay. SMS is not supported for IAM MFA. Each IAM user (and the root user) can have as many as eight MFA devices registered, so keeping a backup device is good practice.
What is the difference between AssumeRole, AssumeRoleWithSAML, and AssumeRoleWithWebIdentity?
All three return temporary credentials for an IAM role, but they authenticate the caller differently. AssumeRole requires the caller to already hold AWS credentials and is used for cross-account, privilege-switching and third-party access. AssumeRoleWithSAML accepts a SAML 2.0 assertion from a trusted corporate identity provider, and AssumeRoleWithWebIdentity accepts an OIDC token from a trusted provider such as GitHub Actions or an EKS cluster; neither needs existing AWS credentials.
What is the difference between GetSessionToken and GetFederationToken?
GetSessionToken gives an IAM user temporary credentials with the user's own permissions and can include an MFA code, so the session satisfies MFA conditions; it accepts no session policy and can call IAM only if MFA was supplied. GetFederationToken is for a custom identity broker: it takes a name and a session policy (without one the session has no permissions), cannot carry MFA, cannot call IAM, and can call no STS operation except GetCallerIdentity, so it cannot assume a role.
What is the maximum session duration for AWS STS temporary credentials?
A role session can last up to the role's maximum session duration, which is set between 1 and 12 hours (default 1 hour). Role chaining — assuming a role with role-session credentials, including EC2 instance profile credentials — is limited to one hour, and a chained request for more than 3,600 seconds fails. GetSessionToken and GetFederationToken run from 15 minutes to 36 hours for an IAM user and at most 1 hour for the root user.
What is an external ID and who should create it?
An external ID is a value a third party passes as the ExternalId parameter when assuming a role in your account, checked by an sts:ExternalId condition in the role's trust policy. The vendor should generate a unique value for each customer and never let customers choose it; that is what stops the confused deputy, where one customer tricks the vendor into using its trusted access against another customer's role. Conditions on the vendor's account or IP range do not help, because the vendor is the legitimate caller in that attack.
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 with no SCP or boundary denying it, and the role's trust policy must name you or your account and have every condition met — external ID, MFA, sts:TagSession when tags are passed, sts:SetSourceIdentity when a source identity is set. A trust policy that named a since-deleted role will not match a recreated role of the same name. The AssumeRole event in CloudTrail shows the caller and the error.
Should I use IAM Identity Center or SAML federation directly to IAM?
Use IAM Identity Center for workforce access across an organization: permission sets are provisioned as roles in every assigned account, SCIM keeps users and groups in step with an external identity provider, and users get one portal with short-lived credentials. Direct SAML 2.0 federation to IAM needs an IAM SAML provider and roles in every account, so it suits a single account, legacy integrations, or brokers that must call AssumeRoleWithSAML themselves.
Source
This lesson covers the "Identity and Access Management" domain of the official SCS-C03 exam guide. Vendors revise their guides — check the source for the current version.
- AWS Certified Security – Specialty (SCS-C03) exam guide — Amazon Web Services
Sign up free to mark lessons complete, bookmark topics and track your exam readiness.