Skip to main content
CloudArq
topiciam keys
scopeaws
typehow-to
how-to guide · aws · iam

How to find and rotate stale IAM access keys

Long-lived IAM access keys are the credential most likely to leak and least likely to be noticed. This guide walks the full lifecycle: pull the account credential report, spot every key past 90 days, rotate it with zero downtime using the two-key method, delete root keys, and move workloads to IAM roles and people to short-lived federated credentials. Real AWS CLI, console, and Terraform steps throughout.

Updated 2026-07-20 · ~8 minute read

78
day rotation baseline
3
IAM key checks below
167
total CloudArq checks
0
credentials stored
why it matters

Why stale keys are the credential that bites you

An IAM access key is a static, long-lived secret. Unlike a console session, it does not expire. It gets pasted into CI variables, laptop dotfiles, old scripts, and Slack threads, and it keeps working for years unless someone rotates or deletes it. When a key leaks — a public repo, a stolen laptop, a compromised build box — the blast radius is whatever policy that key's user carries. Stale keys (unrotated, unused, or on the root account) are the ones no owner is watching, which is exactly why attackers and auditors both look for them first.

1
step · inventory

Pull the account credential report

The credential report is a single CSV covering every IAM user in the account — password age, MFA status, and both access keys with their last-rotated and last-used dates. Generate it, then download and decode it:

aws iam generate-credential-report
aws iam get-credential-report \
  --query 'Content' --output text | base64 --decode > credential-report.csv

The columns that matter for keys are access_key_1_active, access_key_1_last_rotated, access_key_1_last_used_date (and the matching _2_ set). In the console the same view lives under IAM → Users → Security credentials → Access keys, which shows a "Last used" timestamp per key.

2
step · triage

Identify the stale keys

A key is stale if last_rotated is more than 90 days ago, if it has never been used, or if it belongs to a user with no recent activity. For a specific key, confirm the last service and region it touched before you act:

aws iam list-access-keys --user-name ci-deployer
aws iam get-access-key-last-used --access-key-id AKIAEXAMPLE0000

If LastUsedDate is absent, the key has never made a signed request — deactivate and delete it rather than rotating. Sort your CSV by access_key_1_last_rotated to work oldest-first.

3
step · rotate

Rotate safely with the two-key method

IAM allows two access keys per user precisely so you can rotate with an overlap and never take an outage. Never delete the old key first — deactivate it, verify, then delete.

# 1. Create the replacement key (note the SecretAccessKey — shown once)
aws iam create-access-key --user-name ci-deployer

# 2. Deploy the new key everywhere the old one is referenced
#    (CI secrets, ~/.aws/credentials, app config, cron/scripts)

# 3. Deactivate — do NOT delete — the old key
aws iam update-access-key --user-name ci-deployer \
  --access-key-id AKIAEXAMPLE0000 --status Inactive

# 4. Watch last-used for a few days to catch anything you missed
aws iam get-access-key-last-used --access-key-id AKIAEXAMPLE0000

# 5. Once confirmed idle, delete it
aws iam delete-access-key --user-name ci-deployer \
  --access-key-id AKIAEXAMPLE0000

If something breaks in step 3, set the old key back to Active instantly — that is the whole point of deactivating rather than deleting.

4
step · root

Delete the root account access keys

The root user should have zero long-lived access keys. A root key cannot be scoped down, so a single leak is game over for the whole account. You cannot manage root keys with an IAM principal — sign in as root, open My Security Credentials, and delete any access keys under Access keys (root). Then enable MFA on root and lock the credentials away. Everyday work moves to IAM roles or IAM Identity Center users.

5
step · eliminate

Replace long-lived keys with roles + STS

Rotation is a chore you repeat forever; the durable fix is to stop issuing static keys at all. STS hands out short-lived credentials that expire on their own, so there is nothing to leak long-term:

  • Workloads on AWS
    Attach an IAM role to the EC2 instance, ECS task, or Lambda function and remove the static keys entirely — the SDK fetches temporary credentials from the instance/task metadata automatically.
  • People
    Move humans to IAM Identity Center (SSO). aws sso login mints short-lived credentials per session; no access key ever lands on a laptop.
  • CI/CD outside AWS
    Use OIDC federation (sts:AssumeRoleWithWebIdentity) so your pipeline assumes a role with a signed identity token instead of a stored key — e.g. a GitHub Actions or GitLab job with no long-lived secret at all.
