Add script for batch deletion of AWS IAM users
This commit is contained in:
parent
6b49d958d8
commit
b117557525
1 changed files with 125 additions and 0 deletions
125
aws/delete-iam-users.py
Executable file
125
aws/delete-iam-users.py
Executable file
|
@ -0,0 +1,125 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
#
|
||||||
|
# Deleting a user programmatically requires deletion of several
|
||||||
|
# entities for each user:
|
||||||
|
#
|
||||||
|
# Password ( DeleteLoginProfile)
|
||||||
|
# Access keys ( DeleteAccessKey)
|
||||||
|
# Signing certificate ( DeleteSigningCertificate)
|
||||||
|
# SSH public key ( DeleteSSHPublicKey)
|
||||||
|
# Git credentials ( DeleteServiceSpecificCredential)
|
||||||
|
# Multi-factor authentication (MFA) device ( DeactivateMFADevice, DeleteVirtualMFADevice)
|
||||||
|
# Inline policies ( DeleteUserPolicy)
|
||||||
|
# Attached managed policies ( DetachUserPolicy)
|
||||||
|
# Group memberships ( RemoveUserFromGroup)
|
||||||
|
#
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import boto3
|
||||||
|
import botocore
|
||||||
|
|
||||||
|
iam_client = boto3.client("iam")
|
||||||
|
|
||||||
|
def list_all(paginator_name, collection_name, key_name, init_args):
|
||||||
|
result = []
|
||||||
|
paginator = iam_client.get_paginator(paginator_name)
|
||||||
|
for page in paginator.paginate(**init_args):
|
||||||
|
for item in page.get(collection_name, []):
|
||||||
|
if key_name:
|
||||||
|
result.append(item[key_name])
|
||||||
|
else:
|
||||||
|
result.append(item)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def list_access_keys(user_name):
|
||||||
|
return list_all("list_access_keys", "AccessKeyMetadata", "AccessKeyId", {"UserName": user_name})
|
||||||
|
|
||||||
|
|
||||||
|
def list_signing_certificates(user_name):
|
||||||
|
return list_all("list_signing_certificates", "Certificates", "CertificateId", {"UserName": user_name})
|
||||||
|
|
||||||
|
|
||||||
|
def list_ssh_public_keys(user_name):
|
||||||
|
return list_all("list_ssh_public_keys", "SSHPublicKeys", "SSHPublicKeyId", {"UserName": user_name})
|
||||||
|
|
||||||
|
|
||||||
|
def list_mfa_devices(user_name):
|
||||||
|
return list_all("list_mfa_devices", "MFADevices", "SerialNumber", {"UserName": user_name})
|
||||||
|
|
||||||
|
|
||||||
|
def list_service_specific_credentials(user_name):
|
||||||
|
credential_ids = []
|
||||||
|
response = iam_client.list_service_specific_credentials(UserName=user_name)
|
||||||
|
for item in response.get("ServiceSpecificCredentials", []):
|
||||||
|
credential_ids.append(item["ServiceSpecificCredentialId"])
|
||||||
|
return credential_ids
|
||||||
|
|
||||||
|
|
||||||
|
def list_inline_policies(user_name):
|
||||||
|
return list_all("list_user_policies", "PolicyNames", None, {"UserName": user_name})
|
||||||
|
|
||||||
|
|
||||||
|
def list_attached_policies(user_name):
|
||||||
|
return list_all("list_attached_user_policies", "AttachedPolicies", "PolicyArn", {"UserName": user_name})
|
||||||
|
|
||||||
|
|
||||||
|
def list_groups(user_name):
|
||||||
|
return list_all("list_groups_for_user", "Groups", "GroupName", {"UserName": user_name})
|
||||||
|
|
||||||
|
|
||||||
|
def delete_user(user_name, dry_run=True):
|
||||||
|
print(f"Delete user {user_name}:")
|
||||||
|
user = iam_client.get_user(UserName=user_name)
|
||||||
|
try:
|
||||||
|
if not dry_run:
|
||||||
|
iam_client.delete_login_profile(UserName=user_name)
|
||||||
|
print(" Delete login profile")
|
||||||
|
except botocore.exceptions.ClientError as err:
|
||||||
|
if err.response["Error"]["Code"] != "NoSuchEntity":
|
||||||
|
raise
|
||||||
|
for key_id in list_access_keys(user_name):
|
||||||
|
if not dry_run:
|
||||||
|
iam_client.delete_access_key(UserName=user_name, AccessKeyId=key_id)
|
||||||
|
print(f" Delete access key {key_id}")
|
||||||
|
for cert_id in list_signing_certificates(user_name):
|
||||||
|
if not dry_run:
|
||||||
|
iam_client.delete_signing_certificate(UserName=user_name, CertificateId=cert_id)
|
||||||
|
print(f" Delete signing certificate {cert_id}")
|
||||||
|
for key_id in list_ssh_public_keys(user_name):
|
||||||
|
if not dry_run:
|
||||||
|
iam_client.delete_ssh_public_key(UserName=user_name, SSHPublicKeyId=key_id)
|
||||||
|
print(f" Delete SSH public key {key_id}")
|
||||||
|
for cred_id in list_service_specific_credentials(user_name):
|
||||||
|
if not dry_run:
|
||||||
|
iam_client.delete_service_specific_credential(UserName=user_name, ServiceSpecificCredentialId=cred_id)
|
||||||
|
print(f" Delete service-specific credential {cred_id}")
|
||||||
|
for serial_no in list_mfa_devices(user_name):
|
||||||
|
if not dry_run:
|
||||||
|
iam_client.deactivate_mfa_device(UserName=user_name, SerialNumber=serial_no)
|
||||||
|
iam_client.delete_virtual_mfa_device(SerialNumber=serial_no)
|
||||||
|
print(f" Delete MFA device {serial_no}")
|
||||||
|
for policy_name in list_inline_policies(user_name):
|
||||||
|
if not dry_run:
|
||||||
|
iam_client.delete_user_policy(UserName=user_name, PolicyName=policy_name)
|
||||||
|
print(f" Delete inline policy {policy_name}")
|
||||||
|
for policy_arn in list_attached_policies(user_name):
|
||||||
|
if not dry_run:
|
||||||
|
iam_client.detach_user_policy(UserName=user_name, PolicyArn=policy_arn)
|
||||||
|
print(f" Detach policy {policy_arn}")
|
||||||
|
for group_name in list_groups(user_name):
|
||||||
|
if not dry_run:
|
||||||
|
iam_client.remove_user_from_group(UserName=user_name, GroupName=group_name)
|
||||||
|
print(f" Remove user from group {group_name}")
|
||||||
|
if not dry_run:
|
||||||
|
iam_client.delete_user(UserName=user_name)
|
||||||
|
print(f" Deleted {user_name}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
parser = argparse.ArgumentParser(description="Delete IAM user(s)")
|
||||||
|
parser.add_argument("--dry-run", help="Show the actions that would be performed", action=argparse.BooleanOptionalAction, default=True)
|
||||||
|
parser.add_argument("user_names", nargs="+", )
|
||||||
|
args = parser.parse_args()
|
||||||
|
for user_name in args.user_names:
|
||||||
|
delete_user(user_name, args.dry_run)
|
Loading…
Reference in a new issue