☰ All modules Tier 1 · IAM GuideCheat sheet cli-sdk-policies ›
Contents
  1. How IAM appears on DVA-C02
  2. 1. Root user and account protection
  3. 2. IAM users and user groups
  4. 3. IAM roles for AWS services
  5. 4. Policy document structure
  6. 5. Policy conditions and condition keys
  7. 6. Testing and troubleshooting policies
  8. 7. Password policy
  9. 8. MFA devices and enforcement
  10. 9. Access keys and programmatic access
  11. 10. Credential report and last accessed information
  12. 11. IAM Access Analyzer findings and policy generation
  13. 12. Best practices and shared responsibility
  14. Quick decision rules
  15. Changed vs older material

IAM — DVA-C02 Mastery Guide

  • Sources: course chapter 01 (IAM). The slides serve 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 from older practice tests: learn the current value. ⚠️ unverified marks anything that could not be confirmed in AWS documentation. Every change is listed in Changed vs older material; rows enter notes/current-facts.md once you confirm them.
  • Tier 1 (highest exam weight), bank target 30 questions. Domain: Security.
  • Scope: users, groups and roles; policy JSON structure (Effect, Action, Resource, Condition); MFA and access keys; IAM security tools (credential report, last accessed information, IAM Access Analyzer); shared responsibility. Covered elsewhere: STS (AssumeRole, session durations), cross-account access, iam:PassRole, the full policy evaluation logic, inline vs managed policies and policy variables → notes/advanced-identity-guide.md; CLI profiles, credential provider chains, MFA with the CLI (sts get-session-token), SigV4, the IAM policy simulator, dry runs, reading AccessDenied messages and decode-authorization-message → notes/cli-sdk-policies-guide.md §11–§12; instance profiles and IMDS → notes/ec2-mastery-guide.md §1–§2.
  • How to use it: /explain <topic> teaches from these sections (concept → exam facts → developer angle → traps → 3 check questions); /quiz iam asks bank questions whose source_note links point at the ## N. headings below; /drill iam fires short recall prompts from notes/iam-cheat-sheet.md. Suggested loop: read a section, answer its practice questions before opening the answers, /explain what is still unclear, then /quiz iam and /drill iam.

How IAM appears on DVA-C02

IAM is the authorization layer behind every other service on the exam, so it appears both as its own topic and inside Lambda, S3, DynamoDB or CI/CD scenarios. A question describes code, a pipeline or a person that is blocked, over-privileged or holding the wrong kind of credential, and asks for the fix. What you must get right:

Typical question shapes: a scenario with one deciding constraint ("MOST secure", "least privilege", "LEAST operational overhead"); a policy excerpt or an error message to diagnose; "Which TWO…" with five options; the exact API action, CLI command, condition key or setting that does the job.

Domain map: the bank for this module is tagged Security. Scenarios often borrow Development framing (an SDK call fails with AccessDenied) or Troubleshooting framing (§6, §10).

Out of scope here: AWS Organizations design beyond the guardrail facts in §1 and §12, directory services, and network design (only the condition keys that mention VPC endpoints or IP ranges appear).

# Topic Why it is on the exam
1 Root user and account protection Root-only tasks, mandatory root MFA, no root keys, unlocking resources with centralized root access
2 IAM users and user groups When an IAM user is still the right identity, how groups grant permissions, quotas, the DeleteConflict cleanup
3 IAM roles for AWS services Trust policy vs permissions policy, service roles vs service-linked roles: how code on AWS gets permissions
4 Policy document structure Effect, Action, Resource and Principal; statements that grant nothing or too much; managed policy versions
5 Policy conditions and condition keys MFA, source IP, Region, TLS and tag conditions; missing-key behaviour and ...IfExists
6 Testing and troubleshooting policies Access Analyzer validation and custom checks as CI gates, eventual consistency, console policy warnings
7 Password policy Default vs custom rules, what applies immediately, the CLI's no-partial-update trap
8 MFA devices and enforcement Passkeys first, 8 devices per user, MFA for CLI calls, enforcing MFA in policies
9 Access keys and programmatic access Temporary credentials first; key anatomy, zero-downtime rotation, last-used data, leaked keys
10 Credential report and last accessed information Which audit tool answers which question; report contents and tracking periods
11 IAM Access Analyzer findings and policy generation External, internal and unused access findings; least-privilege policies drafted from CloudTrail
12 Best practices and shared responsibility The current AWS IAM best-practice list and who secures what

1. Root user and account protection

Concept

Exam facts

Developer angle

Unlock a bucket that a bad policy has closed to everyone in member account 111122223333, working from the delegated IAM administrator account:

# 1) task-scoped root session for the member account (Regional endpoint, at most 900 s)
aws sts assume-root --region eu-west-1 \
  --target-principal 111122223333 \
  --task-policy-arn arn=arn:aws:iam::aws:policy/root-task/S3UnlockBucketPolicy \
  --duration-seconds 900 \
  --query Credentials --output json > root-session.json

# 2) use the session, then fix the policy properly as a normal admin afterwards
export AWS_ACCESS_KEY_ID=$(jq -r .AccessKeyId root-session.json)
export AWS_SECRET_ACCESS_KEY=$(jq -r .SecretAccessKey root-session.json)
export AWS_SESSION_TOKEN=$(jq -r .SessionToken root-session.json)
aws s3api delete-bucket-policy --bucket locked-reports-bucket

Traps

