This check flags any IAM user with two active access keys at once, which doubles the number of long-lived credentials that can leak and be abused. Keep one active key per user, rotate cleanly using the two-slot window, then deactivate and delete the old one.
AWS gives every IAM user up to two access keys. That second slot exists for one specific reason: rotating credentials without downtime. The trouble is that many teams create the second key, finish the rotation, and never clean up. The result is a user sitting on two permanently active keys, each one a fully functional path into your account.
The user_multipleaccesskeys check in the user_checks module looks at every IAM user and reports any that have two access keys in the Active state at the same time.
What this check detects
Each IAM access key has a status of either Active or Inactive. The check is simple: if a single IAM user has two keys and both are marked Active, it fails.
You can reproduce the check manually with the CLI:
aws iam list-access-keys --user-name deploy-bot
A failing user looks like this:
{
"AccessKeyMetadata": [
{
"UserName": "deploy-bot",
"AccessKeyId": "AKIAEXAMPLE1111111111",
"Status": "Active",
"CreateDate": "2024-02-10T09:14:00Z"
},
{
"UserName": "deploy-bot",
"AccessKeyId": "AKIAEXAMPLE2222222222",
"Status": "Active",
"CreateDate": "2024-08-22T16:31:00Z"
}
]
}
Note: Having two keys is not itself an AWS error. The platform allows it precisely so you can rotate. The check fires on the combination of two keys that are both active, which usually means a rotation was started and never finished.
Why it matters
Access keys are long-lived static credentials. Unlike a role session that expires in an hour, an access key works until someone deactivates it. Every active key is a standing risk, and two active keys means two independent ways for an attacker to authenticate as that user.
Wider attack surface
Static keys leak in predictable ways: committed to a Git repo, pasted into a Slack message, baked into a Docker image, left in a CI environment variable, or exposed through a misconfigured S3 bucket. With two active keys, you have two credentials that can leak, and revoking one does nothing to stop an attacker who grabbed the other.
Harder to reason about during an incident
When you respond to a suspected credential compromise, the first move is usually to disable the key and check CloudTrail for what it touched. Two active keys complicate that. You have to chase down both, correlate activity across both accessKeyId values, and make sure you did not miss one. In a high-pressure incident, the extra key is exactly the kind of thing that gets overlooked.
Warning: A forgotten second key is often the oldest one, created years ago, never rotated, and tied to a script no one remembers. Those keys frequently outlive the person who made them and carry far more privilege than the current workload needs.
It signals a broken rotation process
If keys are piling up in the active state, your rotation almost certainly never completes the final two steps: deactivating and deleting the old key. That means stale credentials accumulate across the whole account, not just on this one user.
How to fix it
The goal is to get back to a single active key per user. If both keys are genuinely in use, that is a sign two different things are sharing one identity, which you should split into separate users or, better, move off keys entirely.
Step 1: Find out which key is actually being used
Check the last-used timestamp for each key before you touch anything:
aws iam get-access-key-last-used --access-key-id AKIAEXAMPLE1111111111
aws iam get-access-key-last-used --access-key-id AKIAEXAMPLE2222222222
The response tells you the date, region, and service the key last hit. The key with old or empty last-used data is your candidate for removal.
Step 2: Deactivate the unused key first
Do not delete straight away. Deactivating is reversible, so it gives you a safe window to confirm nothing breaks.
aws iam update-access-key \
--user-name deploy-bot \
--access-key-id AKIAEXAMPLE1111111111 \
--status Inactive
Leave it inactive for a day or two and watch for failures. If a job suddenly starts getting InvalidClientTokenId errors, you found a hidden consumer of that key and can reactivate it while you migrate the job.
Step 3: Delete the key once you are confident
Danger: Deleting an access key is permanent and cannot be undone. Any system still using it will immediately start failing authentication. Confirm the key has been inactive with no errors before running this.
aws iam delete-access-key \
--user-name deploy-bot \
--access-key-id AKIAEXAMPLE1111111111
Re-run the list command to confirm the user is back to a single active key.
If you actually need to rotate (the legitimate two-key flow)
The correct rotation sequence uses the second slot temporarily and never leaves both keys active long term:
- Create a new key:
aws iam create-access-key --user-name deploy-bot - Update every consumer of the credential to use the new key.
- Verify the new key works using
get-access-key-last-used. - Deactivate the old key (do not delete yet).
- After a soak period with no errors, delete the old key.
The two-active-keys state should only exist during steps 1 through 3, measured in minutes or hours, not months.
Tip: The cleanest fix is to stop using long-lived keys at all. For workloads on EC2, ECS, EKS, or Lambda, use IAM roles. For human users and CI systems, use IAM Identity Center or OIDC federation (for example GitHub Actions assuming a role via OIDC). No keys means no key rotation problem and nothing for this check to flag.
How to prevent it from happening again
Block long-lived keys with a Service Control Policy
If your workloads run on roles, you can deny key creation entirely at the org level so nobody recreates the problem:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyAccessKeyCreation",
"Effect": "Deny",
"Action": "iam:CreateAccessKey",
"Resource": "*"
}
]
}
Warning: A blanket deny on iam:CreateAccessKey will break any legitimate workflow that still depends on keys. Roll it out to a test OU first, and consider a condition that exempts a tightly controlled break-glass path before applying it org-wide.
Gate IAM changes in Terraform
If you manage IAM with Terraform, define at most one aws_iam_access_key per user and let code review catch the second. A policy-as-code rule with OPA or Conftest can fail the plan when a user ends up with two keys:
# run against a terraform plan converted to JSON
conftest test plan.json --policy ./policies/iam_keys.rego
{
"deny": "IAM user 'deploy-bot' defines 2 access keys; only 1 is allowed"
}
Detect and alert continuously
A CI gate only covers resources you manage as code. For console-created or drift-introduced keys, run a scheduled scan. A quick script you can drop into a Lambda or a cron job:
aws iam list-users --query 'Users[].UserName' --output text | tr '\t' '\n' | while read user; do
count=$(aws iam list-access-keys --user-name "$user" \
--query 'length(AccessKeyMetadata[?Status==`Active`])')
if [ "$count" -gt 1 ]; then
echo "ALERT: $user has $count active access keys"
fi
done
Tip: Lensix runs the user_multipleaccesskeys check continuously across your accounts, so you get notified the moment a user ends up with two active keys instead of finding out during your next manual audit.
Best practices
- One active key per user, always. Treat two active keys as a temporary rotation state, never a steady state.
- Prefer roles over keys. Use instance profiles, IRSA on EKS, and OIDC for CI to eliminate static credentials wherever possible.
- Rotate on a schedule. If you must use keys, rotate them on a fixed cadence (for example every 90 days) and finish the rotation by deleting the old key.
- Never share a user between humans and machines. A second key is often a sign that two consumers are squatting on one identity. Give each its own.
- Audit last-used data regularly. Keys that have never been used or have been idle for months should be deactivated and removed.
- Scope keys tightly. Attach the minimum permissions the workload needs so a leaked key does less damage.
A second active access key almost never reflects a real need. It reflects a rotation that stopped halfway. Finish the rotation, delete the old key, and where you can, get off keys entirely.

