AWS IAM Automation
- IAM users spread across multiple AWS accounts. Offboarding meant logging into each console individually.
- Built a Python script with boto3 that iterates across AWS profiles, disables console access, deactivates API keys, and logs everything to Excel.
- One failure doesn't block the rest of the batch.
The problem
We had IAM users spread across multiple AWS accounts. Dev, staging, production, a couple of legacy accounts that still had active users. When someone left the company, their access needed to be revoked in every single one of those accounts. The AWS console makes this tedious because you have to switch accounts, find the user, delete their login profile, track down their API keys, and deactivate each one. Multiply that by four or five accounts per departure and it adds up fast.
I wrote a Python script using boto3 to handle the whole thing in one shot.
How it works
The script uses AWS CLI named profiles to iterate across multiple accounts. You configure a list of profile names at the top, and it loops through each one for every user being offboarded. For each user in each account, it does three things: deletes the login profile (kills console access), lists all access keys and deactivates them, and logs everything to an Excel file.
def disable_iam_user(username, profile): session = boto3.Session(profile_name=profile) iam_client = session.client('iam') # Delete login profile to disable console access try: iam_client.delete_login_profile(UserName=username) except ClientError as e: if e.response['Error']['Code'] == 'NoSuchEntity': pass # No console access in this account # Deactivate all API keys access_keys = iam_client.list_access_keys(UserName=username) for key in access_keys['AccessKeyMetadata']: iam_client.update_access_key( UserName=username, AccessKeyId=key['AccessKeyId'], Status='Inactive' )
Error handling matters here
The tricky part is that not every user exists in every account. If you try to delete a login profile for a user who doesn't have one, IAM throws a NoSuchEntity error. Same thing if the user doesn't exist in that account at all. The script catches those specifically and logs them as expected, rather than crashing out halfway through a batch.
The first version was bare bones. It worked, but if it hit an unexpected error on user 3 of 20, it would stop and you'd have to figure out where it left off. Version 2 wraps each user in its own try/catch so one failure doesn't block the rest of the batch.
The log file
Every action gets logged to an Excel file using pandas. For each user and account combination, the log records whether console access was disabled, whether API keys were found and deactivated, and any notes about errors or edge cases. That log file was important because security would sometimes ask for proof that a departed user's access was revoked across all accounts. Having the timestamped Excel report made those requests a two-second response instead of a manual audit.
What I learned
The main thing I learned building this was how much variance there is across AWS accounts in the same organization. Some users had console access in one account but only API keys in another. Some had access keys that were already inactive. Some existed in accounts that nobody on the current team knew about. Running the script across all profiles was actually a useful audit tool even outside of offboarding, because it showed us the full picture of who had access where.
Bulk offboarding and single-user disable scripts for IAM.