Skip to content

Instantly share code, notes, and snippets.

@hernandanielg
Last active July 14, 2023 09:33
Show Gist options
  • Star 11 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save hernandanielg/430f3adb8e297f37ef6f0efb45a51bdc to your computer and use it in GitHub Desktop.
Save hernandanielg/430f3adb8e297f37ef6f0efb45a51bdc to your computer and use it in GitHub Desktop.
Bash script to delete IAM users using AWS cli tool
#!/bin/bash
#
# @author: Hernan Garcia <hernandanielg@gmail.com>
# https://gist.github.com/hernandanielg/430f3adb8e297f37ef6f0efb45a51bdc
#
# usage: ./delete_iam_user.sh [options] <user>
# options:
# -d|--dry-run dry run mode
#
AWS_CLI_IAM_CMD="aws iam"
list_items() {
local AWS_CLI_LIST_CMD="$1"
local AWS_CLI_LIST_QUERY="$2"
$AWS_CLI_IAM_CMD $AWS_CLI_LIST_CMD --user-name $user --query $AWS_CLI_LIST_QUERY --output text
}
remove_items() {
[[ -z $1 ]] && return 0
local ITEMS=$1
local AWS_CLI_DELETE_CMD="$2"
local AWS_CLI_ITEM_FLAG="$3"
for item in $ITEMS ;
do
local cmd="$AWS_CLI_IAM_CMD $AWS_CLI_DELETE_CMD --user-name $user --$AWS_CLI_ITEM_FLAG $item"
if [[ $DRY_RUN == true ]]; then
>&2 echo "[dry-run] $cmd"
continue
fi
>&2 echo "$cmd"
$cmd
done
}
usage() {
>&2 echo "usage: $0 [-d|--dry-run] <user>"
exit -1
}
unknown_flag() {
if [ "$OPTERR" = 1 ] && [ "${optspec:0:1}" != ":" ]; then
>&2 echo "Unknown flag --${OPTARG}"
usage
fi
}
check_user_exists() {
local user=$1
if [[ -z $($AWS_CLI_IAM_CMD get-user --user-name $user 2>/dev/null) ]]
then
>&2 echo "user not found: $user"
exit -2
fi
}
while getopts ":dh-:" optchar; do
case "${optchar}" in
-)
case "${OPTARG}" in
dry-run)
DRY_RUN=true
>&2 echo "dry run mode..."
;;
help)
usage
;;
*)
unknown_flag
;;
esac;;
d)
DRY_RUN=true
>&2 echo "dry run mode..."
;;
h)
usage
;;
*)
unknown_flag
;;
esac
done
shift "$(($OPTIND -1))"
if [ $# -eq 0 ]; then
usage
fi
user=$1
check_user_exists $user
echo -e "\nUser to be deleted: $user \n"
read -p "Type user name \"$user\" to continue: "
if [ "$REPLY" != $user ]; then
>&2 echo "Cancelled"
exit -3
fi
echo
while read listcmd filter deletecmd flag ;
do
items="$(list_items "$listcmd" "$filter")"
[[ -z $items ]] && continue
remove_items "$items" "$deletecmd" "$flag"
done <<EOF
list-access-keys AccessKeyMetadata[*].AccessKeyId delete-access-key access-key-id
list-signing-certificates Certificates[*].CertificateId delete-signing-certificate certificate-id
list-ssh-public-keys SSHPublicKeys[*].SSHPublicKeyId delete-ssh-public-key ssh-public-key
list-service-specific-credentials ServiceSpecificCredentials[*].ServiceSpecificCredentialId delete-service-specific-credential service-specific-credential-id
list-mfa-devices MFADevices[*].SerialNumber deactivate-mfa-device serial-number
list-mfa-devices MFADevices[*].SerialNumber delete-virtual-mfa-device serial-number
list-user-policies PolicyNames[*] delete-user-policy policy-name
list-attached-user-policies AttachedPolicies[*].PolicyArn detach-user-policy policy-arn
list-groups-for-user Groups[*].GroupName remove-user-from-group group-name
get-login-profile LoginProfile.UserName delete-login-profile user-name
get-user User.UserName delete-user user-name
EOF
@OliverGoetz
Copy link

Very useful, thanks for sharing this!

Just two observations:

  1. There's a typo in line 35: should be $user_access_keys instead of $user_accces_keys
  2. If the user has MFA devices configured it cannot be deleted in the end. The MFA devices need to be deactivated first. I'm not sure how the text output looks when there is more than one such device, as the documentation always only shows the json output format.

The command to list the MFA devices is aws iam list-mfa-devices --user $user.
The command to deactivate an MFA device is aws iam deactivate-mfa-device --user $user --serial-number $device_id

I will probably rewrite this to use the json output as I find it's easier and more stable to parse if you have something like jq installed.

@selfieebritto
Copy link

Work like charm. Thanks

@txynidakis
Copy link

Just a note/improvement from https://docs.aws.amazon.com/cli/latest/reference/iam/delete-user.html
I had an issue deleting a user because of Git Credentials ( DeleteServiceSpecificCredential )

I added

  # Delete Git Credentials
  while read -r GitCredential; do
    echo "For $user_name, deleting the Git Credencial $GitCredential" ;
    aws iam delete-service-specific-credential --user-name $user_name \
                                               --service-specific-credential-id $GitCredential ;
  done< <(aws iam list-service-specific-credentials --user-name $user_name | \
                jq -r '.ServiceSpecificCredentials[]|"\(.ServiceSpecificCredentialId)"')

@crabba
Copy link

crabba commented Sep 28, 2022

I adapted this to delete a role. I kept the first two loops (user_policies and user_attached_policies) and the last line (delete-user) then a global s/user/role/g, and it ran first time. Thanks!

@hernandanielg
Copy link
Author

Hey 👋

Thanks @txynidakis and @OliverGoetz for the observations!

I have updated the script to include new IAM user items, these didn't exist for the time when I created this script...

Cheers

@hernandanielg
Copy link
Author

Example execution:

$ bash delete_iam_user.sh test

User to be deleted: test

Type user name "test" to continue: test

aws iam delete-access-key --user-name test --access-key-id AKIAWVQYG7GQ7DZMGCHO
aws iam delete-signing-certificate --user-name test --certificate-id JONKNP74S5KA7UBTDJECSIRFPU2MVZII
aws iam delete-ssh-public-key --user-name test --ssh-public-key APKAWVQYG7GQSHA735PC
aws iam delete-service-specific-credential --user-name test --service-specific-credential-id ACCAWVQYG7GQ2TZKAA3MX
aws iam delete-service-specific-credential --user-name test --service-specific-credential-id ACCAWVQYG7GQ76CPKD7JW
aws iam delete-user-policy --user-name test --policy-name test
aws iam detach-user-policy --user-name test --policy-arn arn:aws:iam::aws:policy/AdministratorAccess
aws iam remove-user-from-group --user-name test --group-name Test2
aws iam remove-user-from-group --user-name test --group-name Test
aws iam delete-login-profile --user-name test --user-name test
aws iam delete-user --user-name test --user-name test

@lnvn
Copy link

lnvn commented Jul 14, 2023

Thank you for the script, It's very useful 🚀🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment