How to find and remove unused IAM users
Topic: Accounts access
Summary
Identify IAM users that have not signed in or used access keys recently using last-used timestamps and CloudTrail, then safely remove or deactivate them. Use this to reduce attack surface and meet compliance; avoid removing users that own critical resources.
Intent: How-to
Quick answer
- Use get-user (password last used) and get-access-key-last-used for each user and key to find users with no recent console or API activity.
- Cross-check CloudTrail for the user's principal ID over the last 90 days to confirm no activity; account for password and key last-used being updated only on use.
- Remove access keys and login profile, then delete the user after confirming no resource ownership (e.g. S3 bucket owner); or deactivate and tag for later deletion.
Prerequisites
Steps
-
List users and password last used
List all IAM users and get password last used (and access key last used per key); filter for users with no password last used or last used older than your threshold (e.g. 90 days).
-
Cross-check with CloudTrail
Query CloudTrail (or CloudTrail Lake) for events where userIdentity.principalId or userIdentity.userName matches the user, over the last 90 days; if no events, user is a candidate for removal.
-
Check resource ownership and dependencies
Ensure the user does not own resources (e.g. S3 bucket owner, EC2 resource tags); transfer or reassign ownership if needed; check for inline policies or group membership that might be referenced elsewhere.
-
Revoke and delete or deactivate
Delete all access keys and the login profile (see revoke guide); optionally detach policies and remove from groups; delete the user or leave deactivated with a tag for deletion after retention.
Summary
You will find unused IAM users using password and access key last-used data and CloudTrail, verify they do not own critical resources, then revoke access and delete or deactivate them. Use this for periodic cleanup and to reduce unused credentials.
Prerequisites
- IAM permissions to list users, get user details, list and get access key last used (iam:ListUsers, iam:GetUser, iam:ListAccessKeys, iam:GetAccessKeyLastUsed), and optionally CloudTrail read.
- A defined threshold for “unused” (e.g. no activity in 90 days).
Steps
Step 1: List users and password last used
aws iam list-users --query 'Users[].[UserName,CreateDate]' --output table
For each user, get password last used (only set when the user has signed in to the console):
aws iam get-user --user-name USERNAME --query 'User.PasswordLastUsed'
For each user’s access keys, get last used:
aws iam list-access-keys --user-name USERNAME
aws iam get-access-key-last-used --access-key-id AKIA...
Build a list of users with no PasswordLastUsed (or very old) and no access key last used (or all keys older than your threshold). Note: PasswordLastUsed is updated only when the user signs in to the console; access key last used is updated when the key is used for an API call.
Step 2: Cross-check with CloudTrail
In CloudTrail (or CloudTrail Lake), run a query for the last 90 days (or your threshold) filtered by:
userIdentity.type=IAMUseruserIdentity.userName= the candidate user name (oruserIdentity.principalId)
If there are no events, the user has had no API or console activity in that window. This confirms they are unused; password/key last-used can be delayed or missing for some edge cases.
Step 3: Check resource ownership and dependencies
- S3: List buckets and check ownership; if the user is the bucket owner, transfer ownership or update ACLs before deleting the user.
- Other resources: Check tags and resource policies that reference the user ARN; reassign or remove references.
- Inline policies / groups: List inline policies and groups for the user; removing the user from groups and deleting the user will drop these; ensure no automation assumes the user exists.
Step 4: Revoke and delete or deactivate
- Follow How to revoke an IAM user immediately: delete all access keys and the login profile.
- Detach all managed policies and remove the user from all groups (required before delete-user).
- Delete any inline policies:
aws iam delete-user-policy --user-name USERNAME --policy-name POLICYNAME - Delete the user:
aws iam delete-user --user-name USERNAME
If you must retain the user for audit, leave the user but with no keys and no login profile, and tag the user (e.g. pending-deletion) for deletion after your retention period.
Verification
- Unused users are identified from last-used and CloudTrail; no active use in the last 90 days.
- Revoked users have no access keys and no login profile; deleted users no longer appear in list-users.
- No resources are left orphaned or failing due to the removed user ARN.
Troubleshooting
PasswordLastUsed is null — The user may have never signed in to the console or only uses access keys; rely on access key last-used and CloudTrail for those users.
Delete user fails: entity in use — A resource (e.g. S3 bucket owner, inline policy name) still references the user. Fix the dependency (transfer bucket, delete inline policy) and retry.
Uncertain if user is used by automation — Search code and config for the user name or access key ID; check CloudTrail for the key ID. If in doubt, deactivate (remove keys and login profile) and monitor before deleting.