6
step · guardrail

Prevent regressions with AWS Config

AWS does not expire keys for you, but two AWS Config managed rules give you continuous drift detection so a stale key gets flagged the day it crosses the line — not at the next audit. The Terraform below turns on access-keys-rotated with a 90-day age; pair it with iam-user-unused-credentials-check for dormant users:

resource "aws_config_config_rule" "access_keys_rotated" {
  name = "access-keys-rotated"

  source {
    owner             = "AWS"
    source_identifier = "ACCESS_KEYS_ROTATED"
  }

  input_parameters = jsonencode({ maxAccessKeyAge = "90" })
}

Config must be recording in the region for the rule to evaluate. This flags drift — it does not rotate anything for you; the two-key workflow above is still how you remediate.

product · detection

The CloudArq checks that catch this

CloudArq runs the credential-report inventory for you and flags the three stale-credential patterns automatically — read-only, with the exact remediation steps attached to each finding. They are 3 of the 192 checks CloudArq runs against an AWS account.

old_access_keys
IAM access key older than 90 days
Any active access key whose last-rotated date is more than 90 days ago — the rotation window CIS has long recommended.
root_access_keys
Root account has long-lived access keys
The root user should carry zero access keys; a single leaked root key is account-wide and cannot be scoped down.
iam_unused_users
IAM user with unused credentials
A user (and its keys) with no console or API activity — a dormant credential worth deactivating and removing.
findings · iam · stale credentialsillustrative example
Critical1High1Medium1
root_access_keys
Root account has an active access key
root · 1 key active
fix →
old_access_keys
Access key not rotated in 412 days
user/ci-deployer · AKIA…EXAMPLE
fix →
iam_unused_users
IAM user with no activity in 180 days
user/old-contractor
fix →

Each finding ships the copy-paste rotate / deactivate / delete commands — CloudArq is read-only and never touches the key itself.

faq

Frequently asked

01How often should IAM access keys be rotated?
The CIS AWS Foundations Benchmark has long recommended rotating credentials at least every 90 days, and the AWS Config managed rule access-keys-rotated defaults to that window. The stronger move is to eliminate long-lived keys entirely: use IAM roles for workloads and short-lived, federated credentials for people, so there is nothing to rotate.
02What is the safest way to rotate a key without breaking things?
Use the two-key method. IAM allows two access keys per user, so you can create a second key, deploy it everywhere the old one is used, then set the old key to Inactive (not deleted). Watch the last-used data for a few days to confirm nothing still calls the old key, then delete it. This gives you an instant rollback if a service was missed.
03How do I find which keys are stale?
Generate the account credential report (aws iam generate-credential-report, then get-credential-report) — its CSV lists every user with access_key_1_last_rotated and access_key_1_last_used_date. Anything not rotated in over 90 days, or never used, is a candidate. For a single key, aws iam get-access-key-last-used shows the last service and region it touched.
04Should the root user have access keys at all?
No. AWS guidance is to have zero long-lived access keys on the root user — a leaked root key is account-wide and cannot be scoped. If root keys exist, sign in as root, delete them under Security credentials, and use IAM roles or IAM Identity Center users for everyday work.
05Can I enforce a maximum key age automatically?
AWS does not expire keys on its own, but the AWS Config managed rules access-keys-rotated (ACCESS_KEYS_ROTATED) and iam-user-unused-credentials-check flag keys older than a set age and dormant credentials, so you get continuous drift detection instead of a one-off cleanup.
06Does CloudArq rotate the keys for me?
No. CloudArq is a read-only audit — it connects through a read-only IAM role with an ExternalId, never stores your credentials, and never auto-fixes anything. It detects stale, root, and unused IAM credentials and hands you the exact CLI and Terraform steps to rotate or remove them; you apply the change.

Find every stale key in one read-only pass

CloudArq connects through a read-only IAM role with an ExternalId, never stores your credentials, and never auto-fixes anything. It surfaces old, root, and unused IAM keys alongside the rest of your posture and cost findings — each with the exact CLI and Terraform to remediate. See the agentless CSPM overview or the security model, and browse more AWS security & cost guides.