seahaven-account-baseline/scripts/iam-user-delete.sh
Adam Moussa 0dd8d2a7af
Docs + tooling: README phase-2 backup, iam-user-delete script (#10)
README: document AWS Backup phase-2 (phase2-offsite-everything selection),
remove retired database-1 from phase-1 scope (audit H-19), update roadmap +
verify smoke-test to a live resource.

scripts/iam-user-delete.sh: reusable full IAM user teardown (keys, policies,
groups, MFA, login profile, certs, SSH keys, service creds, then user) with
--profile/--yes and a guard against deleting the caller's own identity. Built
from the Day 4 audit IAM cleanup.
2026-06-03 13:15:18 -04:00

109 lines
4.8 KiB
Bash
Executable file

#!/usr/bin/env bash
#
# iam-user-delete.sh — fully delete one or more IAM users (account 328440206208).
#
# IAM refuses to delete a user that still has attached/inline policies, access
# keys, group memberships, MFA devices, a login profile, signing certs, SSH keys,
# or service-specific credentials. This tears all of that down in order, then
# deletes the user. Built from the Day 4 audit cleanup (frappe/termius/ledgerflow,
# then office_mac/home_desktop/Personal-laptop). See reference memory
# `reference_identity_center_workmail` for the SSO context.
#
# Usage:
# scripts/iam-user-delete.sh [--profile NAME] [--yes] USER [USER ...]
#
# --profile NAME AWS CLI profile (default: $AWS_PROFILE or the default chain).
# Post-SSO-cutover this is normally `amoussa-seahaven`.
# --yes Skip the per-user confirmation prompt.
#
# Safety:
# * Refuses to delete the user the current credentials authenticate as.
# * Deactivates access keys before deleting them (a brief, reversible window
# if you remove --yes and inspect between users).
# * Prints each user's attachments before deleting so there is a record.
#
set -euo pipefail
PROFILE_ARG=()
ASSUME_YES=0
USERS=()
while [[ $# -gt 0 ]]; do
case "$1" in
--profile) PROFILE_ARG=(--profile "$2"); shift 2 ;;
--yes|-y) ASSUME_YES=1; shift ;;
-h|--help) sed -n '2,30p' "$0"; exit 0 ;;
-*) echo "unknown flag: $1" >&2; exit 2 ;;
*) USERS+=("$1"); shift ;;
esac
done
[[ ${#USERS[@]} -eq 0 ]] && { echo "usage: $0 [--profile NAME] [--yes] USER [USER ...]" >&2; exit 2; }
aws_() { aws "${PROFILE_ARG[@]}" "$@"; }
# Guard: never delete the identity we're running as.
SELF_ARN="$(aws_ sts get-caller-identity --query Arn --output text)"
echo "running as: $SELF_ARN"
delete_user() {
local u="$1"
if ! aws_ iam get-user --user-name "$u" >/dev/null 2>&1; then
echo " $u: does not exist, skipping"; return 0
fi
if [[ "$SELF_ARN" == *":user/$u" ]]; then
echo " $u: REFUSING — this is the identity you are authenticated as" >&2; return 1
fi
echo "== $u =="
echo " keys: $(aws_ iam list-access-keys --user-name "$u" --query 'AccessKeyMetadata[].AccessKeyId' --output text)"
echo " attached: $(aws_ iam list-attached-user-policies --user-name "$u" --query 'AttachedPolicies[].PolicyName' --output text)"
echo " inline: $(aws_ iam list-user-policies --user-name "$u" --query 'PolicyNames' --output text)"
echo " groups: $(aws_ iam list-groups-for-user --user-name "$u" --query 'Groups[].GroupName' --output text)"
if [[ $ASSUME_YES -eq 0 ]]; then
read -r -p " delete user '$u'? [y/N] " ans
[[ "$ans" =~ ^[Yy]$ ]] || { echo " skipped"; return 0; }
fi
# access keys: deactivate (reversible) then delete
for k in $(aws_ iam list-access-keys --user-name "$u" --query 'AccessKeyMetadata[].AccessKeyId' --output text); do
aws_ iam update-access-key --user-name "$u" --access-key-id "$k" --status Inactive
aws_ iam delete-access-key --user-name "$u" --access-key-id "$k"
done
# detach managed policies
for p in $(aws_ iam list-attached-user-policies --user-name "$u" --query 'AttachedPolicies[].PolicyArn' --output text); do
aws_ iam detach-user-policy --user-name "$u" --policy-arn "$p"
done
# delete inline policies
for ip in $(aws_ iam list-user-policies --user-name "$u" --query 'PolicyNames[]' --output text); do
aws_ iam delete-user-policy --user-name "$u" --policy-name "$ip"
done
# remove from groups
for g in $(aws_ iam list-groups-for-user --user-name "$u" --query 'Groups[].GroupName' --output text); do
aws_ iam remove-user-from-group --user-name "$u" --group-name "$g"
done
# MFA devices
for m in $(aws_ iam list-mfa-devices --user-name "$u" --query 'MFADevices[].SerialNumber' --output text); do
aws_ iam deactivate-mfa-device --user-name "$u" --serial-number "$m"
done
# login profile (console password)
aws_ iam delete-login-profile --user-name "$u" 2>/dev/null || true
# signing certs
for c in $(aws_ iam list-signing-certificates --user-name "$u" --query 'Certificates[].CertificateId' --output text 2>/dev/null); do
aws_ iam delete-signing-certificate --user-name "$u" --certificate-id "$c"
done
# SSH public keys (CodeCommit)
for s in $(aws_ iam list-ssh-public-keys --user-name "$u" --query 'SSHPublicKeys[].SSHPublicKeyId' --output text 2>/dev/null); do
aws_ iam delete-ssh-public-key --user-name "$u" --ssh-public-key-id "$s"
done
# service-specific credentials
for sc in $(aws_ iam list-service-specific-credentials --user-name "$u" --query 'ServiceSpecificCredentials[].ServiceSpecificCredentialId' --output text 2>/dev/null); do
aws_ iam delete-service-specific-credential --user-name "$u" --service-specific-credential-id "$sc"
done
aws_ iam delete-user --user-name "$u"
echo " $u: deleted"
}
rc=0
for u in "${USERS[@]}"; do delete_user "$u" || rc=1; done
exit $rc