Finding Unused IAM Credentials (AWS Access Keys)
To increase the security of our AWS account, we need to update IAM user credentials (passwords and access keys) sooner rather than later that are not needed anymore. Updating or removing unused credentials is one of the best practices for IAM. In this article, we will see how to find unused credentials and notify users(admin).
The definition of unused can change and in this article it means a credential that has not been used within a specified period of time.
We will schedule a lambda function using AWS CloudWatch to be invoked periodically. Lambda function will list all the user credentials and will check last used time of credentials and if last used time is more than 45 days, it will notify users with SNS.

1- First we will create a Lambda function.
You can see how to create Lambda function in here.
2- In addition to Lambda function policy we created with Lambda, we will attach following permissions to newly created IAM role.
{
"Effect": "Allow",
"Action": [
"iam:ListUsers",
"iam:ListAccessKeys",
"iam:GetAccessKeyLastUsed",
"iam:DeleteAccessKey",
"iam:DeleteLoginProfile",
"iam:DeleteUser"
],
"Resource": [
"*"
]
}
3. We will write our Lambda function code.
We assume we already have SNS topic and subscription as email and we are going to use in our Lambda function.
import json
import boto3
from datetime import datetime
from datetime import timedelta
from botocore.exceptions import ClientError
list_users_to_notify = []
list_access_keys_to_notify = []
date_now = datetime.now()
iam_client = boto3.client('iam')
sns_client = boto3.client('sns')
max_idle_days = 45
max_items = 50
def lambda_handler(event, context):
#Retrieve list of users using list_users() method
try:
res_users = iam_client.list_users(
MaxItems=max_items
)
#call a custom function check_credentials() which will check last used time for the given user
check_credentials(res_users)
except ClientError as error:
print('An error occurred while fetching user list.', error)
return
#We will use pagination using MaxItems, Marker and IsTruncated parameters, because there can be many users
if res_users['IsTruncated']:
while res_users['IsTruncated']:
marker = res_users['Marker']
try:
res_users = iam_client.list_users(
Marker=marker,
MaxItems=max_items
)
check_credentials(res_users)
except ClientError as error:
print('An error occurred while fetching user list.', error)
return
return list_access_keys_to_notify
def check_credentials(res_users):
created_date = datetime.now()
last_used_date = datetime.now()
access_key_id = None
for user in res_users['Users']:
# Below we are checking for access keys last usage
try:
res_keys = iam_client.list_access_keys(
UserName=user['UserName'],
MaxItems=2)
if 'AccessKeyMetadata' in res_keys:
for key in res_keys['AccessKeyMetadata']:
if 'CreateDate' in key:
created_date = res_keys['AccessKeyMetadata'][0]['CreateDate'].replace(tzinfo=None)
if 'AccessKeyId' in key:
access_key_id = key['AccessKeyId']
res_last_used_key = iam_client.get_access_key_last_used(
AccessKeyId=access_key_id)
if 'LastUsedDate' in key:
last_used_date = res_last_used_key['AccessKeyLastUsed']['LastUsedDate'].replace(tzinfo=None)
else:
last_used_date = created_date
difference = date_now - last_used_date
if difference.days > max_idle_days:
response = sns_client.publish(
TopicArn='<YourSNSTopicARN',
Message='Ensure credentials unused for 45 days or greater are updated for user: "{0}". It is recommended that all credentials that have been unused in 45 or greater days be deactivated or removed. If we will use, we should update our access key.'.format(user['UserName']),
Subject='Access keys need to be updated',
MessageStructure='string'
)
list_access_keys_to_notify.append(access_key_id)
except ClientError as error:
print('An error occurred while listing access keys', error)
return
4- Next, we will schedule our Lambda function using Amazon EventBridge rule. As shown below, create a EventBridge scheduled rule to invoke our Lambda function periodically every day at 10 AM UTC.
Select EventBridge service in AWS Console →Click on Rules →Create Rule

Enter your rule name and description. Select “Schedule” in “Rule type” and next

Select schedule pattern and Cron expression as (0 10 * * ? *)

Select AWS service and Lambda function as target → Choose your Lambda function

Thank you so much for reading this article, I hope it has helped simplify the process of your case.
If you have any questions, please feel free to drop a comment or to write me on LinkedIn, and I’ll be happy to answer it for you.
If this article helped you out I’d appreciate you letting me know with a few claps or a follow on Medium, thank you.