Created
October 30, 2017 23:41
-
-
Save andymotta/35ddd594ff8757573d1eda409e7cc615 to your computer and use it in GitHub Desktop.
Report AWS IAM access keys that require rotation within 45 days to SNS topic (Compliance)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import boto3 | |
from botocore.exceptions import ClientError | |
import datetime | |
from datetime import date | |
import os | |
from ConfigParser import SafeConfigParser | |
access_file = os.path.join(os.environ['HOME'], '.aws', 'credentials') | |
access_list = SafeConfigParser() | |
access_list.read(access_file) | |
global DEFAULT_WARNING_THRESHOLD_IN_DAYS | |
DEFAULT_WARNING_THRESHOLD_IN_DAYS = 45 | |
global DEFAULT_ROTATION_THRESHOLD_IN_DAYS | |
DEFAULT_ROTATION_THRESHOLD_IN_DAYS = 90 | |
def main(): | |
sns = boto3.client('sns') | |
access = generate_access_list() # Use sts_assume instead | |
offending = [] | |
for p in access: | |
#will loop through every boto profile on control machine | |
try: | |
if p == 'default': | |
print "Skipping 'default' access profile" | |
continue | |
os.environ["AWS_PROFILE"] = p | |
# Create a custom session to switch profiles later | |
session = boto3.session.Session() | |
global iam | |
iam = session.client('iam') | |
keys = iam_access_keys_due_for_rotation() | |
offending.append(p.upper()) | |
if keys: | |
offending.extend(keys) | |
else: | |
offending.append('No keys due for rotation in this account') | |
except: | |
raise | |
print "Skipping " + p | |
continue | |
msg = '\n\n'.join(offending) | |
response = sns.publish( | |
#fill in your sns topic arn here | |
TopicArn='arn:aws:sns:us-west-2:000000000000:iam-access-keys-requiring-rotation', | |
Message=msg, | |
Subject='IAM Access Keys Requiring Rotation' | |
) | |
def generate_access_list(): | |
lst = [] | |
for profile in access_list.sections(): | |
lst.append(profile) | |
return lst | |
def iam_access_keys_due_for_rotation(): | |
text = [] | |
try: | |
for user in iam.list_users()['Users']: | |
now = date(datetime.date.today().year, datetime.date.today().month, datetime.date.today().day) | |
for access_key in iam.list_access_keys(UserName = user['UserName'])['AccessKeyMetadata']: | |
if access_key['Status'] == 'Active': | |
# response = iam.get_access_key_last_used(AccessKeyId = access_key['AccessKeyId']) | |
# if 'LastUsedDate' in response['AccessKeyLastUsed']: | |
access_key_create_date = access_key['CreateDate'] | |
access_key_create_date = date(access_key_create_date.year, access_key_create_date.month, access_key_create_date.day) | |
age = (now - access_key_create_date).days | |
if age >= DEFAULT_WARNING_THRESHOLD_IN_DAYS: | |
user_name = user['UserName'] | |
when = DEFAULT_ROTATION_THRESHOLD_IN_DAYS - age | |
if when > 0: | |
text.append('User {0} access key {1} created {2} is {3} days old and will require rotation in {4} days'.format(user_name.upper(), access_key['AccessKeyId'], access_key_create_date, age, when)) | |
else: | |
text.append('User {0} access key {1} created {2} is {3} days old and immediately requires rotation'.format(user_name.upper(), access_key['AccessKeyId'], access_key_create_date, age)) | |
return text | |
except ClientError as e: | |
if e.response['Error']['Code'] == 'InvalidClientTokenId': | |
return "Not authorized to perform iam maintainence" | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment