☰ All modules Tier 1 · Advanced Identity (Cognito, STS, cross-account roles) GuideCheat sheet ‹ security-encryptioncicd ›
Contents
  1. How Advanced Identity (Cognito, STS, cross-account roles) appears on DVA-C02
  2. 1. Cognito user pools vs identity pools
  3. 2. User pool sign up sign in and MFA
  4. 3. User pool tokens and JWT validation
  5. 4. User pool Lambda triggers
  6. 5. Managed login domains and OAuth flows
  7. 6. Feature plans and threat protection
  8. 7. ALB authentication with Cognito and OIDC
  9. 8. Identity pools and temporary AWS credentials
  10. 9. STS AssumeRole and cross account access
  11. 10. STS with MFA
  12. 11. Policy evaluation logic
  13. 12. Dynamic policies and policy variables
  14. 13. Managed vs inline policies and passing roles
  15. 14. AWS Directory Service
  16. Quick decision rules
  17. Changed vs older material

Advanced Identity (Cognito, STS, cross-account roles) — DVA-C02 Mastery Guide

  • Sources: course chapters 20 (Cognito) and 22 (Advanced Identity). The course serves as the syllabus only; all wording here is original.
  • Written 2026-10-12; values checked against AWS docs on 2026-10-12. The marker ⚠️ Changed: <current>. Older material may say <old>. flags a value or behaviour that differs from the course or older practice tests: learn the current value. ⚠️ unverified marks a value that could not be confirmed in AWS documentation: don't rely on it. Every change is listed in Changed vs older material; once you confirm them they also go to notes/current-facts.md.
  • Tier 1 (highest exam weight), bank target 40 questions. Domain: Security (task statement "authentication and authorization for applications and AWS services").
  • How to use it: /explain <topic> teaches from these sections (concept → exam facts → developer angle → traps → 3 check questions); /quiz advanced-identity asks bank questions whose source_note links point at the ## N. headings below; /drill advanced-identity fires short recall prompts from notes/advanced-identity-cheat-sheet.md. Suggested loop: read a section and answer its two practice questions before opening the answers → /explain what is still unclear → /quiz → /drill.

How Advanced Identity (Cognito, STS, cross-account roles) appears on DVA-C02

Security is 26 % of the exam, and its first task statement is exactly this module. Questions rarely ask for definitions; they describe an application and ask which identity component, token, API call or policy statement makes it work securely:

Deciding constraints you will meet: no long-term credentials in the app, least privilege, least custom code / operational overhead (managed login, ALB authentication, triggers instead of hand-written auth), a third party must not misuse the role (external ID), guests must stay limited (unauthenticated role).

Domain map: every topic is Security; §2–§4 and §8 also appear as Development with AWS Services questions (SDK calls, triggers), §9 and §11–§13 as Troubleshooting (AccessDenied diagnosis).

Out of scope: Active Directory administration (forests, group policy design, domain controllers), VPN or Direct Connect design for directories, and SAML/OIDC protocol internals beyond what a developer configures.

Owned by other modules (only cross-referenced here): IAM users, groups, policy grammar, MFA devices and access keys → notes/iam-guide.md · CLI profiles (role_arn, mfa_serial, source_profile), credential chain, sts decode-authorization-message, SigV4 → notes/cli-sdk-policies-guide.md · instance profiles, IMDS, ALB listeners and target groups → notes/ec2-mastery-guide.md §1, §2, §8 · API Gateway Cognito, IAM and Lambda authorizers → notes/api-gateway-guide.md · KMS key policies → notes/security-encryption-guide.md · bucket policies → notes/s3-guide.md · dynamodb:LeadingKeys → notes/dynamodb-guide.md · ECS task vs execution role → notes/containers-guide.md · Lambda execution role → notes/lambda-guide.md · AppSync and Amplify Auth → notes/other-services-guide.md · CloudTrail → notes/monitoring-guide.md.

# Topic Why it is on the exam
1 Cognito user pools vs identity pools The classic Cognito question: authenticate users (JWTs), authorize them to AWS (credentials), or both
2 User pool sign up sign in and MFA App clients, auth flows, SECRET_HASH, confirmation states, MFA factors, the exceptions you must recognise
3 User pool tokens and JWT validation ID vs access vs refresh token, lifetimes, verifying a JWT, revocation and rotation
4 User pool Lambda triggers The trigger that auto-confirms, migrates, customises tokens or messages; 5-second limit; invoke permission
5 Managed login domains and OAuth flows Hosted pages, custom domain with a us-east-1 certificate, code + PKCE vs implicit vs client credentials
6 Feature plans and threat protection Lite / Essentials / Plus; adaptive authentication and compromised-credential checks need Plus
7 ALB authentication with Cognito and OIDC Sign-in at the load balancer with no app code: HTTPS listener, callback URL, claims headers
8 Identity pools and temporary AWS credentials Guest vs authenticated roles, trust-policy conditions, role selection, enhanced vs basic flow
9 STS AssumeRole and cross account access Trust policy + identity policy, external ID, session-duration limits, the STS API set
10 STS with MFA GetSessionToken, MFA parameters on AssumeRole, aws:MultiFactorAuthPresent pitfalls
11 Policy evaluation logic Explicit deny wins; identity vs resource policies; cross-account needs both sides; guardrails never grant
12 Dynamic policies and policy variables One policy for many principals: ${aws:username}, principal tags, identity-pool sub
13 Managed vs inline policies and passing roles Policy types, versions and quotas; scoping iam:PassRole; one role per workload
14 AWS Directory Service Managed Microsoft AD vs AD Connector vs Simple AD, and when the answer is Cognito instead

1. Cognito user pools vs identity pools

Concept

Exam facts

Developer angle

Sign in at the user pool, exchange the ID token at the identity pool, call S3 with the result (boto3; assumes no MFA challenge):

import boto3

REGION, POOL_ID = "eu-west-1", "eu-west-1_Example1"
IDENTITY_POOL_ID = "eu-west-1:11111111-2222-3333-4444-555555555555"
auth = boto3.client("cognito-idp", region_name=REGION).initiate_auth(
    ClientId="1example23456789",                 # public app client: no secret
    AuthFlow="USER_PASSWORD_AUTH",               # needs ALLOW_USER_PASSWORD_AUTH on the client
    AuthParameters={"USERNAME": "maria@example.com", "PASSWORD": "Corr3ct-Horse-Battery"})
logins = {f"cognito-idp.{REGION}.amazonaws.com/{POOL_ID}": auth["AuthenticationResult"]["IdToken"]}
cid = boto3.client("cognito-identity", region_name=REGION)
identity_id = cid.get_id(IdentityPoolId=IDENTITY_POOL_ID, Logins=logins)["IdentityId"]
creds = cid.get_credentials_for_identity(IdentityId=identity_id, Logins=logins)["Credentials"]
s3 = boto3.client("s3", region_name=REGION, aws_access_key_id=creds["AccessKeyId"],
                  aws_secret_access_key=creds["SecretKey"],   # identity pools call it SecretKey
                  aws_session_token=creds["SessionToken"])
s3.put_object(Bucket="photo-uploads", Key=f"{identity_id}/cat.jpg", Body=b"jpeg-bytes")

Traps

Practice questions

  1. A startup builds a mobile photo app. Users must sign up with email and password or with Google, and the app must upload each user's photos directly to an S3 prefix that only that user can access, without running a backend. Which solution meets these requirements?
    • A. Create a Cognito user pool with Google federation and a Lambda function behind an API Gateway Cognito authorizer that returns S3 presigned URLs.
    • B. Create a Cognito user pool with Google federation, an identity pool that trusts it, and an authenticated role whose S3 resource uses ${cognito-identity.amazonaws.com:sub}.
    • C. Create an IAM user for each customer at sign-up and store its access keys in the device keychain.
    • D. Create an identity pool with developer-authenticated identities and one unauthenticated role that allows s3:* on the bucket.
  2. A news website shows article metadata from a DynamoDB table to anonymous visitors and lets signed-in readers post comments to a second table. The browser code must call DynamoDB directly with temporary credentials. Which TWO steps are required? (Select TWO.)
    • A. Enable unauthenticated identities in an identity pool and give its guest role read-only access to the metadata table.
    • B. Add the user pool as an authentication provider of the identity pool and give the authenticated role write access to the comments table.
    • C. Create one shared user pool account for anonymous visitors and embed its password in the website.
    • D. Create an API key in an API Gateway usage plan and embed it in the website to authorize the DynamoDB writes.
    • E. Embed an IAM user's access key in the website with a policy restricted to the two tables.
Answers
  1. B. The user pool signs users in (local or Google), the identity pool turns the ID token into role credentials, and the identity-ID variable confines each user to their own prefix. A works but runs a backend (API Gateway and Lambda), which the requirement rules out; C puts long-term keys on devices; D gives every guest full bucket access.
  2. A, B. Guests get the unauthenticated role, signed-in users the authenticated role. C publishes a credential and still yields tokens, not AWS credentials; D: API keys identify usage-plan clients and authorize nothing in DynamoDB; E ships a long-term key to every browser.

2. User pool sign up sign in and MFA

Concept

Exam facts

Developer angle

Public calls need no AWS credentials; admin calls need IAM permissions:

# Public operations: only the app client ID, no AWS credentials
aws cognito-idp sign-up --client-id 1example23456789 --username maria@example.com \
  --password 'Corr3ct-Horse-Battery' --user-attributes Name=email,Value=maria@example.com
aws cognito-idp confirm-sign-up --client-id 1example23456789 --username maria@example.com --confirmation-code 123456
# IAM-authorized: the caller needs cognito-idp:AdminConfirmSignUp on the pool
aws cognito-idp admin-confirm-sign-up --user-pool-id eu-west-1_Example1 --username maria@example.com
# Sign in, then answer the MFA challenge with the Session value from the first response
aws cognito-idp initiate-auth --client-id 1example23456789 --auth-flow USER_PASSWORD_AUTH \
  --auth-parameters USERNAME=maria@example.com,PASSWORD='Corr3ct-Horse-Battery'
aws cognito-idp respond-to-auth-challenge --client-id 1example23456789 --challenge-name SOFTWARE_TOKEN_MFA \
  --session "$SESSION" --challenge-responses USERNAME=maria@example.com,SOFTWARE_TOKEN_MFA_CODE=654321

Computing SECRET_HASH in a confidential server-side client:

import base64, hashlib, hmac

def secret_hash(username: str, client_id: str, client_secret: str) -> str:
    """Base64(HMAC-SHA256(key=client secret, message=username + client ID))."""
    digest = hmac.new(client_secret.encode(), (username + client_id).encode(), hashlib.sha256).digest()
    return base64.b64encode(digest).decode()

Traps

Practice questions

  1. A developer runs a Node.js service on Amazon ECS that signs users in with AdminInitiateAuth against an app client that has a client secret. The task role allows cognito-idp:AdminInitiateAuth on the user pool. Every request fails with the message Unable to verify secret hash for client. What should the developer change?
    • A. Add cognito-idp:AdminRespondToAuthChallenge to the task role.
    • B. Switch the request to USER_SRP_AUTH so that the password isn't sent.
    • C. Confirm the users with AdminConfirmSignUp before they sign in.
    • D. Send SECRET_HASH, computed from the username and client ID with the client secret, in AuthParameters.
  2. A fintech company builds its own sign-in screens on a Cognito user pool. Every local user must enter an authenticator-app code at each sign-in. Which TWO actions are required? (Select TWO.)
    • A. Add a custom message Lambda trigger that emails a TOTP code to the user at each sign-in.
    • B. Set the user pool MFA configuration to required with software-token (TOTP) MFA enabled.
    • C. Create an IAM role that allows Amazon Cognito to publish SMS messages through Amazon SNS.
    • D. During onboarding, call AssociateSoftwareToken and then VerifySoftwareToken with the user's first code.
    • E. Enable email MFA on the Essentials plan with an Amazon SES configuration.
Answers
  1. D. A client with a secret must prove knowledge of it in every sign-in call. A would surface as an IAM AccessDenied, not a hash error; B changes the flow but still needs the hash; C addresses UserNotConfirmedException, a different error.
  2. B, D. Required MFA with TOTP enabled forces the second factor, and the authenticator must be registered and verified once. A: TOTP codes come from the user's app, not from Cognito messages; C enables SMS, not TOTP; E adds email codes, not an authenticator app.

3. User pool tokens and JWT validation

Concept

Exam facts

Developer angle

Verifying access tokens in a Lambda function behind your own API (Node.js, aws-jwt-verify):

import { CognitoJwtVerifier } from "aws-jwt-verify";

const verifier = CognitoJwtVerifier.create({
  userPoolId: "eu-west-1_Example1",
  tokenUse: "access",            // "id" for ID tokens
  clientId: "1example23456789",  // checked against client_id (access) or aud (id)
  scope: "orders/read",          // optional: required OAuth scope
});
export const handler = async (event) => {
  const token = (event.headers?.authorization ?? "").replace(/^Bearer /, "");
  try {
    const claims = await verifier.verify(token);  // signature, exp, iss, token_use, client
    return { statusCode: 200, body: JSON.stringify({ user: claims.sub }) };
  } catch {
    return { statusCode: 401, body: "invalid token" };
  }
};

Token lifetimes, refresh and revocation from the CLI:

# Shorter tokens for a sensitive app (omitted client settings fall back to defaults!)
aws cognito-idp update-user-pool-client --user-pool-id eu-west-1_Example1 --client-id 1example23456789 \
  --access-token-validity 15 --id-token-validity 15 --refresh-token-validity 7 \
  --token-validity-units AccessToken=minutes,IdToken=minutes,RefreshToken=days \
  --explicit-auth-flows ALLOW_USER_SRP_AUTH ALLOW_REFRESH_TOKEN_AUTH
aws cognito-idp get-tokens-from-refresh-token --client-id 1example23456789 \
  --refresh-token "$REFRESH_TOKEN"     # also returns a new refresh token if rotation is on
aws cognito-idp revoke-token --client-id 1example23456789 --token "$REFRESH_TOKEN"
aws cognito-idp admin-user-global-sign-out --user-pool-id eu-west-1_Example1 --username maria@example.com

Traps

Practice questions

  1. A team runs a containerized Python microservice that receives Cognito user pool access tokens in the Authorization header of every request. It must reject forged or expired tokens while adding the least latency per request. What should the service do?
    • A. Call the user pool GetUser operation with each token and treat any error as an invalid token.
    • B. Base64-decode the token payload and accept the token when its exp claim is in the future.
    • C. Verify the RS256 signature with the user pool's cached JWKS keys, then check exp, iss, client_id and token_use.
    • D. Call AdminGetUser with the token's username claim and compare the stored attributes with the token claims.
  2. A banking app's security team requires that when a customer reports a stolen phone, the thief can no longer renew the session and already-issued access tokens stop working soon, without signing out any other customer. The APIs validate tokens offline. Which TWO actions meet this requirement? (Select TWO.)
    • A. Call AdminUserGlobalSignOut for the affected user from the support backend.
    • B. Increase the refresh token validity so that the customer doesn't have to sign in again.
    • C. Delete and recreate the app client used by the mobile app.
    • D. Call RevokeToken with the stolen access token.
    • E. Reduce the app client's access token validity to a short value such as 15 minutes.
Answers
  1. C. Local signature and claim checks are both secure and fast. A works but adds a network call per request and burns quota; B accepts forged tokens; D adds an IAM-authorized call per request and doesn't check the signature.
  2. A, E. Global sign-out kills the refresh tokens, and short access tokens limit how long an offline validator keeps accepting the stolen one. B lengthens exposure; C signs out every customer; D: RevokeToken takes a refresh token, not an access token.

4. User pool Lambda triggers

Concept

Exam facts

Trigger Fires Typical use Key response fields
Pre sign-up SignUp, AdminCreateUser, first federated sign-in (PreSignUp_ExternalProvider) Validate or reject; auto-confirm trusted users autoConfirmUser, autoVerifyEmail, autoVerifyPhone
Post confirmation After ConfirmSignUp, AdminConfirmSignUp, ConfirmForgotPassword, a federated user's first sign-in Welcome flow, create the profile row in DynamoDB —
Pre authentication Before Cognito checks the credentials Block a tenant, a device or a user throw an error
Post authentication After a successful sign-in Audit and analytics —
Pre token generation Before tokens are issued, also on refresh Add, change or suppress claims; override groups and roles claimsOverrideDetails (V1) / claimsAndScopeOverrideDetails (V2, V3)
Migrate user User not in the pool at password sign-in or ForgotPassword Just-in-time migration from a legacy store userAttributes, finalUserStatus, messageAction
Custom message Before codes, invitations or MFA messages go out Branded, localised text smsMessage, emailMessage, emailSubject (must contain the code placeholder)
Define / Create / Verify auth challenge CUSTOM_AUTH flow CAPTCHA, magic link, extra question challengeName, issueTokens, failAuthentication / challenge parameters / answerCorrect
Custom email / SMS sender Every message delivery Third-party email or SMS provider your function sends it

Developer angle

Pre sign-up that admits only company addresses and confirms them automatically (Python):

ALLOWED_DOMAIN = "@example.com"

def lambda_handler(event, context):
    if event["triggerSource"] == "PreSignUp_SignUp":
        if not event["request"]["userAttributes"].get("email", "").endswith(ALLOWED_DOMAIN):
            raise Exception("Sign-up is limited to company email addresses")
        event["response"].update(autoConfirmUser=True, autoVerifyEmail=True)
    return event

Pre token generation (event version V2_0) that adds a tenant claim to both tokens and a custom scope to the access token:

def lambda_handler(event, context):
    tenant = event["request"]["userAttributes"].get("custom:tenant_id", "none")
    event["response"]["claimsAndScopeOverrideDetails"] = {
        "idTokenGeneration": {"claimsToAddOrOverride": {"tenant_id": tenant}},
        "accessTokenGeneration": {"claimsToAddOrOverride": {"tenant_id": tenant},
                                  "scopesToAdd": ["orders/read"]},
    }
    return event

Wiring the functions outside the console:

aws lambda add-permission --function-name tenant-claims --statement-id cognito-pretoken \
  --action lambda:InvokeFunction --principal cognito-idp.amazonaws.com --source-account 111122223333 \
  --source-arn arn:aws:cognito-idp:eu-west-1:111122223333:userpool/eu-west-1_Example1
# UpdateUserPool resets omitted settings: list every trigger (and setting) you want to keep
aws cognito-idp update-user-pool --user-pool-id eu-west-1_Example1 \
  --lambda-config 'PreSignUp=arn:aws:lambda:eu-west-1:111122223333:function:signup-guard,PreTokenGenerationConfig={LambdaArn=arn:aws:lambda:eu-west-1:111122223333:function:tenant-claims,LambdaVersion=V2_0}'

Traps

Practice questions

  1. A company is moving 200,000 users from a legacy MySQL table with salted password hashes into a Cognito user pool. Users must keep their current passwords and must not receive password-reset emails. Which approach meets these requirements with the LEAST effort?
    • A. Add a migrate user trigger that checks credentials against the legacy store and returns finalUserStatus CONFIRMED, and allow USER_PASSWORD_AUTH on the app client.
    • B. Export the users to a CSV file, run a user import job and let users sign in with their old passwords.
    • C. Create every user with AdminCreateUser and a temporary password while suppressing the invitation message.
    • D. Add a pre authentication trigger that copies the legacy password hash into a custom attribute at each sign-in.
  2. An API behind an API Gateway Cognito authorizer needs a tenant_id claim in the access tokens that users present. The value comes from a DynamoDB lookup at sign-in. Which TWO steps are required? (Select TWO.)
    • A. Add a post authentication trigger that returns tenant_id in its response.
    • B. Store the value in a custom:tenant_id attribute and read it from the access token.
    • C. Configure a pre token generation trigger with event version V2_0 that sets the claim under accessTokenGeneration.
    • D. Make sure that the user pool is on the Essentials or Plus feature plan.
    • E. Enable token revocation on the app client.
Answers
  1. A. Just-in-time migration validates the old password once and creates a confirmed user with it. B: CSV import can't carry passwords, so imported users must reset; C forces a password change; D can't log anyone in, since Cognito never sees the legacy hash format.
  2. C, D. Access-token claims need a V2 (or V3) pre token generation event, which requires Essentials or Plus. A: post authentication can't change tokens; B: custom attributes reach the ID token only; E: revocation has nothing to do with claims.

5. Managed login domains and OAuth flows

Concept

Exam facts

Developer angle

Authorization code grant with PKCE (split over lines for reading; one URL in practice):

https://auth.example.com/oauth2/authorize?response_type=code&client_id=1example23456789
  &redirect_uri=https%3A%2F%2Fapp.example.com%2Fcallback&scope=openid+email+orders%2Fread
  &state=4f1c9a2b&code_challenge_method=S256&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
# Swap the code for tokens (public client: code_verifier instead of a secret)
curl -s -X POST https://auth.example.com/oauth2/token -H "Content-Type: application/x-www-form-urlencoded" \
  -d grant_type=authorization_code -d client_id=1example23456789 -d code="$AUTH_CODE" \
  --data-urlencode redirect_uri=https://app.example.com/callback -d code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
# Machine-to-machine: confidential client, custom scopes only, access token only
curl -s -X POST https://auth.example.com/oauth2/token -u "7m2mclient890abc:$CLIENT_SECRET" \
  -H "Content-Type: application/x-www-form-urlencoded" -d grant_type=client_credentials -d scope=orders/read
# Resource server with two custom scopes
aws cognito-idp create-resource-server --user-pool-id eu-west-1_Example1 --identifier orders --name OrdersAPI \
  --scopes ScopeName=read,ScopeDescription=ReadOrders ScopeName=write,ScopeDescription=WriteOrders
# Custom domain with managed login; certificate in us-east-1; the response's CloudFrontDomain is the alias target
aws cognito-idp create-user-pool-domain --user-pool-id eu-west-1_Example1 --domain auth.example.com \
  --managed-login-version 2 \
  --custom-domain-config CertificateArn=arn:aws:acm:us-east-1:111122223333:certificate/a1b2c3d4-5678-90ab-cdef-EXAMPLE11111
# Default branding style for an app client created with the API
aws cognito-idp create-managed-login-branding --user-pool-id eu-west-1_Example1 \
  --client-id 1example23456789 --use-cognito-provided-values

Traps

Practice questions

  1. A single-page application signs users in through managed login. It needs refresh tokens, and tokens must never appear in the browser's address bar or history. Which OAuth 2.0 grant should the application use?
    • A. Implicit grant with response_type=token.
    • B. Authorization code grant with PKCE.
    • C. Client credentials grant called from the browser.
    • D. USER_PASSWORD_AUTH with the password kept in local storage.
  2. A company wants its managed login pages at https://login.example.com for a user pool in eu-central-1. Which TWO actions are required? (Select TWO.)
    • A. Request a public ACM certificate for login.example.com in us-east-1.
    • B. Request a public ACM certificate for login.example.com in eu-central-1.
    • C. Create a CloudFront distribution that uses the user pool's prefix domain as its origin.
    • D. Create a DNS alias record that points login.example.com to the CloudFront domain that Cognito returns.
    • E. Upload the certificate to IAM and reference its ARN in the user pool domain.
Answers
  1. B. The code travels in the URL, but the tokens come back from the token endpoint, and PKCE binds the code to the app that started the flow. A puts tokens in the URL fragment without a refresh token; C needs a secret and issues no user tokens; D stores the password in the browser.
  2. A, D. Cognito creates and manages the CloudFront distribution, so you only supply a us-east-1 ACM certificate and the DNS alias. B is the wrong Region; C duplicates what Cognito already runs; E: user pool domains take ACM certificates, not IAM server certificates.

6. Feature plans and threat protection

Concept

Exam facts

Developer angle

Start in audit mode on the Plus plan, then define the responses for full-function mode:

# UpdateUserPool resets omitted settings: include your current configuration as well
aws cognito-idp update-user-pool --user-pool-id eu-west-1_Example1 \
  --user-pool-tier PLUS --user-pool-add-ons AdvancedSecurityMode=AUDIT
aws cognito-idp set-risk-configuration --cli-input-json file://risk.json
aws cognito-idp admin-list-user-auth-events --user-pool-id eu-west-1_Example1 --username maria@example.com --max-results 10

risk.json (notifications off here; turning them on needs a NotifyConfiguration with an SES identity):

{
  "UserPoolId": "eu-west-1_Example1",
  "CompromisedCredentialsRiskConfiguration": {
    "EventFilter": ["SIGN_IN", "SIGN_UP", "PASSWORD_CHANGE"], "Actions": { "EventAction": "BLOCK" } },
  "AccountTakeoverRiskConfiguration": { "Actions": {
    "LowAction":    { "EventAction": "NO_ACTION",         "Notify": false },
    "MediumAction": { "EventAction": "MFA_IF_CONFIGURED", "Notify": false },
    "HighAction":   { "EventAction": "MFA_REQUIRED",      "Notify": false } } }
}

Traps

Practice questions

  1. A retailer wants to observe Cognito's risk assessments of real sign-ins for two weeks before blocking anything, without affecting users. Which configuration meets this requirement?
    • A. Essentials plan with a pre authentication trigger that writes each source IP address to CloudWatch Logs.
    • B. Plus plan with AdvancedSecurityMode set to ENFORCED and every risk level set to block.
    • C. Essentials plan with CloudTrail data events turned on for the user pool.
    • D. Plus plan with AdvancedSecurityMode set to AUDIT.
  2. A user pool must block sign-ins that use passwords found in public breaches and must require MFA for high-risk sign-ins. The custom app signs users in with USER_SRP_AUTH, and MFA is set to optional. Which TWO changes are needed? (Select TWO.)
    • A. Set MFA to required for all users.
    • B. Move to the Plus plan and enable full-function threat protection with compromised-credential blocking and MFA_REQUIRED for high risk.
    • C. Switch the app's sign-in flow from USER_SRP_AUTH to USER_PASSWORD_AUTH.
    • D. Associate an AWS WAF rate-based rule with the user pool.
    • E. Add a pre token generation trigger that compares passwords with a breach list.
Answers
  1. D. Audit-only mode scores and logs every event with no automatic response. A logs data but produces no risk scores; B blocks users immediately; C records API calls, not sign-in risk.
  2. B, C. Plus with full-function mode provides both responses, and the breached-password check only works in password flows. A breaks risk-based MFA (it needs Optional); D limits request rates, not breached passwords; E: the trigger never receives the password.

7. ALB authentication with Cognito and OIDC

Concept

Exam facts

Developer angle

