skip to content

In AWS IAM, what is the credential report, and how would you use it to answer "which IAM users still hold stale long-lived credentials, and is MFA enabled on the root user?"

level: juniorimportance: should knowfreq 40%

answer

  1. one CSV, whole account
  2. inventory of long-lived credentials
  3. users and root, never roles
  4. mfa_active, last_rotated, last_used_date
  5. regenerated at most every four hours

basics

~10 s

The IAM credential report is an account-wide CSV listing every IAM user and the root user, with password state, access-key rotation and last-used dates, and MFA status. One download answers stale-credential and root-MFA questions.

solid answer

~40 s

The credential report is a per-account CSV you generate with `aws iam generate-credential-report` and download with `aws iam get-credential-report` (the payload is base64-encoded). Each row is an IAM user, plus one special row for the root user. The columns that matter for hygiene are `password_enabled`, `password_last_used`, `mfa_active`, and per access key `access_key_N_active`, `access_key_N_last_rotated` and `access_key_N_last_used_date`. To answer the question I download it, filter rows where a key is active but was rotated long ago or shows `N/A` for last use, and read `mfa_active` on the `<root_account>` row. Two caveats: the report covers IAM users only, not roles, and it can be regenerated at most once every four hours, so a fresh download can still be up to four hours stale.

code

bash · 3 lines
bash
aws iam generate-credential-report
aws iam get-credential-report --query Content --output text | base64 --decode > credential-report.csv
awk -F, 'NR==1 || $1=="<root_account>"' credential-report.csv

go deeper

for a junior

Know that one CLI call produces an account-wide CSV of every IAM user plus root, and be able to name the columns you would check: mfa_active, access key last rotated, and access key last used.

for a middle

Explain the two-call generate-then-get flow, the base64-encoded payload, and the four-hour regeneration limit — then say why the report covers users and root but never roles.

for a senior

Show how you turn the report into a recurring control: schedule it, diff it, and drive root access keys, MFA gaps and over-age keys to zero, while joining rows to attached policies so you rank findings by blast radius rather than by count.

for a principal

Argue the endgame — an account whose credential report is empty because all human access is federated short-lived roles — and be ready to defend the migration cost and the break-glass identity you deliberately keep outside that scheme.

## What the report is The IAM credential report is a single, account-wide CSV snapshot of the state of every long-lived credential in the account. It is not a log and not a stream of events — it is a point-in-time inventory. AWS builds it on request and caches it, so it is the fastest way to answer questions of the shape "across this whole account, who has what, and when did they last use it?" ## Getting it Two API calls. `GenerateCredentialReport` kicks off the build and returns a state (`STARTED` or `COMPLETE`); `GetCredentialReport` returns the CSV, base64-encoded in the `Content` field, along with a `GeneratedTime`. On the CLI: ```bash aws iam generate-credential-report aws iam get-credential-report --query Content --output text | base64 --decode ``` AWS regenerates the report at most once every four hours. If you call `GenerateCredentialReport` again inside that window you get the cached copy, so the freshest report you can ever hold may describe the account as it was up to four hours ago. That is fine for hygiene sweeps and wrong for incident response — during an incident you want CloudTrail, not a cached inventory. ## What is in a row One row per IAM user, plus one synthetic row whose `user` column is `<root_account>`. The columns worth knowing: - `password_enabled`, `password_last_used`, `password_last_changed`, `password_next_rotation` — console-login state and age. - `mfa_active` — whether the identity has an MFA device attached. This is the column people actually open the report for, because the root row tells you in one glance whether the account's most dangerous identity is protected. - `access_key_1_active` / `access_key_2_active` — an IAM user can hold at most two access keys, which is exactly why rotation is a two-slot dance: create the second key, roll consumers onto it, confirm the first has stopped being used, then delete it. - `access_key_N_last_rotated` — when the key was created. This is your age signal. - `access_key_N_last_used_date`, `..._last_used_service`, `..._last_used_region` — when and against what the key was last used. A value of `N/A` means the key has not been used since AWS began tracking, which usually means never. - `cert_1_active` / `cert_2_active` — signing certificates, a legacy surface most accounts should show as false. ## Reading it for the two questions asked For stale credentials, the useful predicate combines two columns, not one. A key that is `active` and was `last_rotated` two years ago is an age problem. A key that is `active` and shows `N/A` for `last_used_date` is a different and often worse problem: nothing depends on it, so nobody will notice if an attacker starts using it. Both are deletion candidates; the unused one is the easy win because removing it cannot break a caller. For root MFA, read `mfa_active` on the `<root_account>` row. While you are there, `access_key_1_active` on that same row should be `false` — root access keys are a finding on their own, since they cannot be constrained by IAM policy and, in the organization's management account, are not constrained by service control policies either. ## What it does not cover The report is about long-lived credentials attached to IAM *users*. Roles do not appear in it at all, and in a well-built account most access is roles assumed through federation, so an empty-looking credential report is a good sign rather than a complete picture. For roles you need a different evidence source: service last-accessed data tells you which services a role's permissions were actually used against, IAM Access Analyzer's unused-access findings surface roles nobody has assumed, and CloudTrail is the underlying record of individual calls. It also says nothing about *what* a user is permitted to do. `mfa_active = false` on a user with read-only access to one bucket and on a user with `AdministratorAccess` look identical in the CSV. Pair the report with the policies attached to each row before you rank findings, or you will spend your remediation effort on the harmless users. ## Where it fits Treat the credential report as the recurring hygiene sweep: run it on a schedule, diff it, and drive three metrics to zero — root access keys, users without MFA, and active keys older than your rotation policy. It is cheap, needs only `iam:GenerateCredentialReport` and `iam:GetCredentialReport`, and it is the artifact an auditor will ask for by name.

  • The report shows an access key that is active but whose last-used date is N/A. Is that safer or more dangerous than a key used daily?
    More dangerous in practice. A key nothing uses is a credential nobody monitors: no consumer breaks if it is stolen and used, and no one notices the change in traffic. It is also the easiest to remove, because by definition no caller depends on it. Delete it rather than scheduling it for rotation.
  • Why do roles not appear in the credential report, and what do you use instead?
    The report inventories long-lived credentials, and a role has none — it issues short-lived STS credentials on assumption. For roles, use IAM service last-accessed data to see which services the role's permissions were used against, IAM Access Analyzer unused-access findings to surface roles nobody assumes, and CloudTrail for the individual calls.
  • An account has zero IAM users and its credential report is essentially empty. Is that a finding?
    No — it is the target state. It means human access arrives through federated roles with short-lived credentials rather than static keys. Shift the audit to the roles: who can assume them, from which identity provider, and whether the trust policies are scoped.

saying these in an interview costs you the question

  • Thinks the credential report lists IAM roles too
  • Calls it a log of API activity rather than a snapshot
  • Assumes it is real-time and current to the second
  • Ignores the root row's MFA and access-key columns
  • Treats key age alone as the finding, ignoring last-used

context