Practice questions

  1. A company uses AWS Organizations with centralized root access enabled, and the root credentials of all member accounts have been deleted. In member account 111122223333, a faulty bucket policy now denies every principal access to a bucket. A developer in the delegated IAM administrator account must remove the policy with the LEAST operational overhead. What should the developer do?

    • A. Run the Allow password recovery task, reset the member root password, sign in as root and delete the bucket policy.
    • B. Call sts:AssumeRoot on a Regional endpoint with the S3UnlockBucketPolicy task policy, then delete the bucket policy with the session credentials.
    • C. Assume the OrganizationAccountAccessRole role in the member account and run aws s3api delete-bucket-policy.
    • D. Attach an SCP to the member account that allows s3:DeleteBucketPolicy on the bucket.
  2. A developer is hardening a new standalone AWS account that hosts a side project. Which TWO actions follow AWS guidance for the root user? (Select TWO.)

    • A. Register a passkey or a FIDO security key as an MFA device for the root user.
    • B. Create root access keys and store them in AWS Secrets Manager for automation jobs.
    • C. Set a custom IAM account password policy that requires 20-character passwords for the root user.
    • D. Create an administrative identity for everyday work and keep the root credentials for root-only tasks.
    • E. Attach a permissions boundary to the root user to cap what it can do.
Answers
  1. B. A privileged session scoped by S3UnlockBucketPolicy is exactly what centralized root access provides. A works but re-creates root credentials and adds manual steps; C fails because the bucket policy's deny also matches the administrator role; D fails because an SCP never grants permissions and cannot override the bucket's explicit deny.
  2. A, D. Phishing-resistant MFA and a separate administrative identity are root best practices. B: AWS recommends never creating root access keys; C: the password policy applies only to IAM users; E: permissions boundaries attach to IAM users and roles, never to root.

2. IAM users and user groups

Concept

Exam facts

Developer angle

aws iam create-group --group-name Backend
aws iam attach-group-policy --group-name Backend \
  --policy-arn arn:aws:iam::111122223333:policy/backend-data-access
aws iam create-user --user-name build-agent-legacy --tags Key=owner,Value=platform
aws iam add-user-to-group --user-name build-agent-legacy --group-name Backend
aws iam list-groups-for-user --user-name build-agent-legacy
aws iam list-attached-user-policies --user-name build-agent-legacy   # managed policies
aws iam list-user-policies --user-name build-agent-legacy            # inline policy names
aws iam get-account-authorization-details --filter User Group        # one dump for audits
aws iam get-account-summary                                          # usage vs IAM quotas

Removing a user in code means emptying it first (boto3):

import boto3

iam = boto3.client("iam")


def delete_user(name):
    for key in iam.list_access_keys(UserName=name)["AccessKeyMetadata"]:
        iam.delete_access_key(UserName=name, AccessKeyId=key["AccessKeyId"])
    for device in iam.list_mfa_devices(UserName=name)["MFADevices"]:
        iam.deactivate_mfa_device(UserName=name, SerialNumber=device["SerialNumber"])
    for policy in iam.list_attached_user_policies(UserName=name)["AttachedPolicies"]:
        iam.detach_user_policy(UserName=name, PolicyArn=policy["PolicyArn"])
    for policy_name in iam.list_user_policies(UserName=name)["PolicyNames"]:
        iam.delete_user_policy(UserName=name, PolicyName=policy_name)
    for group in iam.list_groups_for_user(UserName=name)["Groups"]:
        iam.remove_user_from_group(UserName=name, GroupName=group["GroupName"])
    try:
        iam.delete_login_profile(UserName=name)
    except iam.exceptions.NoSuchEntityException:
        pass  # the user never had a console password
    try:
        iam.delete_user(UserName=name)
    except iam.exceptions.DeleteConflictException as err:
        print("still attached:", err)  # e.g. signing certificates, SSH keys, Git credentials

Traps

Practice questions

  1. A developer writes a cleanup job that calls DeleteUser for contractors who have left the company. The calls fail with DeleteConflict, although the job's role has full IAM permissions. What is the MOST likely cause?

    • A. IAM is eventually consistent, so the users are not yet visible to the job.
    • B. The users belong to a group whose policy contains an explicit Deny for iam:DeleteUser.
    • C. The users still have attached items such as access keys, MFA devices or managed policies.
    • D. The job's role lacks iam:PassRole for the users being deleted.
  2. A team lead must give 12 backend developers, who sign in as IAM users, identical read/write access to one DynamoDB table and one S3 bucket in the same account, with the LEAST operational overhead. Which TWO steps meet the requirement? (Select TWO.)

    • A. Add arn:aws:iam::111122223333:group/Backend as the Principal in the bucket policy.
    • B. Create a Backend user group, attach one customer managed policy with the table and bucket permissions, and add the 12 users.
    • C. Nest the Backend group inside the existing Engineering group.
    • D. Attach an identical inline policy to each of the 12 users.
    • E. Keep the current bucket policy as it is, without adding a statement for the developers.
Answers
  1. C. DeleteConflict (HTTP 409) means subordinate entities are still attached; the CLI and API never remove them for you. A would surface as NoSuchEntity rather than a conflict; B and D would produce AccessDenied, and iam:PassRole has nothing to do with deleting users.
  2. B, E. One managed policy on a group is the low-overhead pattern, and within one account the identity-based allow is sufficient. A fails because a group can't be a principal; C fails because groups can't be nested; D works but multiplies maintenance across 12 copies.

3. IAM roles for AWS services

Concept

Exam facts

Developer angle

Create a Lambda execution role: trust first, then permissions.

cat > lambda-trust.json <<'EOF'
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": { "Service": "lambda.amazonaws.com" },
    "Action": "sts:AssumeRole"
  }]
}
EOF
aws iam create-role --role-name orders-fn-role \
  --assume-role-policy-document file://lambda-trust.json \
  --max-session-duration 3600
aws iam attach-role-policy --role-name orders-fn-role \
  --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
aws iam put-role-policy --role-name orders-fn-role --policy-name orders-table-rw \
  --policy-document file://orders-table-rw.json
aws iam update-assume-role-policy --role-name orders-fn-role \
  --policy-document file://lambda-trust.json     # replaces a wrong trust policy in place
