Clean up IAM users groups roles and policies
📑 On this page
Part 125 of AWS from Zero. This IAM checkpoint turns cleanup into a deliberate permission review rather than a collection of failing delete commands.
What we are learning
IAM resources cannot be deleted while dependent credentials, memberships, inline policies, managed-policy attachments, instance profiles, or policy versions remain.
Before you run it
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
USER_NAME="aws-zero-learner"
GROUP_NAME="aws-zero-readers"
ROLE_NAME="aws-zero-demo-role"
POLICY_ARN="arn:aws:iam::$ACCOUNT_ID:policy/AwsZeroListBuckets"Run all list commands first. Delete only resources created for this series and never production identities with similar names.
The command
aws iam list-access-keys --user-name "$USER_NAME"
aws iam list-user-policies --user-name "$USER_NAME"
aws iam list-attached-user-policies --user-name "$USER_NAME"
aws iam list-groups-for-user --user-name "$USER_NAME"
aws iam list-role-policies --role-name "$ROLE_NAME"
aws iam list-attached-role-policies --role-name "$ROLE_NAME"
aws iam list-policy-versions --policy-arn "$POLICY_ARN"
aws iam list-entities-for-policy --policy-arn "$POLICY_ARN"This inventory is the cleanup plan. Preserve identifiers and resolve each dependency before deleting parents.
Inspect the result
aws iam get-user --user-name "$USER_NAME"
aws iam get-group --group-name "$GROUP_NAME"
aws iam get-role --role-name "$ROLE_NAME"
aws iam get-policy --policy-arn "$POLICY_ARN"After cleanup, each command should return its corresponding NoSuchEntity error.
One tiny variation
# Example dependency order:
# 1. Delete user access keys, login profile, MFA devices, signing certificates.
# 2. Delete inline policies and detach managed policies.
# 3. Remove user from groups, then delete the user.
# 4. Empty and delete groups.
# 5. Remove role policies and instance-profile membership, then delete the role.
# 6. Delete non-default policy versions, then delete the managed policy.Turn this order into an idempotent script only after every list operation and scope check is explicit.
Common mistake
Do not hide DeleteConflict errors with broad force logic. The conflict names a dependency that deserves inspection.
Cleanup
aws iam list-users \
--query "Users[?starts_with(UserName, 'aws-zero')].UserName" \
--output text
aws iam list-roles \
--query "Roles[?starts_with(RoleName, 'aws-zero')].RoleName" \
--output text
aws iam list-policies \
--scope Local \
--query "Policies[?starts_with(PolicyName, 'AwsZero')].Arn" \
--output textAll three final inventories should be empty for the demo naming convention.
The next post will begin another AWS CLI track with the same one-small-step approach.