116 lines
4.4 KiB
Python
116 lines
4.4 KiB
Python
|
#!/usr/bin/python3
|
||
|
from datetime import datetime
|
||
|
|
||
|
import boto3
|
||
|
import jmespath
|
||
|
import time
|
||
|
import re
|
||
|
|
||
|
# dump user/group/role last activity
|
||
|
|
||
|
|
||
|
def generateLastAccessed(myclient: boto3.client, arn: str, myAccountId: str) -> list[str]:
|
||
|
response = myclient.generate_service_last_accessed_details(
|
||
|
Arn=arn,
|
||
|
Granularity='SERVICE_LEVEL')
|
||
|
jobId = response.get("JobId")
|
||
|
accessDetails = client.get_service_last_accessed_details(JobId=jobId, MaxItems=20)
|
||
|
while True:
|
||
|
time.sleep(2)
|
||
|
accessDetails = client.get_service_last_accessed_details(JobId=jobId, MaxItems=20)
|
||
|
if accessDetails.get("JobStatus") != "COMPLETED":
|
||
|
continue
|
||
|
else:
|
||
|
break
|
||
|
r2 = client.list_policies_granting_service_access(
|
||
|
Arn=arn,
|
||
|
ServiceNamespaces=jmespath.search("ServicesLastAccessed[*].ServiceNamespace", accessDetails)
|
||
|
)
|
||
|
returnString = []
|
||
|
for p in jmespath.search("PoliciesGrantingServiceAccess[*].Policies[]", r2):
|
||
|
if p.get("PolicyType") == "INLINE":
|
||
|
returnString.append("INLINE:" + p.get("PolicyName"))
|
||
|
else:
|
||
|
if myAccountId in p.get("PolicyArn"):
|
||
|
returnString.append(p.get("PolicyArn"))
|
||
|
return list(dict.fromkeys(returnString))
|
||
|
|
||
|
|
||
|
def formatDate(myTime: time) -> str:
|
||
|
if myTime is None:
|
||
|
return "Never"
|
||
|
else:
|
||
|
return myTime.date()
|
||
|
|
||
|
|
||
|
def getPolicyUpdateTime(myClient: boto3.client, arn: str) -> str:
|
||
|
resp = myClient.get_policy(PolicyArn=arn)
|
||
|
return resp.get("Policy").get("UpdateDate").date()
|
||
|
|
||
|
|
||
|
def heading(title: str) -> None:
|
||
|
print("=" * 40)
|
||
|
print("**", title, "**")
|
||
|
print("=" * 40)
|
||
|
|
||
|
|
||
|
sts = boto3.client('sts')
|
||
|
accountId = sts.get_caller_identity()["Account"]
|
||
|
|
||
|
client = boto3.client('iam')
|
||
|
heading("Users")
|
||
|
entity = client.list_users()
|
||
|
for u in jmespath.search("Users[*]", entity):
|
||
|
accessKeyQuery = client.list_access_keys(UserName=u.get('UserName'))
|
||
|
keys = accessKeyQuery.get("AccessKeyMetadata")
|
||
|
print("UserName", u.get("UserName"), sep=": ")
|
||
|
print("CreateDate", formatDate(u.get("CreateDate")), sep=": ")
|
||
|
print("PasswordLastUsed", formatDate(u.get("PasswordLastUsed")), sep=": ")
|
||
|
doPolicyLastUsed = False if u.get("PasswordLastUsed") is None else True
|
||
|
for k in accessKeyQuery.get("AccessKeyMetadata"):
|
||
|
print("AccessKeyId", k.get("AccessKeyId"), sep=": ")
|
||
|
print("AccessKeyStatus", k.get("Status"), sep=": ")
|
||
|
if k.get("Status") == "Inactive":
|
||
|
doPolicyLastUsed = False
|
||
|
print("AccessKeyCreateDate", formatDate(k.get("CreateDate")), sep=": ")
|
||
|
akLastUsedQuery = client.get_access_key_last_used(AccessKeyId=k.get("AccessKeyId"))
|
||
|
print("AccessKeyLastUsed", formatDate(akLastUsedQuery.get("AccessKeyLastUsed").get("LastUsedDate")), sep=": ")
|
||
|
if doPolicyLastUsed:
|
||
|
lastAccessed = generateLastAccessed(client, u.get("Arn"), accountId)
|
||
|
if len(lastAccessed) > 0:
|
||
|
print("CustomerPolicyLastUsed and PolicyLastModified:")
|
||
|
for p in lastAccessed:
|
||
|
if "INLINE" not in p:
|
||
|
print(p, getPolicyUpdateTime(client, p), sep=", ")
|
||
|
else:
|
||
|
print(p)
|
||
|
print("-" * 10)
|
||
|
|
||
|
heading("Groups")
|
||
|
entity = client.list_groups()
|
||
|
print("GroupName", "CreateDate", sep=", ")
|
||
|
for g in jmespath.search("Groups[*]", entity):
|
||
|
print(g.get("GroupName"), formatDate(g.get("CreateDate")), sep=", ")
|
||
|
|
||
|
heading("Roles")
|
||
|
entity = client.list_roles()
|
||
|
for r in jmespath.search("Roles[*]", entity):
|
||
|
if re.match("^/.*service-role/.*", r.get("Path")) is not None or re.match("^/aws-reserved/",
|
||
|
r.get("Path")) is not None:
|
||
|
continue
|
||
|
getRoleQuery = client.get_role(RoleName=r.get("RoleName"))
|
||
|
r1 = getRoleQuery.get("Role")
|
||
|
print("RoleName", r1.get("RoleName"), sep=": ")
|
||
|
print("CreateDate", formatDate(r1.get("CreateDate")), sep=": ")
|
||
|
print("RoleLastUsed", formatDate(jmespath.search("RoleLastUsed.LastUsedDate", r1)), sep=": ")
|
||
|
if jmespath.search("RoleLastUsed.LastUsedDate", r1) is not None:
|
||
|
lastAccessed = generateLastAccessed(client, r1.get("Arn"), accountId)
|
||
|
if len(lastAccessed) > 0:
|
||
|
print("CustomerPolicyLastUsed and PolicyLastModified:")
|
||
|
for p in lastAccessed:
|
||
|
if "INLINE" not in p:
|
||
|
print(p, getPolicyUpdateTime(client, p), sep=", ")
|
||
|
else:
|
||
|
print(p)
|
||
|
print("-" * 10)
|