This script is designed to check for inactive IAM (Identity and Access Management) users within a specified AWS account. It utilizes the AWS SDK for Python (Boto3) to retrieve user data and provides information about the last console access and last programmatic access for each user.
Code
"""
AWS IAM User Inactivity Checker
Author: Mario Lechończak (mario at lechonczak.pl)
"""
import csv
import sys
from datetime import datetime
import boto3
import pytz
# Define variable
max_date = sys.argv[1]
AWS_PROFILE = sys.argv[2]
AWS_REGION = "eu-central-1"
# Initialize session
session = boto3.Session(profile_name=AWS_PROFILE)
iam = session.client('iam', region_name=AWS_REGION)
def get_inactive_iam_users(max_date):
# Get list of users
users = iam.list_users()['Users']
user_data = []
target_date = datetime.strptime(max_date, "%Y-%m-%d").replace(tzinfo=pytz.UTC)
for user in users:
create_date = user['CreateDate']
# use create_date if PasswordLastUsed is not available
last_used_date = user.get('PasswordLastUsed', create_date)
if create_date <= target_date and last_used_date <= target_date:
# Get the last console access date
last_console_access_response = iam.get_user(UserName=user['UserName'])
last_console_access = last_console_access_response['User'].get('PasswordLastUsed', None)
# Get list of access keys
access_keys = iam.list_access_keys(UserName=user['UserName'])['AccessKeyMetadata']
last_key_used_date = datetime.min.replace(tzinfo=pytz.UTC) # Initialize to a minimum date
for key in access_keys:
# Get last used date of access key
last_used_response = iam.get_access_key_last_used(AccessKeyId=key['AccessKeyId'])
if last_used_response['AccessKeyLastUsed'].get('LastUsedDate') is not None:
last_key_used_date = max(
last_key_used_date,
last_used_response['AccessKeyLastUsed'].get('LastUsedDate')
)
# If last used date of any key is more recent than the target date,
# move to the next user
if last_key_used_date >= target_date:
continue
if last_key_used_date == datetime.min.replace(tzinfo=pytz.UTC):
last_key_used_date = None
user_data.append([user['UserName'], str(last_console_access), str(last_key_used_date)])
return user_data
def save_user_info_to_csv(user_data):
current_date = datetime.now().strftime("%Y-%m-%d")
filename = f"output_{AWS_PROFILE}_{current_date}.csv"
with open(filename, mode='w', newline='', encoding="utf-8") as csv_file:
writer = csv.writer(csv_file)
writer.writerow(["User", "Last Console Access", "Last Programmatic Access"])
for user_info in user_data:
writer.writerow(user_info)
def print_inactive_iam_users(user_data):
print(f"{'User':<20}{'Last Console Access':<25}{'Last Programmatic Access':<25}")
for user_info in user_data:
user = user_info[0]
last_console_access = user_info[1]
last_programmatic_access = user_info[2]
print(f"{user:<20}{last_console_access:<25}{last_programmatic_access:<25}")
if __name__ == "__main__":
get_inactive_iam_users(max_date)
print_inactive_iam_users(get_inactive_iam_users(max_date))
save_user_info_to_csv(get_inactive_iam_users(max_date))
Functions
get_inactive_iam_users(max_date)
This function retrieves and identifies inactive IAM users based on a specific target date. It takes in the max_date parameter, which represents the target date in “YYYY-MM-DD” format. The function first initializes the AWS session using the provided AWS profile name and region. It then uses the IAM client to fetch information about all IAM users in the account. For each user, it checks if their creation date and last used date (either console access or programmatic access) are before or on the target date. If both dates are before or on the target date, the user is considered inactive. The function compiles a list of user data for inactive users, including their username, last console access date, and last programmatic access date.
print(get_inactive_iam_users(max_date))
[['user1', 'None', '2023-02-10 18:16:00+00:00'], ['user2', 'None', '2023-10-27 17:50:00+00:00'], ['user3', 'None', '2023-08-17 06:26:00+00:00']]
save_user_info_to_csv(user_data)
This function saves the user data obtained from get_inactive_iam_users to a CSV file. It takes in the user_data parameter, which is a list of user data to be saved to the CSV file. The function also uses the AWS_PROFILE and current_date variables to generate a filename for the CSV file. It opens the file in write mode and creates a CSV writer object. It writes a header row with column names: “User,” “Last Console Access,” and “Last Programmatic Access.” It then iterates over the user data list and writes each user’s information as a row in the CSV file.
mario@local:~$ cat output_personal_2023_10_31.csv
User,Last Console Access,Last Programmatic Access
user1,None,2023-02-10 18:16:00+00:00
user2,None,2023-10-27 17:50:00+00:00
user3,None,2023-08-17 06:26:00+00:00
print_inactive_iam_users(user_data)
This function prints the user data obtained from get_inactive_iam_users in a tabular format for easy readability. It takes in the user_data parameter, which is a list of user data to be displayed in the tabular format. The function uses string formatting to align the data within columns. It prints a header row with column names: “User,” “Last Console Access,” and “Last Programmatic Access.” It then iterates over the user data list and prints each user’s information as a row in the tabular format.
mario@local:~$ python3 main.py 2023-10-31 personal
User Last Console Access Last Programmatic Access
user1 None 2023-02-10 18:16:00+00:00
user2 None 2023-10-27 17:50:00+00:00
user3 None 2023-08-17 06:26:00+00:00
Usage
To use this script, you need to provide two command line arguments:
max_date
: The target date in “YYYY-MM-DD” format to determine user inactivity.
AWS_PROFILE
: The AWS profile name used to initialize the session.
Here is an example command to run the script:
python3 main.py 2022-01-01 my-aws-profile
The script will retrieve the inactive IAM users based on the provided target date, print their data in a tabular format, and save the data to a CSV file named output_<AWS_PROFILE>_<current_date>.csv
.
The CSV file includes the user data with columns User
, Last Console Access
, and Last Programmatic Access
.