|
|
@@ -0,0 +1,101 @@ |
|
|
#!/usr/bin/env python |
|
|
|
|
|
# Parses the output from AWS credential reports and displays |
|
|
# users which have been inactive for 60+ days. |
|
|
# |
|
|
# Usage: |
|
|
# audit_iam_accounts.py credential_report.csv <days> |
|
|
# |
|
|
|
|
|
import csv |
|
|
import sys |
|
|
|
|
|
from datetime import datetime, timedelta |
|
|
|
|
|
from prettytable import PrettyTable |
|
|
|
|
|
|
|
|
class IAMUser(object): |
|
|
DATE_FORMAT = '%Y-%m-%dT%H:%M:%S+00:00' |
|
|
|
|
|
def __init__(self, data, inactive_days=60): |
|
|
self.data = data |
|
|
self.inactive_days = inactive_days |
|
|
|
|
|
self.mfa_active = self._parse_bool(data['mfa_active']) |
|
|
|
|
|
self.name = data['user'] |
|
|
self.created_at = self._parse_date(data['user_creation_time']) |
|
|
self.password_last_used = \ |
|
|
self._parse_date(data['password_last_used']) |
|
|
|
|
|
self.access_key_1_active = self._parse_bool(data['access_key_1_active']) |
|
|
self.access_key_1_last_used = \ |
|
|
self._parse_date(data['access_key_1_last_used_date']) |
|
|
|
|
|
self.access_key_2_active = self._parse_bool(data['access_key_2_active']) |
|
|
self.access_key_2_last_used = \ |
|
|
self._parse_date(data['access_key_2_last_used_date']) |
|
|
|
|
|
def _parse_bool(self, boolstring): |
|
|
if boolstring == 'true': |
|
|
return True |
|
|
else: |
|
|
return False |
|
|
|
|
|
def _parse_date(self, datestring): |
|
|
epoch = datetime.fromtimestamp(0) |
|
|
return (epoch if (datestring == 'N/A' or datestring == 'no_information') |
|
|
else datetime.strptime(datestring, self.DATE_FORMAT)) |
|
|
|
|
|
def is_inactive(self): |
|
|
inactive_date = datetime.now() - timedelta(days=self.inactive_days) |
|
|
if (self.password_last_used < inactive_date and |
|
|
self.access_key_1_last_used < inactive_date and |
|
|
self.access_key_2_last_used < inactive_date): |
|
|
return True |
|
|
|
|
|
return False |
|
|
|
|
|
|
|
|
def main(): |
|
|
filename = sys.argv[1] |
|
|
try: |
|
|
inactive_days = int(sys.argv[2]) |
|
|
except: |
|
|
inactive_days = 60 |
|
|
|
|
|
try: |
|
|
user_report = csv.DictReader(open(filename)) |
|
|
except Exception as e: |
|
|
print("Error parsing CSV File: %s" % e) |
|
|
sys.exit(1) |
|
|
|
|
|
pt = PrettyTable() |
|
|
pt.field_names = [ |
|
|
"User", |
|
|
"MFA Enabled", |
|
|
"Password Last Used", |
|
|
"Key 1 Last Used", |
|
|
"Key 2 Last Used" |
|
|
] |
|
|
|
|
|
for user_data in user_report: |
|
|
user = IAMUser(user_data, inactive_days) |
|
|
if user.is_inactive(): |
|
|
row = [user.name, user.mfa_active, user.password_last_used] |
|
|
if user.access_key_1_active: |
|
|
row.append(user.access_key_1_last_used) |
|
|
else: |
|
|
row.append('inactive') |
|
|
if user.access_key_2_active: |
|
|
row.append(user.access_key_2_last_used) |
|
|
else: |
|
|
row.append('inactive') |
|
|
|
|
|
pt.add_row(row) |
|
|
|
|
|
print(pt) |
|
|
|
|
|
if __name__ == '__main__': |
|
|
main() |