Authenticate, then forward (aws elbv2 create-rule … --actions file://auth-actions.json):

[
  { "Type": "authenticate-cognito", "Order": 1,
    "AuthenticateCognitoConfig": {
      "UserPoolArn": "arn:aws:cognito-idp:eu-west-1:111122223333:userpool/eu-west-1_Example1",
      "UserPoolClientId": "4alb2client3456789", "UserPoolDomain": "auth.example.com",
      "OnUnauthenticatedRequest": "authenticate", "Scope": "openid email", "SessionTimeout": 28800 } },
  { "Type": "forward", "Order": 2,
    "TargetGroupArn": "arn:aws:elasticloadbalancing:eu-west-1:111122223333:targetgroup/web/0123456789abcdef" }
]

Bearer-token validation for M2M callers at the ALB:

[
  { "Type": "jwt-validation", "Order": 1,
    "JwtValidationConfig": {
      "JwksEndpoint": "https://cognito-idp.eu-west-1.amazonaws.com/eu-west-1_Example1/.well-known/jwks.json",
      "Issuer": "https://cognito-idp.eu-west-1.amazonaws.com/eu-west-1_Example1",
      "AdditionalClaims": [ { "Format": "string-array", "Name": "client_id", "Values": ["7m2mclient890abc"] } ] } },
  { "Type": "forward", "Order": 2,
    "TargetGroupArn": "arn:aws:elasticloadbalancing:eu-west-1:111122223333:targetgroup/api/0123456789abcdef" }
]

Traps

Practice questions

  1. An internal reporting web app runs on EC2 instances behind an Application Load Balancer. Employees must sign in with the company's SAML 2.0 identity provider, and the developers want to write no authentication code. Which solution meets these requirements?
    • A. Add an authenticate-oidc action that points directly at the SAML identity provider's endpoints.
    • B. Add Amplify Auth to the web app and validate tokens in the application code.
    • C. Federate the SAML IdP into a Cognito user pool and add an authenticate-cognito action to the HTTPS listener rule.
    • D. Put CloudFront in front of the ALB and require signed cookies.
  2. After a developer adds an authenticate-cognito action to an ALB rule, users sign in successfully on the Cognito pages but then get a redirect error instead of the application. Which TWO changes are most likely needed? (Select TWO.)
    • A. Add https://<ALB DNS name>/oauth2/idpresponse and the CNAME variant as allowed callback URLs of the app client.
    • B. Change the listener protocol to HTTP.
    • C. Remove the client secret from the user pool app client.
    • D. Set OnUnauthenticatedRequest to allow.
    • E. Enable the authorization code grant and the openid scope on the app client.
Answers
  1. C. The user pool brokers SAML, and the ALB handles the browser flow, so the app gets signed claims without code. A: SAML isn't OIDC; B means writing auth code; D: signed cookies come from your own signing logic, not corporate sign-in.
  2. A, E. The ALB's callback must be registered, and the client must allow the code grant with openid. B: authenticate actions require HTTPS; C: the ALB needs the secret; D only skips sign-in for anonymous users.

8. Identity pools and temporary AWS credentials

Concept

Exam facts

Developer angle

Trust policy of the authenticated role:

{ "Version": "2012-10-17",
  "Statement": [{ "Effect": "Allow", "Principal": { "Federated": "cognito-identity.amazonaws.com" },
    "Action": ["sts:AssumeRoleWithWebIdentity", "sts:TagSession"],
    "Condition": {
      "StringEquals": { "cognito-identity.amazonaws.com:aud": "eu-west-1:11111111-2222-3333-4444-555555555555" },
      "ForAnyValue:StringLike": { "cognito-identity.amazonaws.com:amr": "authenticated" } } }] }

Assign the default roles (the caller needs iam:PassRole on both):

aws cognito-identity set-identity-pool-roles \
  --identity-pool-id eu-west-1:11111111-2222-3333-4444-555555555555 \
  --roles authenticated=arn:aws:iam::111122223333:role/AppAuthRole,unauthenticated=arn:aws:iam::111122223333:role/AppGuestRole

Browser or React Native code lets the SDK handle GetId, credentials and refresh:

import { S3Client } from "@aws-sdk/client-s3";
import { fromCognitoIdentityPool } from "@aws-sdk/credential-providers";

export const s3ForUser = (idToken, region = "eu-west-1") => new S3Client({
  region,
  credentials: fromCognitoIdentityPool({
    clientConfig: { region },
    identityPoolId: "eu-west-1:11111111-2222-3333-4444-555555555555",
    logins: { "cognito-idp.eu-west-1.amazonaws.com/eu-west-1_Example1": idToken },  // omit for guests
  }),
});

Traps

Practice questions

  1. A mobile app gets credentials for guest users from an identity pool with the enhanced flow. The unauthenticated role allows states:StartExecution, yet the app's call to AWS Step Functions fails. What is the cause?
    • A. Guest sessions in the enhanced flow get a scope-down session policy that doesn't include Step Functions.
    • B. The role's trust policy is missing the cognito-identity.amazonaws.com:aud condition.
    • C. The identity pool exceeded its GetId request quota.
    • D. Guest credentials from identity pools expire after 15 minutes.
  2. Users in the user pool group editors must receive an IAM role with write access, all other signed-in users a read-only role, and the client app must not be able to pick its own role. Which TWO configurations meet these requirements? (Select TWO.)
    • A. Enable the basic flow and let the app call AssumeRoleWithWebIdentity with whichever role it needs.
    • B. Attach the write role's ARN, with a precedence value, to the editors group in the user pool.
    • C. Map a user-writable custom attribute custom:role to role-selection rules.
    • D. Set the identity pool's authenticated role selection to choose the role from the token, with ambiguous role resolution set to the default (read-only) authenticated role.
    • E. Create IAM users for the editors and give them access keys.
Answers
  1. A. Step Functions isn't in the guest scope-down list, so the session can't use it whatever the role says; front it with API Gateway (allowed) or use the basic flow. B would stop the role being assumed at all; C would fail GetId, not the Step Functions call; D: enhanced-flow credentials last 1 hour.
  2. B, D. The group's role arrives in the ID token, and the identity pool honours it with a safe fallback. A gives the client free choice of role; C lets users elevate themselves; E abandons Cognito for long-term keys.

9. STS AssumeRole and cross account access

Concept

Exam facts

STS API Who calls it Typical use Credential lifetime
AssumeRole IAM user or role session Delegation in or across accounts 900 s up to the role's maximum (1–12 h), default 1 h
AssumeRoleWithSAML Anyone with a SAML assertion from a trusted IdP Workforce SAML federation same as AssumeRole
AssumeRoleWithWebIdentity Anyone with an OIDC token from a trusted IdP Identity pools, CI/CD with OIDC same as AssumeRole
GetSessionToken IAM user (root possible, not recommended) MFA-protected API calls (§10) 15 min–36 h, default 12 h (root ≤ 1 h)
GetFederationToken IAM user (root possible) Custom identity broker 15 min–36 h, default 12 h (root ≤ 1 h)
GetCallerIdentity Anyone "Who am I?" — needs no permission —
DecodeAuthorizationMessage Caller with sts:DecodeAuthorizationMessage Decode an encoded authorization failure —
GetAccessKeyInfo Any IAM principal Which account owns an access key ID (AKIA… long-term, ASIA… temporary) —
AssumeRoot Organizations management account or delegated admin Privileged root task on a member account ≤ 900 s

Developer angle

Account B (444455556666) owns the role; account A (111122223333) runs the caller. Trust policy of AuditReadOnly in account B, then the identity policy on nightly-audit in account A:

{ "Version": "2012-10-17",
  "Statement": [{ "Effect": "Allow", "Action": "sts:AssumeRole",
                  "Principal": { "AWS": "arn:aws:iam::111122223333:role/nightly-audit" } }] }
{ "Version": "2012-10-17",
  "Statement": [{ "Effect": "Allow", "Action": "sts:AssumeRole",
                  "Resource": "arn:aws:iam::444455556666:role/AuditReadOnly" }] }

Third-party variant: the vendor's account in Principal, plus "Condition": {"StringEquals": {"sts:ExternalId": "<value the vendor gave you>"}}.

aws sts assume-role --role-arn arn:aws:iam::444455556666:role/AuditReadOnly \
  --role-session-name nightly-audit --duration-seconds 3600
aws iam update-role --role-name AuditReadOnly --max-session-duration 14400   # 4 h, in account B
aws sts get-caller-identity          # with the new credentials: ...:assumed-role/AuditReadOnly/nightly-audit

Traps

Practice questions

  1. A Lambda function in account A must stop and tag EC2 instances in account B every night. The security team forbids long-term credentials. Which solution follows least privilege?
    • A. Create an IAM user in account B, store its access keys in Secrets Manager in account A and read them in the function.
    • B. Add a resource-based policy to the function that allows account B to invoke it, and make the EC2 calls under that permission.
    • C. Add account B's root principal to the trust policy of the function's execution role.
    • D. Create a role in account B that trusts the execution role and allows only the needed EC2 actions, and have the function assume it.
  2. A developer in account A runs aws sts assume-role for a role in account B and receives AccessDenied. The role's trust policy names account A as its principal. Which TWO causes are possible? (Select TWO.)
    • A. The developer's identity-based policies don't allow sts:AssumeRole on the role's ARN.
    • B. The role's permissions policy doesn't allow the S3 actions the developer plans to run.
    • C. The trust policy has an sts:ExternalId or MFA condition that the request doesn't satisfy.
    • D. The role's maximum session duration is set to 12 hours.
    • E. Account A has a bucket policy that denies principals from account B.
Answers
  1. D. A narrowly scoped role in B, trusted by one execution role (which also needs sts:AssumeRole on it) and assumed on demand, uses only temporary credentials. A relies on long-term keys; B lets account B invoke the function but gives the function no rights in account B; C reverses the trust direction (it would let B assume A's role).
  2. A, C. Cross-account assumption needs the caller's own permission, and every trust condition must be met. B affects later calls, not the assumption; D only allows longer sessions; E is unrelated to STS.

10. STS with MFA

Concept

Exam facts

Developer angle

Allow destructive EC2 actions only with MFA done within the last hour, and deny them otherwise:

{
  "Version": "2012-10-17",
  "Statement": [
    { "Sid": "AllowWithRecentMfa", "Effect": "Allow",
      "Action": ["ec2:StopInstances", "ec2:TerminateInstances"], "Resource": "*",
      "Condition": { "Bool": { "aws:MultiFactorAuthPresent": "true" },
                     "NumericLessThan": { "aws:MultiFactorAuthAge": "3600" } } },
    { "Sid": "DenyWithoutMfa", "Effect": "Deny",
      "Action": ["ec2:StopInstances", "ec2:TerminateInstances"], "Resource": "*",
      "Condition": { "BoolIfExists": { "aws:MultiFactorAuthPresent": "false" } } }
  ]
}
# Long-term keys + MFA code -> 8-hour session credentials
aws sts get-session-token --serial-number arn:aws:iam::111122223333:mfa/maria --token-code 123456 --duration-seconds 28800
export AWS_ACCESS_KEY_ID="<AccessKeyId>" AWS_SECRET_ACCESS_KEY="<SecretAccessKey>" AWS_SESSION_TOKEN="<SessionToken>"
aws ec2 stop-instances --instance-ids i-0123456789abcdef0
# Role whose trust policy requires MFA
aws sts assume-role --role-arn arn:aws:iam::444455556666:role/ProdAdmin --role-session-name maria \
  --serial-number arn:aws:iam::111122223333:mfa/maria --token-code 123456

Traps

Practice questions

  1. A policy statement denies ec2:TerminateInstances with the condition "Bool": {"aws:MultiFactorAuthPresent": "false"}. A nightly script that uses an IAM user's long-term access keys can still terminate instances. What should the developer change?
    • A. Change the Deny condition to "Bool": {"aws:MultiFactorAuthPresent": "true"}.
    • B. Change the Deny condition operator to BoolIfExists with the value "false".
    • C. Add a second Allow statement for ec2:TerminateInstances that requires "Bool": {"aws:MultiFactorAuthPresent": "true"}.
    • D. Attach the policy to the script user's IAM group instead of the user.
  2. A developer with an IAM user must run AWS CLI commands that are protected by MFA conditions for a full 8-hour working day without typing another code. Which TWO steps meet the requirement? (Select TWO.)
    • A. Call aws sts get-session-token without MFA parameters and rely on the MFA device registered for the user.
    • B. Call aws sts get-session-token from an EC2 instance role to obtain MFA credentials.
    • C. Call aws sts get-session-token with --serial-number, --token-code and --duration-seconds 28800.
    • D. Request --duration-seconds 172800 so that the credentials last two days.
    • E. Use the returned access key ID, secret access key and session token for the following commands.
Answers
  1. B. With BoolIfExists, a missing MFA key counts as a match, so requests signed with long-term keys are denied too. A would deny MFA users instead; C adds an allow, and an extra allow never removes the permission the script already has; D only moves the same flawed statement.
  2. C, E. One MFA-backed session of 8 hours (within the 36-hour limit), reused for every command. A yields credentials without MFA context; B: roles can't call GetSessionToken; D exceeds the 129,600-second maximum.

11. Policy evaluation logic

Concept

Exam facts

Developer angle

Bucket policy in the same account: grants the app role access and denies non-TLS requests for everyone:

{
  "Version": "2012-10-17",
  "Statement": [
    { "Sid": "AllowReportsApp", "Effect": "Allow",
      "Principal": { "AWS": "arn:aws:iam::111122223333:role/ReportsAppRole" },
      "Action": ["s3:GetObject", "s3:PutObject"], "Resource": "arn:aws:s3:::reports-bucket/*" },
    { "Sid": "DenyInsecureTransport", "Effect": "Deny", "Principal": "*", "Action": "s3:*",
      "Resource": ["arn:aws:s3:::reports-bucket", "arn:aws:s3:::reports-bucket/*"],
      "Condition": { "Bool": { "aws:SecureTransport": "false" } } }
  ]
}

Check what a role may do before deploying:

aws iam simulate-principal-policy --policy-source-arn arn:aws:iam::111122223333:role/ReportsAppRole \
  --action-names s3:GetObject s3:DeleteObject --resource-arns arn:aws:s3:::reports-bucket/2026/q3.csv \
  --query 'EvaluationResults[].{action:EvalActionName,decision:EvalDecision}'

Traps

Practice questions

  1. An EC2 instance role allows s3:* on the bucket reports. The bucket policy denies all principals when aws:SourceVpce isn't the company's VPC endpoint. The application on the instance reaches S3 through a NAT gateway and receives AccessDenied. What is the reason?
    • A. Identity-based policies are ignored whenever the bucket has a bucket policy.
    • B. The bucket policy must also contain an Allow statement that names the role.
    • C. The explicit deny in the bucket policy applies, and an explicit deny overrides the role's allow.
    • D. S3 evaluates only the bucket policy for requests that arrive through a NAT gateway.
  2. A developer's role in account A must read objects encrypted with SSE-S3 from a bucket in account B. Which TWO policies must allow the access? (Select TWO.)
    • A. A service control policy in account A that grants s3:GetObject.
    • B. The bucket policy in account B, naming the developer's role or account A as principal.
    • C. A permissions boundary on a role in account B.
    • D. An identity-based policy on the developer's role that allows s3:GetObject on the bucket's objects.
    • E. A resource control policy in account A that grants s3:GetObject.
Answers
  1. C. Requests through the NAT gateway carry no matching aws:SourceVpce, the deny condition matches, and an explicit deny beats any allow. A and D are false statements about evaluation; B: in the same account the role's identity policy already allows, so a missing bucket allow isn't the issue.
  2. B, D. Cross-account access needs the resource-based policy in B and the identity policy in A. A and E: SCPs and RCPs never grant; C: boundaries in B don't apply to A's role. (With SSE-KMS the key policy would also have to allow.)

12. Dynamic policies and policy variables

Concept

Exam facts

Developer angle

Per-user home folders for an IAM group:

{
  "Version": "2012-10-17",
  "Statement": [
    { "Sid": "ListOwnHomeFolder", "Effect": "Allow", "Action": "s3:ListBucket",
      "Resource": "arn:aws:s3:::team-files",
      "Condition": { "StringLike": { "s3:prefix": ["home/${aws:username}/*"] } } },
    { "Sid": "ManageOwnObjects", "Effect": "Allow",
      "Action": ["s3:GetObject", "s3:PutObject", "s3:DeleteObject"],
      "Resource": "arn:aws:s3:::team-files/home/${aws:username}/*" }
  ]
}

Per-identity items for an identity pool's authenticated role:

{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Action": ["dynamodb:GetItem", "dynamodb:PutItem", "dynamodb:UpdateItem", "dynamodb:Query"],
    "Resource": "arn:aws:dynamodb:eu-west-1:111122223333:table/UserNotes",
    "Condition": { "ForAllValues:StringEquals": { "dynamodb:LeadingKeys": ["${cognito-identity.amazonaws.com:sub}"] } }
  }]
}

Traps

Practice questions

  1. An ECS task role has a policy that allows s3:GetObject on arn:aws:s3:::docs/home/${aws:username}/*. Every request from the task is denied. What is the reason?
    • A. aws:username isn't present in requests made by role sessions, so the resource never matches.
    • B. Policy variables are allowed only in the Condition element.
    • C. The policy needs "Version": "2008-10-17" to support variables.
    • D. Amazon S3 doesn't support policy variables in identity-based policies.
  2. Each IAM user in the analysts group must list and manage only the objects under home/<user name>/ in the bucket team-files, using a single group policy. Which TWO statements should the policy contain? (Select TWO.)
    • A. s3:ListBucket on arn:aws:s3:::team-files with a StringLike condition on s3:prefix of home/${aws:username}/*.
    • B. s3:ListBucket on arn:aws:s3:::team-files/home/${aws:username}/*.
    • C. s3:* on arn:aws:s3:::team-files/* with "Version": "2008-10-17".
    • D. s3:GetObject, s3:PutObject and s3:DeleteObject on arn:aws:s3:::team-files/home/${aws:username}/*.
    • E. s3:GetObject on arn:aws:s3:::team-files/home/* with a StringEquals condition on aws:userid.
Answers
  1. A. Role sessions have no aws:username, so the variable stays unresolved and the statement matches nothing; use principal or session tags. B: variables also work in Resource; C: the old version disables variables; D: S3 supports them.
  2. A, D. Listing is a bucket-level action filtered by s3:prefix; object actions use the per-user object ARN. B targets the wrong resource for listing; C grants every object and disables the variable; E: aws:userid is an opaque ID, not the folder name, and the resource covers everyone's folders.

13. Managed vs inline policies and passing roles

Concept

Exam facts

Developer angle

Customer managed policy lifecycle and an inline policy for comparison:

aws iam create-policy --policy-name orders-rw --policy-document file://orders-rw.json
aws iam attach-role-policy --role-name orders-fn-role --policy-arn arn:aws:iam::111122223333:policy/orders-rw
aws iam create-policy-version --policy-arn arn:aws:iam::111122223333:policy/orders-rw \
  --policy-document file://orders-rw-v2.json --set-as-default
aws iam set-default-policy-version --policy-arn arn:aws:iam::111122223333:policy/orders-rw --version-id v1   # roll back
aws iam put-role-policy --role-name orders-fn-role --policy-name kms-decrypt \
  --policy-document file://kms-decrypt.json         # inline: lives and dies with the role

What a developer needs to deploy functions with pre-approved execution roles:

{
  "Version": "2012-10-17",
  "Statement": [
    { "Sid": "ManageOrderFunctions", "Effect": "Allow",
      "Action": ["lambda:CreateFunction", "lambda:UpdateFunctionConfiguration"],
      "Resource": "arn:aws:lambda:eu-west-1:111122223333:function:orders-*" },
    { "Sid": "PassOnlyLambdaRoles", "Effect": "Allow", "Action": "iam:PassRole",
      "Resource": "arn:aws:iam::111122223333:role/lambda/orders-*",
      "Condition": { "StringEquals": { "iam:PassedToService": "lambda.amazonaws.com" } } },
    { "Sid": "SeeTheRoles", "Effect": "Allow", "Action": "iam:GetRole",
      "Resource": "arn:aws:iam::111122223333:role/lambda/orders-*" }
  ]
}

Traps

Practice questions

  1. A developer runs aws lambda create-function with an existing execution role and gets AccessDenied … is not authorized to perform: iam:PassRole on resource: arn:aws:iam::111122223333:role/orders-fn-role. Which change fixes the error with least privilege?
    • A. Attach AWSLambda_FullAccess to the execution role.
    • B. Add lambda.amazonaws.com to the trust policy of the developer's own role.
    • C. Allow the developer iam:PassRole on that role's ARN with iam:PassedToService set to lambda.amazonaws.com.
    • D. Allow the developer sts:AssumeRole on the execution role.
  2. A platform team maintains one set of permissions used by 30 IAM roles. The team needs a change history and a way to undo a bad change within minutes. Which TWO practices meet these requirements? (Select TWO.)
    • A. Copy the permissions into an inline policy on each role.
    • B. Store the permissions in one customer managed policy attached to all 30 roles.
    • C. Edit the AWS managed PowerUserAccess policy to add the permissions.
    • D. Keep a new policy version for every change, up to 10 versions per policy.
    • E. Roll back by setting a previous policy version as the default version.
Answers
  1. C. The caller needs permission to pass exactly this role, narrowed to Lambda. A changes the role's own permissions, not the caller's; B confuses the developer's role with the execution role's trust; D lets the developer act as the role, which isn't what creating a function checks.
  2. B, E. A customer managed policy keeps versions, and switching the default version undoes a change for every attached role at once. A has no versions and must be edited 30 times; C: AWS managed policies can't be edited; D: the limit is 5 versions.

14. AWS Directory Service

Concept

Exam facts

Need Choose
Real AD in AWS for AD-aware apps, SharePoint, trusts with on-premises AD, or RDS for SQL Server Windows auth without running your own domain controllers AWS Managed Microsoft AD
Keep using on-premises AD for WorkSpaces, console sign-in or EC2 domain join, with no directory data in AWS AD Connector
Small, cheap standalone directory with basic AD features or LDAP for Linux apps Simple AD (existing customers only); new customers: Managed Microsoft AD Standard
Extend a self-managed AD into AWS with the same identities Managed Microsoft AD Hybrid Edition
Sign-up and sign-in for app customers, social logins Amazon Cognito (not Directory Service)

Developer angle

Creating directories from the CLI (network prerequisites are out of scope):

# Real AD managed by AWS (Standard edition)
aws ds create-microsoft-ad --name corp.example.com --password 'Adm1n-Passw0rd-2026' --edition Standard \
  --vpc-settings VpcId=vpc-0abc1234def567890,SubnetIds=subnet-0aaa1111bbb22222c,subnet-0ddd3333eee44444f
# Proxy to the on-premises domain (users stay on premises)
aws ds connect-directory --name corp.example.com --password 'Svc-Passw0rd-2026' --size Small \
  --connect-settings VpcId=vpc-0abc1234def567890,SubnetIds=subnet-0aaa1111bbb22222c,subnet-0ddd3333eee44444f,CustomerDnsIps=10.0.0.10,CustomerUserName=svc-adconnector
aws ds describe-directories --query 'DirectoryDescriptions[].{Id:DirectoryId,Type:Type,Name:Name,Stage:Stage}'

Traps

Practice questions

  1. A company wants Amazon WorkSpaces users to sign in with their existing on-premises Active Directory credentials and wants EC2 Windows instances to join the on-premises domain. No directory data may be stored in AWS, and operational overhead must be minimal. Which option meets these requirements?
    • A. Simple AD with a trust relationship to the on-premises domain.
    • B. AWS Managed Microsoft AD with all users re-created in the new domain.
    • C. An Amazon Cognito user pool federated with the on-premises AD through SAML.
    • D. AD Connector pointing at the on-premises domain controllers.
  2. A company has run Simple AD for years for its Windows and Linux EC2 instances. Which TWO new requirements would force a move to AWS Managed Microsoft AD? (Select TWO.)
    • A. A trust relationship with a partner's existing Active Directory.
    • B. Joining Linux EC2 instances to the domain.
    • C. RADIUS-based multi-factor authentication for directory users.
    • D. Kerberos-based single sign-on for domain users.
    • E. Group policies for the Windows instances.
Answers
  1. D. AD Connector proxies authentication and domain join to the existing AD and stores no directory data. A: Simple AD can't trust other domains; B duplicates the directory in AWS; C: WorkSpaces and domain join need AD, not a user pool.
  2. A, C. Trusts and RADIUS MFA are beyond Simple AD. B, D and E are basic AD features that Simple AD already provides.

Quick decision rules

Cognito (§1–§8)

STS and policies (§9–§14)

Changed vs older material

Learn the Current column; older practice material may still show the Older material may say value. After you confirm them, these rows (with verification dates) also live in notes/current-facts.md.

Topic Older material may say Current (verified 2026-10-12) Source
§1 · Cognito Sync Use Cognito Sync to sync user data across devices No longer open to new customers; use AWS AppSync or DynamoDB AWS docs
§3 · Refresh tokens Refresh tokens are never rotated; refresh with REFRESH_TOKEN_AUTH Optional rotation per app client (RefreshTokenRotation, grace ≤ 60 s) through GetTokensFromRefreshToken or the token endpoint; REFRESH_TOKEN_AUTH not allowed with rotation; expiry window unchanged AWS docs
§4 · Pre token generation trigger Adds or removes claims in ID tokens only V1_0 ID token (+ group override); V2_0 ID and access tokens (claims, scopes); V3_0 adds M2M tokens; V2/V3 need Essentials or Plus AWS docs
§5 · Hosted UI Hosted sign-in pages customisable only with a logo and a CSS file Managed login (22 Nov 2024): branding editor, passkeys, localisation, Essentials/Plus; classic hosted UI still in all plans and the only option in Lite; one branding version per domain AWS docs
§5 · Custom domain setup Defined in the console's "App integration" section Console Branding → Domain; API CreateUserPoolDomain with CustomDomainConfig; certificate still in us-east-1 AWS docs
§6 · User pool pricing model One per-user price plus an optional advanced security features add-on Feature plans Lite / Essentials / Plus since 22 Nov 2024; Essentials is the default for new pools AWS docs
§6 · Advanced security features Separately priced add-on; compromised-credential blocking shown as a basic user pool feature Now in Essentials or Plus; threat protection (adaptive auth, compromised credentials, log export) is Plus only; AUDIT/ENFORCED requires tier PLUS AWS docs
§7 · ALB user-claims headers x-amzn-oidc-accesstoken, x-amzn-oidc-identity and x-amzn-oidc-data are equally usable Only x-amzn-oidc-data is signed (ES256; check signer); the other two are legacy unsigned headers AWS docs
§7 · Token validation at the ALB The ALB only authenticates browser users; APIs validate JWTs in code or API Gateway jwt-validation rule action (12 Nov 2025) verifies RS256 JWTs (iss, exp, up to 10 claims) on HTTPS listeners AWS docs
§8 · STS call behind identity pools "AssumeRoleForWebIdentity" sts:AssumeRoleWithWebIdentity; Cognito makes the call itself in the enhanced flow (GetCredentialsForIdentity) AWS docs
§9 · STS credential lifetime Temporary credentials last 15 minutes to 1 hour AssumeRole*: default 1 h, 900 s up to the role's maximum (1–12 h); role chaining ≤ 1 h; GetSessionToken / GetFederationToken: 15 min–36 h, default 12 h (root ≤ 1 h) AWS docs
§9 · AssumeRoleWithWebIdentity guidance AWS recommends against calling it; use Cognito identity pools instead Cognito recommended for mobile apps; calling it directly is a documented best-practice path for workloads with an OIDC IdP (e.g. CI/CD) AWS docs
§9 · STS API set Seven operations (AssumeRole, AssumeRoleWithSAML, AssumeRoleWithWebIdentity, GetSessionToken, GetFederationToken, GetCallerIdentity, DecodeAuthorizationMessage) Also AssumeRoot (privileged root task in a member account, ≤ 900 s, Regional endpoint) and GetAccessKeyInfo AWS docs
§9 · STS global endpoint sts.amazonaws.com is always served from us-east-1 Served in the originating Region for Regions enabled by default (Amazon DNS); opt-in Regions and other resolvers still go to us-east-1; Regional endpoints recommended AWS docs
§11 · Policy types in evaluation Explicit deny → allow → implicit deny over identity and resource policies (plus SCPs, boundaries, session policies) Adds resource control policies (13 Nov 2024; launched for 5 services, now dozens): explicit deny → RCPs → SCPs → resource-based → identity-based → permissions boundary → session policy AWS docs
§13 · IAM managed-policy and trust-policy quotas 10 managed policies per role (max 20); trust policy max 4,096 characters 20 per role (adjustable to 25); users 10 (to 20); groups 10 (fixed); trust policy 2,048 by default (adjustable to 8,192) AWS docs
§13 · ECS task roles Always set ECS_ENABLE_TASK_IAM_ROLE=true Current ECS-optimized AMIs support task roles out of the box; the variable is for non-optimized AMIs and external instances; Fargate always uses task roles AWS docs
§13 · Long-term access keys Acceptable on a personal computer or an on-premises server Temporary credentials for humans (IAM Identity Center, federation) and workloads (roles, IAM Roles Anywhere, OIDC/SAML); keys only where roles are impossible AWS docs
§14 · Directory types Managed Microsoft AD, AD Connector, Simple AD Plus AWS Managed Microsoft AD (Hybrid Edition, 30 Jul 2025) to extend a self-managed AD into AWS AWS docs
§14 · Simple AD availability Simple AD is the low-cost choice for any account Closed to new customers since 30 Jul 2026; existing customers keep full functionality and can still create directories; new customers use Managed Microsoft AD or AD Connector AWS docs