← Recipes

阅读中文版本

Run a Quarterly Access Review

Generate an IAM credential report, flag unused keys and administrator roles, and record reviewer sign-off before the due date.

~45 miniamaccess-controlcompliance

Task

Prove that every production access grant is still needed and owned by a named person.

When to use this

An audit finds eleven IAM users with administrator access, four access keys unused for a year, and no evidence that anyone reviewed them. Access accumulated through incident fixes and nobody can say which grants are still required.

Prerequisites

  • AWS IAM with permission to generate and read the credential report
  • A list of services and their owning teams
  • A ticketing or GRC system to record sign-off

Steps

1. Generate a fresh credential report and decode it to CSV.

aws iam generate-credential-report && aws iam get-credential-report --query Content --output text | base64 -d > credential-report-2026-10-21.csv

Expected output: A CSV with one row per IAM user, including password age, access key ages, and MFA status.

2. List users with administrator access so each one receives explicit scrutiny.

for user in $(aws iam list-users --query 'Users[].UserName' --output text); do
  policies=$(aws iam list-attached-user-policies --user-name "$user" \
    --query "AttachedPolicies[?PolicyName=='AdministratorAccess'].PolicyName" --output text)
  if [ -n "$policies" ]; then
    echo "$user has AdministratorAccess"
  fi
done

Expected output: A short list of administrator users instead of the full user inventory.

3. Send each service owner their users, roles, and key ages, and require an approve or revoke decision with a date.

aws iam list-users --query 'Users[?PasswordLastUsed<`2026-07-21`].[UserName,PasswordLastUsed]' --output text

Expected output: Users who have not signed in for 90 days are highlighted for revocation unless the owner justifies them.

4. Record decisions in a review file and disable credentials that were not approved.

aws iam update-access-key --user-name legacy-ci --access-key-id AKIAIOSFODNN7EXAMPLE --status Inactive

Expected output: The unapproved key is inactive, the review file lists the decision and approver, and no service breaks undetected.

Troubleshooting

Problem

The credential report is stale

Solution

Reports are generated asynchronously and can take up to four hours; poll the report state and wait for COMPLETE before decoding.

Problem

A shared service account has no named owner

Solution

Assign it to a team in the service catalog and treat the review as incomplete until an owner accepts accountability.

Limitations

  • The credential report covers IAM users only, not federated sessions or resource-based policies.
  • It is a point-in-time snapshot; access granted after generation is not reviewed.

Review access, not just users

An access review asks one question per grant: does this principal still need this permission? Start from the credential report because it contains the evidence reviewers need: last password use, key age, key last-used date, and MFA status. Combine it with the list of administrator principals, which deserve the closest reading.

Make it easy to say no

Owners ignore reviews that require them to reconstruct their own inventory. Send each owner a short table of their users and roles with a recommended decision based on inactivity. Ask for approve or revoke plus a date, not free-form prose. Set a deadline and escalate to the owner’s manager if it passes.

aws iam list-users \
  --query 'Users[?PasswordLastUsed<`2026-07-21`].[UserName,PasswordLastUsed]' \
  --output text

Act on the decisions

A review without revocation is paperwork. Disable access keys before deleting them so a broken automation can be detected and restored. Remove policies from users who do not need them, and convert long-lived keys to roles where possible. Record the decision, the approver, and the date in a file stored with the audit evidence.

Handle the exceptions

Break-glass accounts, CI users, and vendor integrations need documented exceptions with an owner and an expiry. Review exceptions at the same cadence. If an account has no owner, disable it; an unowned credential is a liability, not an asset. Close the loop by reporting the number of grants removed and the number of exceptions renewed. The expected outcome is a review file where every active principal has an approve or revoke decision, a named approver, and a date, with no administrator role left unexamined.