aws iam get-role --role-name orders-fn-role --query Role.RoleLastUsed
aws iam list-roles --path-prefix /aws-service-role/ --query 'Roles[].RoleName'

Traps

Practice questions

  1. A developer creates an IAM role whose permissions policy allows dynamodb:PutItem on the Orders table, then selects it as the execution role of a new Lambda function. Lambda rejects the role because the service cannot assume it. Which change fixes the problem?

    • A. Allow sts:AssumeRole for the lambda.amazonaws.com service principal in the role's trust policy.
    • B. Add dynamodb:* on all resources to the role's permissions policy.
    • C. Increase the role's maximum session duration to 12 hours.
    • D. Attach the AWSLambdaBasicExecutionRole managed policy to the role.
  2. While reviewing roles, a developer finds AWSServiceRoleForElasticLoadBalancing under the path /aws-service-role/ and wants to reduce its permissions. Which TWO statements are correct? (Select TWO.)

    • A. Its permissions are defined by Elastic Load Balancing and cannot be edited in IAM.
    • B. A permissions boundary can be attached to it to cap its permissions.
    • C. It can be deleted only after the load balancer resources that depend on it are gone.
    • D. Any principal in the account that has sts:AssumeRole permission can assume it.
    • E. It does not count toward the account's quota of IAM roles.
Answers
  1. A. The role's trust policy must name the Lambda service principal; permissions are irrelevant until the service can assume the role. B only broadens permissions; C changes session length, not who may assume the role; D adds CloudWatch Logs permissions but still no trust.
  2. A, C. Service-linked roles are defined and owned by their service and are protected while resources depend on them. B is wrong because boundaries can't be applied to service-linked roles; D is wrong because only the linked service assumes them; E is wrong because they count toward the quota (they may merely exceed it).

4. Policy document structure

Concept

Exam facts

Developer angle

A least-privilege identity policy for an order-reporting service:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "ReadOrdersTable",
      "Effect": "Allow",
      "Action": ["dynamodb:GetItem", "dynamodb:Query"],
      "Resource": "arn:aws:dynamodb:eu-west-1:111122223333:table/Orders"
    },
    { "Sid": "ListTablesNeedsStar", "Effect": "Allow", "Action": "dynamodb:ListTables", "Resource": "*" },
    {
      "Sid": "ListReportPrefix",
      "Effect": "Allow",
      "Action": "s3:ListBucket",
      "Resource": "arn:aws:s3:::reports-bucket",
      "Condition": { "StringLike": { "s3:prefix": "2026/*" } }
    },
    {
      "Sid": "ReadWriteReportObjects",
      "Effect": "Allow",
      "Action": ["s3:GetObject", "s3:PutObject"],
      "Resource": "arn:aws:s3:::reports-bucket/2026/*"
    },
    { "Sid": "NeverDropTables", "Effect": "Deny", "Action": "dynamodb:DeleteTable", "Resource": "*" }
  ]
}
aws iam create-policy --policy-name orders-reporting --policy-document file://orders-reporting.json
aws iam create-policy-version \
  --policy-arn arn:aws:iam::111122223333:policy/orders-reporting \
  --policy-document file://orders-reporting-v2.json --set-as-default
aws iam list-policy-versions --policy-arn arn:aws:iam::111122223333:policy/orders-reporting
aws iam set-default-policy-version \
  --policy-arn arn:aws:iam::111122223333:policy/orders-reporting --version-id v1   # roll back
aws iam delete-policy-version \
  --policy-arn arn:aws:iam::111122223333:policy/orders-reporting --version-id v2

Traps

