Quick Fix: Remove IAM User
Outcome
The IAM user will be deleted from the AWS account, eliminating a stale or unnecessary principal that could be compromised. Removing unused users reduces your account's attack surface.
For example, after applying this fix:
- An IAM user
former-contractorthat hasn't been used in 180 days will no longer exist as an authenticatable identity - An IAM user
temp-deploy-usercreated for a one-time migration will no longer be available for abuse
Fix
Step 1: Set the target user
USER_NAME="the-user-to-remove"
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
USER_ARN="arn:aws:iam::${ACCOUNT_ID}:user/${USER_NAME}"
Step 2: Check for KMS key policy references
Before deleting the user, verify it is not referenced in any customer managed KMS key policies. Deleting a user that is the sole grantee in a KMS key policy can result in losing access to encrypted data.
# List all customer managed KMS keys in the account
KMS_KEY_IDS=$(aws kms list-keys --query 'Keys[*].KeyId' --output text)
# Check each key's policy for references to the user
for KEY_ID in ${KMS_KEY_IDS}; do
KEY_POLICY=$(aws kms get-key-policy --key-id "${KEY_ID}" --policy-name default --output text 2>/dev/null)
if echo "${KEY_POLICY}" | grep -q "${USER_NAME}\|${USER_ARN}"; then
echo "WARNING: KMS key ${KEY_ID} references ${USER_NAME}"
echo "${KEY_POLICY}" | grep -B2 -A2 "${USER_NAME}\|${USER_ARN}"
echo "---"
fi
done
If any KMS keys reference the user, update those key policies to grant access to an alternative principal before proceeding. Otherwise you risk losing the ability to decrypt data protected by those keys.
Step 3: Remove credentials
Delete the user's access keys, login profile (console password), MFA devices, signing certificates, SSH public keys,
and service-specific credentials. The AWS CLI delete-user command requires all of these to be removed first.
# Delete all access keys
for KEY_ID in $(aws iam list-access-keys \
--user-name "${USER_NAME}" \
--query 'AccessKeyMetadata[*].AccessKeyId' --output text); do
echo "Deleting access key: ${KEY_ID}"
aws iam delete-access-key \
--user-name "${USER_NAME}" \
--access-key-id "${KEY_ID}"
done
# Delete login profile (console password) if it exists
aws iam delete-login-profile --user-name "${USER_NAME}" 2>/dev/null \
&& echo "Deleted login profile" \
|| echo "No login profile to delete"
# Deactivate and delete MFA devices
for MFA_SERIAL in $(aws iam list-mfa-devices \
--user-name "${USER_NAME}" \
--query 'MFADevices[*].SerialNumber' --output text); do
echo "Deactivating MFA device: ${MFA_SERIAL}"
aws iam deactivate-mfa-device \
--user-name "${USER_NAME}" \
--serial-number "${MFA_SERIAL}"
# Delete virtual MFA devices (hardware devices cannot be deleted via API)
if echo "${MFA_SERIAL}" | grep -q ":mfa/"; then
aws iam delete-virtual-mfa-device --serial-number "${MFA_SERIAL}" 2>/dev/null
fi
done
# Delete signing certificates
for CERT_ID in $(aws iam list-signing-certificates \
--user-name "${USER_NAME}" \
--query 'Certificates[*].CertificateId' --output text); do
echo "Deleting signing certificate: ${CERT_ID}"
aws iam delete-signing-certificate \
--user-name "${USER_NAME}" \
--certificate-id "${CERT_ID}"
done
# Delete SSH public keys
for SSH_KEY_ID in $(aws iam list-ssh-public-keys \
--user-name "${USER_NAME}" \
--query 'SSHPublicKeys[*].SSHPublicKeyId' --output text); do
echo "Deleting SSH public key: ${SSH_KEY_ID}"
aws iam delete-ssh-public-key \
--user-name "${USER_NAME}" \
--ssh-public-key-id "${SSH_KEY_ID}"
done
# Delete service-specific credentials (e.g. CodeCommit Git credentials)
for CRED_ID in $(aws iam list-service-specific-credentials \
--user-name "${USER_NAME}" \
--query 'ServiceSpecificCredentials[*].ServiceSpecificCredentialId' --output text); do
echo "Deleting service-specific credential: ${CRED_ID}"
aws iam delete-service-specific-credential \
--user-name "${USER_NAME}" \
--service-specific-credential-id "${CRED_ID}"
done
Step 4: Remove policies and group memberships
# Detach all managed policies
for POLICY_ARN in $(aws iam list-attached-user-policies \
--user-name "${USER_NAME}" \
--query 'AttachedPolicies[*].PolicyArn' --output text); do
echo "Detaching managed policy: ${POLICY_ARN}"
aws iam detach-user-policy \
--user-name "${USER_NAME}" \
--policy-arn "${POLICY_ARN}"
done
# Delete all inline policies
for POLICY_NAME in $(aws iam list-user-policies \
--user-name "${USER_NAME}" \
--query 'PolicyNames[*]' --output text); do
echo "Deleting inline policy: ${POLICY_NAME}"
aws iam delete-user-policy \
--user-name "${USER_NAME}" \
--policy-name "${POLICY_NAME}"
done
# Remove from all groups
for GROUP_NAME in $(aws iam list-groups-for-user \
--user-name "${USER_NAME}" \
--query 'Groups[*].GroupName' --output text); do
echo "Removing user from group: ${GROUP_NAME}"
aws iam remove-user-from-group \
--user-name "${USER_NAME}" \
--group-name "${GROUP_NAME}"
done
Step 5: Delete the user
aws iam delete-user --user-name "${USER_NAME}"
Verify the fix
Confirm the user no longer exists:
aws iam get-user --user-name "${USER_NAME}" 2>&1
This should return a NoSuchEntity error, confirming the user has been deleted.
References
- AWS: Remove or deactivate an IAM user
- AWS: Key policies in AWS KMS
- k9 Security Kata 1: Review AWS IAM administrators
Gotcha
Deleting an IAM user that is referenced in a KMS key policy can cause you to lose access to encrypted data. KMS key policies are resource-based policies that grant permissions independently of IAM policies. If the deleted user was the only principal authorized to use a KMS key, no one will be able to decrypt data encrypted with that key (short of contacting AWS Support). Always run the KMS key policy check in Step 2 and update any references before deleting the user.