Practice questions

  1. A developer attaches this statement to a role: {"Effect": "Allow", "Action": ["s3:ListBucket", "s3:GetObject"], "Resource": "arn:aws:s3:::reports-bucket"}. Listing the bucket works, but downloading objects fails with AccessDenied. What should the developer change?

    • A. Set "Version" to "2008-10-17" in the policy.
    • B. Add a Principal element that names the role ARN.
    • C. Replace Action with NotAction, keeping the same two actions.
    • D. Add arn:aws:s3:::reports-bucket/* to the statement's Resource list.
  2. A developer tries to save the following identity-based policy for a role, expecting it to let the role describe EC2 instances:

    {
      "Version": "2012-10-17",
      "Statement": [{
        "Effect": "Allow",
        "Principal": { "AWS": "arn:aws:iam::111122223333:role/app-role" },
        "Action": "ec2:DescribeInstances",
        "Resource": "arn:aws:ec2:eu-west-1:111122223333:instance/i-0abc1234def567890"
      }]
    }
    

    Which TWO changes are needed? (Select TWO.)

    • A. Change Version to 2008-10-17.
    • B. Replace Principal with NotPrincipal.
    • C. Remove the Principal element.
    • D. Add a Sid to the statement.
    • E. Set Resource to "*" for ec2:DescribeInstances.
Answers
  1. D. s3:GetObject acts on object ARNs, so the statement needs reports-bucket/*. A switches to the old language without changing ARN matching; B is invalid in an identity-based policy; C would allow every other S3 action on the bucket ARN instead.
  2. C, E. IAM rejects a Principal in an identity-based policy, and DescribeInstances has no resource-level permissions, so it needs "*". A breaks policy variables and fixes nothing; B is invalid outside resource-based policies; D is optional metadata.

5. Policy conditions and condition keys

Concept

Exam facts

Operator family Operators Typical keys
String StringEquals, StringNotEquals, StringEqualsIgnoreCase, StringLike / StringNotLike (* and ?) aws:PrincipalTag/team, s3:prefix
Numeric NumericEquals, NumericLessThan(Equals), NumericGreaterThan(Equals) aws:MultiFactorAuthAge, s3:max-keys
Date DateEquals, DateLessThan(Equals), DateGreaterThan(Equals) (ISO 8601 or epoch) aws:CurrentTime, aws:EpochTime, aws:TokenIssueTime
Boolean Bool aws:SecureTransport, aws:MultiFactorAuthPresent
IP address IpAddress, NotIpAddress (CIDR, IPv4 or IPv6; an address without a prefix gets the default /32, so give a single IPv6 address an explicit /128) aws:SourceIp
ARN ArnEquals = ArnLike, ArnNotEquals = ArnNotLike aws:SourceArn, aws:PrincipalArn
Binary BinaryEquals (base64 value) binary keys
Existence <operator>IfExists, Null any key
Multivalued ForAnyValue: / ForAllValues: prefixes aws:TagKeys, aws:CalledVia

Developer angle

Guardrails and scoping in one identity policy:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "OnlyEuWest1ExceptGlobalServices",
      "Effect": "Deny",
      "NotAction": ["iam:*", "sts:*", "organizations:*", "support:*"],
      "Resource": "*",
      "Condition": { "StringNotEquals": { "aws:RequestedRegion": "eu-west-1" } }
    },
    {
      "Sid": "StartStopOwnTeamInstances",
      "Effect": "Allow",
      "Action": ["ec2:StartInstances", "ec2:StopInstances"],
      "Resource": "arn:aws:ec2:eu-west-1:111122223333:instance/*",
      "Condition": { "StringEquals": { "aws:ResourceTag/team": "${aws:PrincipalTag/team}" } }
    },
    {
      "Sid": "OwnKeysOnlyWithRecentMfa",
      "Effect": "Allow",
      "Action": ["iam:CreateAccessKey", "iam:DeleteAccessKey"],
      "Resource": "arn:aws:iam::111122223333:user/${aws:username}",
      "Condition": { "NumericLessThan": { "aws:MultiFactorAuthAge": "3600" } }
    }
  ]
}

A bucket policy that refuses plain HTTP:

{
  "Version": "2012-10-17",
  "Statement": [{
    "Sid": "DenyPlainHttp",
    "Effect": "Deny",
    "Principal": "*",
    "Action": "s3:*",
    "Resource": ["arn:aws:s3:::invoices-bucket", "arn:aws:s3:::invoices-bucket/*"],
    "Condition": { "Bool": { "aws:SecureTransport": "false" } }
  }]
}

Traps

Practice questions

  1. A security team requires that IAM users can call no AWS API, other than setting up their own MFA, unless they authenticated with MFA. This must also apply to CLI calls signed with long-term access keys. The current deny statement uses "Bool": {"aws:MultiFactorAuthPresent": "false"}, yet CLI calls made with access keys still succeed. What should the developer change?

    • A. Replace the condition with "NumericGreaterThan": {"aws:MultiFactorAuthAge": "3600"}.
    • B. Change the operator to BoolIfExists and keep the value "false".
    • C. Change the value to "true" and switch the statement's effect to Allow.
    • D. Add "Bool": {"aws:SecureTransport": "false"} to the same condition block.
  2. A developer attaches a deny statement with "NotIpAddress": {"aws:SourceIp": "198.51.100.0/24"} to a role. The role is used from laptops on the corporate network, by EC2 instances in private subnets that reach S3 through a gateway VPC endpoint, and by a CloudFormation stack that creates EC2 resources with the role's credentials. Laptop calls work, but the instances' S3 calls and the stack's EC2 calls are denied. Which TWO explanations are correct? (Select TWO.)

    • A. aws:SourceIp accepts only IPv6 ranges, so the IPv4 CIDR never matches.
    • B. Requests that arrive through a VPC endpoint carry no aws:SourceIp value, so the negated condition is true and the deny applies.
    • C. aws:SourceIp is evaluated only in resource-based policies, so in a role policy it denies everything.
    • D. When CloudFormation calls EC2 on the developer's behalf, EC2 sees CloudFormation's address instead of the corporate range.
    • E. The statement must use StringNotEquals because NotIpAddress is not a valid operator.
Answers
  1. B. With BoolIfExists, a missing key counts as true, so access-key calls (no MFA key) and non-MFA sessions (false) are both denied. A fails because the age key is also absent for long-term keys; C would not stop other policies from allowing non-MFA calls; D tests TLS, not MFA.
  2. B, D. VPC endpoint traffic has no aws:SourceIp, and service-made calls show the service's address. A, C and E are false: the key supports IPv4 and IPv6, works in identity-based policies, and NotIpAddress is the correct operator.

6. Testing and troubleshooting policies

Concept

Exam facts

Developer angle

A CI stage that lints and gates policy changes before deployment:

# lint an identity policy draft (fail the build on ERROR or SECURITY_WARNING)
aws accessanalyzer validate-policy --policy-type IDENTITY_POLICY \
  --policy-document file://draft.json --query 'findings[].[findingType,issueCode]'

# lint a role trust policy with the trust-policy-specific checks
aws accessanalyzer validate-policy --policy-type RESOURCE_POLICY \
  --validate-policy-resource-type AWS::IAM::AssumeRolePolicyDocument \
  --policy-document file://trust.json

# gate 1: no broader than what is deployed today (prints PASS or FAIL)
aws accessanalyzer check-no-new-access --policy-type IDENTITY_POLICY \
  --existing-policy-document file://deployed.json --new-policy-document file://draft.json \
  --query result --output text

# gate 2: never grant these critical actions
aws accessanalyzer check-access-not-granted --policy-type IDENTITY_POLICY \
  --policy-document file://draft.json \
  --access '[{"actions": ["iam:CreateUser", "s3:DeleteBucket"]}]'

# gate 3: the bucket policy must not allow public access
aws accessanalyzer check-no-public-access --resource-type AWS::S3::Bucket \
  --policy-document file://bucket-policy.json

When a deployment script creates a role and uses it straight away, wait for it and retry the first use:

aws iam create-role --role-name orders-fn-role \
  --assume-role-policy-document file://lambda-trust.json
aws iam wait role-exists --role-name orders-fn-role   # GetRole sees it; other endpoints may still lag
# then retry the first call that uses the role (e.g. lambda create-function) with backoff

Traps

Practice questions

  1. A team stores a role's customer managed policy in Git. The CI pipeline must block any merge that would grant more access than the currently deployed version, with the LEAST operational overhead. What should the developer add to the pipeline?

    • A. aws accessanalyzer validate-policy, failing the build on any WARNING finding.
    • B. aws iam simulate-custom-policy for every action of every service against the new document.
    • C. aws accessanalyzer check-no-new-access with the deployed and proposed documents, failing on FAIL.
    • D. A post-deployment review of CloudTrail for newly allowed calls during the following week.
  2. A deployment script creates an IAM role and immediately creates a Lambda function that uses it. The first CreateFunction call sometimes fails because Lambda cannot assume the role, yet the same call succeeds when the script is rerun a minute later. The trust policy is correct. Which TWO changes make the deployment reliable? (Select TWO.)

    • A. Wait with aws iam wait role-exists, then retry CreateFunction with exponential backoff.
    • B. Create the role in an earlier deployment stage than the function.
    • C. Add lambda:* on all resources to the role's permissions policy.
    • D. Change the trust policy principal to "Service": "*" for all services.
    • E. Raise the role's maximum session duration to 12 hours.
Answers
  1. C. check-no-new-access compares two versions and returns FAIL when the new one grants more, which is exactly the gate required. A checks grammar and best practices, not added access; B is impractical; D detects the problem only after deployment.
  2. A, B. The failure is IAM eventual consistency: the new role has not reached every endpoint yet, so waiting and retrying, or creating roles ahead of time, fixes it. C changes what the function may do, not whether Lambda can assume the role; D is not allowed in a trust policy; E only changes session length.

7. Password policy

Concept

Exam facts

Developer angle

# always send the complete policy: omitted options fall back to defaults
aws iam update-account-password-policy \
  --minimum-password-length 14 \
  --require-uppercase-characters --require-lowercase-characters \
  --require-numbers --require-symbols \
  --max-password-age 90 --password-reuse-prevention 24 \
  --allow-users-to-change-password
aws iam get-account-password-policy
aws iam delete-account-password-policy          # back to the AWS default policy

# an administrator resets a console password and forces a change at next sign-in
aws iam update-login-profile --user-name alice \
  --password 'Temp-Reset#2026-Q4' --password-reset-required

Change one setting safely from code by copying every active setting back (boto3):

import boto3

iam = boto3.client("iam")
SETTABLE = {"MinimumPasswordLength", "RequireSymbols", "RequireNumbers",
            "RequireUppercaseCharacters", "RequireLowercaseCharacters",
            "AllowUsersToChangePassword", "MaxPasswordAge",
            "PasswordReusePrevention", "HardExpiry"}
try:
    current = iam.get_account_password_policy()["PasswordPolicy"]
except iam.exceptions.NoSuchEntityException:
    current = {}  # no custom policy yet

# copy every active setting (ExpirePasswords is read-only and skipped); anything left out
# reverts to its default, i.e. false or "not set", exactly what a false or 0 value meant
settings = {key: value for key, value in current.items() if key in SETTABLE and value}
settings["RequireSymbols"] = True  # the one setting being changed
iam.update_account_password_policy(**settings)

Traps

Practice questions

  1. A deployment script runs aws iam update-account-password-policy --require-symbols to add a symbol requirement. Afterwards, the minimum length has dropped from 14 to 6 characters and passwords no longer expire. What explains this?

    • A. The operation does not support partial updates, so every omitted option reverted to its default.
    • B. IAM is eventually consistent, so the previous values will reappear after propagation.
    • C. The default AWS password policy overrides custom settings once symbols are required.
    • D. Requiring symbols resets the length and expiry rules because they conflict.
  2. An administrator changes the account password policy: the minimum length rises from 8 to 14 characters and passwords now expire after 60 days. Which TWO outcomes are expected? (Select TWO.)

    • A. Users' access keys stop working as soon as their console passwords expire.
    • B. Users whose current password is older than 60 days must set a new one at their next console sign-in.
    • C. Users with passwords shorter than 14 characters may keep them until their next password change.
    • D. The root user's password also expires after 60 days.
    • E. Users who fail to sign in five times are locked out for 30 minutes.
Answers
  1. A. UpdateAccountPasswordPolicy replaces the whole policy, so options left out return to their defaults (length 6, no expiry). B is wrong because the change is not a propagation delay; C and D describe behaviour that does not exist.
  2. B, C. Expiration applies immediately, while length and character rules apply at the next change. A: expired passwords leave access keys working; D: the policy never applies to root; E: IAM has no lockout setting.

8. MFA devices and enforcement

Concept

Exam facts

Developer angle

Register a virtual device from the CLI (passkeys and security keys need the console):

aws iam create-virtual-mfa-device --virtual-mfa-device-name alice-phone \
  --outfile alice-qr.png --bootstrap-method QRCodePNG
aws iam enable-mfa-device --user-name alice \
  --serial-number arn:aws:iam::111122223333:mfa/alice-phone \
  --authentication-code1 123456 --authentication-code2 789012
aws iam list-mfa-devices --user-name alice
aws iam list-virtual-mfa-devices --assignment-status Unassigned
aws iam deactivate-mfa-device --user-name alice \
  --serial-number arn:aws:iam::111122223333:mfa/alice-phone
aws iam delete-virtual-mfa-device --serial-number arn:aws:iam::111122223333:mfa/alice-phone

Enforce MFA while still letting users enrol their first device:

{
  "Version": "2012-10-17",
  "Statement": [
    { "Sid": "ListDevicesNeedsStar", "Effect": "Allow", "Action": "iam:ListVirtualMFADevices", "Resource": "*" },
    { "Sid": "CreateOwnVirtualDevice", "Effect": "Allow", "Action": "iam:CreateVirtualMFADevice", "Resource": "arn:aws:iam::*:mfa/*" },
    {
      "Sid": "ManageOwnUserMfa",
      "Effect": "Allow",
      "Action": ["iam:EnableMFADevice", "iam:ResyncMFADevice", "iam:ListMFADevices", "iam:GetUser"],
      "Resource": "arn:aws:iam::*:user/${aws:username}"
    },
    {
      "Sid": "BlockOtherCallsWithoutMfa",
      "Effect": "Deny",
      "NotAction": ["iam:CreateVirtualMFADevice", "iam:EnableMFADevice", "iam:ResyncMFADevice",
                    "iam:ListMFADevices", "iam:ListVirtualMFADevices", "iam:GetUser",
                    "sts:GetSessionToken"],
      "Resource": "*",
      "Condition": { "BoolIfExists": { "aws:MultiFactorAuthPresent": "false" } }
    }
  ]
}

Traps

Practice questions

  1. Developers who are IAM users sign in to the console with passwords and passkeys. They now need temporary credentials for the AWS CLI, without anyone creating access keys, with the LEAST operational overhead. What should they do?

    • A. Run aws sts get-session-token with the passkey's ARN as --serial-number and a code produced by the passkey.
    • B. Create access keys for each developer and exempt those keys from the MFA policy.
    • C. Register each passkey again with aws iam enable-mfa-device.
    • D. Run aws login and complete the browser sign-in with the console password and passkey.
  2. The only FIDO security key of an IAM administrator broke. A year ago, the administrator also registered a virtual authenticator app on the same IAM user. Which TWO statements are correct? (Select TWO.)

    • A. The administrator must complete the AWS account recovery process with the account's email address and phone number.
    • B. An IAM user can hold one MFA device only, so the app registration replaced the security key.
    • C. A replacement security key can be registered with aws iam enable-mfa-device.
    • D. The administrator can still sign in by entering a code from the virtual authenticator app.
    • E. After signing in with the app, the administrator can remove the broken security key from the user.
Answers
  1. D. aws login turns the console sign-in, passkey included, into temporary CLI credentials (the IAM users need the SignInLocalDevelopmentAccess managed policy). A fails because FIDO MFA can't be passed to STS; B breaks the no-access-keys requirement; C fails because passkeys can only be registered in the console.
  2. D, E. Any one of up to eight registered devices signs the user in, and authenticating with an existing device allows removing another. A applies to root users who lost every device; B is outdated; C fails because security keys are console-only.

9. Access keys and programmatic access

Concept

Exam facts

Developer angle

aws iam create-access-key --user-name legacy-sync          # the only time the secret is returned
aws iam list-access-keys --user-name legacy-sync \
  --query 'AccessKeyMetadata[].[AccessKeyId,Status,CreateDate]' --output table
aws iam get-access-key-last-used --access-key-id AKIAIOSFODNN7EXAMPLE
aws iam update-access-key --user-name legacy-sync \
  --access-key-id AKIAIOSFODNN7EXAMPLE --status Inactive
aws iam delete-access-key --user-name legacy-sync --access-key-id AKIAIOSFODNN7EXAMPLE
aws sts get-access-key-info --access-key-id AKIAIOSFODNN7EXAMPLE   # which account owns it?

Find old active keys and their last use (boto3); the 90-day threshold is an example, not an AWS rule:

from datetime import datetime, timedelta, timezone

import boto3

iam = boto3.client("iam")
cutoff = datetime.now(timezone.utc) - timedelta(days=90)

for page in iam.get_paginator("list_users").paginate():
    for user in page["Users"]:
        for key in iam.list_access_keys(UserName=user["UserName"])["AccessKeyMetadata"]:
            if key["Status"] == "Active" and key["CreateDate"] < cutoff:
                last = iam.get_access_key_last_used(AccessKeyId=key["AccessKeyId"])
                used = last["AccessKeyLastUsed"].get("LastUsedDate", "never")
                print(user["UserName"], key["AccessKeyId"], key["CreateDate"].date(), used)

Traps

Practice questions

  1. An on-premises batch job signs requests with the access key of an IAM user. Security asks for the key to be rotated without interrupting the job. What should the developer do FIRST?

    • A. Deactivate the current key, then create a replacement and update the job.
    • B. Create a second access key while the first stays active, then move the job to it.
    • C. Retrieve the current secret access key and store it in AWS Secrets Manager.
    • D. Delete the current key, then create a new one and update the job.
  2. A developer learns that an access key ID beginning with AKIA was pushed to a public Git repository. Which TWO actions are appropriate? (Select TWO.)

    • A. Run aws sts get-access-key-info on the key ID to confirm which AWS account owns it.
    • B. Detach the AWSCompromisedKeyQuarantineV3 policy that AWS attached to the user.
    • C. Identify the owning IAM user (credential report or list-access-keys), then deactivate and replace the key.
    • D. Change the IAM user's console password, which invalidates the user's access keys.
    • E. Wait 12 hours, after which AKIA keys expire automatically.
Answers
  1. B. The second key slot exists for overlap: create, switch, verify, then deactivate and delete the old key. A and D interrupt the job before the replacement is in place; C is impossible because the secret is shown only at creation.
  2. A, C. Confirm the owning account, find the user, then replace the key. B removes AWS's protective controls instead of fixing the exposure; D fails because passwords and access keys are independent; E fails because AKIA keys never expire.

10. Credential report and last accessed information

Concept

You need to know… Use
Which users have a password but no MFA, old keys or unused keys Credential report
Which services and actions a user, group, role or policy actually used Last accessed information
Who outside the account or organization can reach a resource Access Analyzer external access (§11)
Unused roles, keys, passwords and permissions across the organization, continuously Access Analyzer unused access (§11)
Every call a principal made, when, from where and with what result CloudTrail
Whether a policy would allow a given call Policy simulator (§6)

Exam facts

Developer angle

aws iam generate-credential-report            # State: STARTED → COMPLETE
aws iam get-credential-report --query Content --output text | base64 --decode > credential-report.csv

JOB=$(aws iam generate-service-last-accessed-details \
  --arn arn:aws:iam::111122223333:role/orders-fn-role --granularity ACTION_LEVEL \
  --query JobId --output text)
aws iam get-service-last-accessed-details --job-id "$JOB" \
  --query 'ServicesLastAccessed[].[ServiceNamespace,LastAuthenticated]' --output table
# repeat the get call until JobStatus is COMPLETED (it starts as IN_PROGRESS)

Flag console users without MFA straight from the report (boto3 returns the CSV as raw bytes):

import csv
import io
import time

import boto3

iam = boto3.client("iam")
while iam.generate_credential_report()["State"] != "COMPLETE":
    time.sleep(2)

report = iam.get_credential_report()["Content"].decode("utf-8")
for row in csv.DictReader(io.StringIO(report)):
    if row["password_enabled"].lower() == "true" and row["mfa_active"].lower() == "false":
        print("console password without MFA:", row["user"])

Traps

Practice questions

  1. A compliance team needs a list of every IAM user who has a console password but no MFA device, plus every access key that has not been used for 90 days, with the LEAST effort. What should a developer use?

    • A. The IAM credential report, filtered on password_enabled, mfa_active and the access_key_*_last_used_date columns.
    • B. Service last accessed details generated for each user at action level.
    • C. A CloudTrail Lake query per user covering the last 90 days.
    • D. An IAM Access Analyzer external access analyzer for the account.
  2. A developer wants to trim a role's broad managed policy down to what the application actually uses. Which TWO approaches help? (Select TWO.)

    • A. Download the credential report and remove the services the role has not used.
    • B. Generate action-level last accessed details for the role and review unused services and actions.
    • C. Read the RoleLastUsed field returned by aws iam get-role.
    • D. Use IAM Access Analyzer policy generation on the role's CloudTrail activity to draft a policy.
    • E. Run the policy simulator against the current policy to list the actions it allows.
Answers
  1. A. The credential report already holds password, MFA and key-usage columns for every user in one CSV. B shows permission usage, not credentials; C works but costs far more effort; D reports resources shared outside the zone of trust.
  2. B, D. Last accessed data shows which granted services and actions are used, and policy generation drafts a policy from real activity. A covers credentials, not permissions; C gives only the role's last use date and Region; E shows what is allowed, not what is used.

11. IAM Access Analyzer findings and policy generation

Concept

Exam facts

Developer angle

# external access, organization as zone of trust (run in every Region you use)
aws accessanalyzer create-analyzer --analyzer-name org-external --type ORGANIZATION
aws accessanalyzer list-findings-v2 \
  --analyzer-arn arn:aws:access-analyzer:eu-west-1:111122223333:analyzer/org-external \
  --filter '{"status": {"eq": ["ACTIVE"]}}'
aws accessanalyzer start-resource-scan \
  --analyzer-arn arn:aws:access-analyzer:eu-west-1:111122223333:analyzer/org-external \
  --resource-arn arn:aws:s3:::invoices-bucket

# unused access across the organization (paid, one analyzer is enough)
aws accessanalyzer create-analyzer --analyzer-name org-unused --type ORGANIZATION_UNUSED_ACCESS

# draft a least-privilege policy from 90 days of the role's CloudTrail activity
JOB_ID=$(aws accessanalyzer start-policy-generation \
  --policy-generation-details principalArn=arn:aws:iam::111122223333:role/orders-fn-role \
  --cloud-trail-details '{
    "trails": [{"cloudTrailArn": "arn:aws:cloudtrail:eu-west-1:111122223333:trail/main", "allRegions": true}],
    "accessRole": "arn:aws:iam::111122223333:role/service-role/AccessAnalyzerMonitorServiceRole",
    "startTime": "2026-07-01T00:00:00Z",
    "endTime": "2026-09-29T00:00:00Z"
  }' --query jobId --output text)
aws accessanalyzer get-generated-policy --job-id "$JOB_ID"   # once the job has succeeded

Traps

Practice questions

  1. A company wants continuous alerts whenever an S3 bucket, a KMS key, an IAM role trust policy or an SQS queue anywhere in its organization grants access to principals outside the organization, with the LEAST operational overhead. What should a developer configure?

    • A. A scheduled Lambda function that parses every resource policy and compares the account IDs it finds.
    • B. A weekly export of the IAM credential report to the security team's mailbox.
    • C. An IAM Access Analyzer external access analyzer with the organization as zone of trust, in each Region in use.
    • D. An IAM Access Analyzer unused access analyzer for the organization.
  2. A developer plans to use IAM Access Analyzer policy generation to replace a broad policy on a role. Which TWO statements are correct? (Select TWO.)

    • A. The generated policy automatically includes iam:PassRole for the roles the application passes.
    • B. The generated policy lists S3 data-event actions such as s3:GetObject at action level.
    • C. A CloudTrail trail must be logging the account's activity, and up to 90 days of events can be analyzed.
    • D. An unused access analyzer must exist in the Region before a policy can be generated.
    • E. Resource ARNs and conditions still have to be added and tested before the policy goes to production.
Answers
  1. C. External access analyzers continuously evaluate resource-based policies against the zone of trust; one is needed per Region. A recreates the feature with custom code; B is about credentials, not sharing; D finds unused access, not external access.
  2. C, E. Generation reads up to 90 days from a trail and produces a template that still needs resources and conditions. A and B are false because PassRole and data events are never included; D is false because policy generation doesn't depend on an unused access analyzer.

12. Best practices and shared responsibility

Concept

Exam facts

Area AWS (security of the cloud) You (security in the cloud)
IAM service Infrastructure, availability, replication of IAM data across Regions Which users, groups, roles and policies exist
Credentials Issuing and rotating temporary credentials it hands to roles Password policy, MFA for IAM users, access key lifecycle
Permissions Evaluating policies exactly as written Least privilege, conditions, guardrails, removing unused access
Monitoring Recording events in CloudTrail and providing the analysis tools Turning on trails, analyzers and alerts, and acting on findings

Developer angle

import boto3

# No keys in code: the SDK finds credentials from the environment, an SSO or login
# session, a container role or the instance profile (cli-sdk-policies guide).
s3 = boto3.client("s3")
s3.put_object(Bucket="reports-bucket", Key="2026/oct.csv", Body=b"id,total\n1,42\n")

Traps

Practice questions

  1. A startup has 40 developers working across three AWS accounts. Each developer has an IAM user with long-term access keys for the CLI. Which change is MOST secure while keeping operational overhead low?

    • A. Keep the IAM users and rotate every access key each 30 days through a scheduled Lambda function that emails the new keys.
    • B. Store each developer's access keys in AWS Secrets Manager and fetch them in the developers' shell scripts.
    • C. Replace the individual IAM users with one shared IAM user per team that requires MFA at console sign-in.
    • D. Federate the developers through IAM Identity Center and have them use aws configure sso for CLI access.
  2. During a security review, a developer must list which IAM-related tasks are the company's responsibility under the AWS shared responsibility model. Which TWO belong to the company? (Select TWO.)

    • A. Requiring MFA for IAM users and enforcing it in policies.
    • B. Patching the servers that run the IAM service.
    • C. Replicating IAM data across AWS data centres and Regions.
    • D. Reviewing last accessed information and removing unused permissions.
    • E. Securing the physical facilities that host the IAM infrastructure.
Answers
  1. D. Identity Center gives every developer temporary, MFA-backed credentials across the accounts with central permission sets. A keeps long-term keys and adds custom code; B still distributes long-term keys; C removes individual accountability and keeps shared long-term credentials.
  2. A, D. Configuring MFA and keeping permissions minimal are security in the cloud. B, C and E are AWS's side: infrastructure, replication and physical security.

Quick decision rules

Root user (§1)

Users, groups and roles (§2–§3)

Policies and conditions (§4–§5)

Testing and troubleshooting (§6)

Credentials (§7–§9)

Audit tools (§10–§12)

Changed vs older material

Learn the Current column; older practice material may still show the Older material may say value. Once you confirm them, the same rows go to notes/current-facts.md with their verification dates.

Topic Older material may say Current (verified 2026-10-12) Source
§1 · Root user MFA Root MFA is a recommended best practice but optional Required for the root user of every account type (standalone, management, member); a root user without MFA must register one within 35 days of its first console sign-in attempt AWS docs
§1 · Root credentials of Organizations member accounts Every member account has root credentials that must each be secured with MFA Centralized root access (since Nov 15, 2024): delete member root password, keys, certificates and MFA; privileged tasks via sts:AssumeRoot (Regional endpoint, ≤ 900 s, 5 task policies) What's New
§1 · Tasks that require root Only root can change the account name or the Support plan Standalone accounts need root only for the email address, root password and root access keys (plus closing and reopening the account); name, contacts, alternate contacts, payment currency and Regions don't AWS docs
§2 · Identities for people A dedicated IAM user for every person Human users federate (IAM Identity Center or an IdP) with temporary credentials; IAM users only for workloads that can't use roles, third-party tools, CodeCommit, Keyspaces and emergency access AWS docs
§3 · Managed policies per role 10 by default, adjustable to 20 20 by default, adjustable up to 25 AWS docs
§3–§4 · Adjustable IAM quota maximums Roles up to 5,000; customer managed policies up to 5,000; instance profiles up to 5,000; role trust policy up to 4,096 characters Roles up to 10,000; customer managed policies up to 10,000; instance profiles up to 10,000; role trust policy up to 8,192 characters (defaults unchanged: 1,000 / 1,500 / 1,000 / 2,048) AWS docs
§8 · MFA devices per user One MFA device per IAM user or root user Up to 8 devices of any type per user (since Nov 16, 2022); passkeys supported (since June 11, 2024) and recommended What's New
§8 · MFA device types and vendors U2F security keys, Gemalto key fobs, SurePassID fobs for GovCloud Passkeys and FIDO security keys, virtual authenticator apps, hardware TOTP tokens from Thales (OTP token or display card) or, for GovCloud, Hypersecu AWS
§8 · SMS MFA SMS text messages are an MFA option AWS ended support for enabling SMS MFA AWS docs
§9 · Programmatic access Create access keys for CLI and SDK use Long-term keys are "not recommended"; use aws login, IAM Identity Center, CloudShell, roles or IAM Roles Anywhere AWS docs
§10 · Access Advisor Access Advisor tab, service-level data for users (action detail for S3 only) Last accessed information on the Last Accessed tab for users, groups, roles and policies; action-level for S3 (2020), EC2, IAM and Lambda (2021) and other services' management actions (since May 23, 2023) AWS docs
§12 · Access key guidance Rotate all access keys regularly Prefer temporary credentials; update long-term keys when needed, guided by last-used data AWS docs
§12 · AWS SSO AWS Single Sign-On (AWS SSO) Renamed AWS IAM Identity Center on July 26, 2022; aws configure sso and the sso* API namespaces unchanged AWS docs