mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-07-19 22:19:39 +03:00
Initial commit - 611 cybersecurity skills across all subdomains
This commit is contained in:
@@ -0,0 +1,311 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Privileged Account Access Review Automation
|
||||
|
||||
Discovers privileged accounts from Active Directory, AWS IAM, and Azure AD,
|
||||
generates review campaigns, and tracks certification decisions.
|
||||
|
||||
Requirements:
|
||||
pip install ldap3 boto3 msal requests pandas openpyxl
|
||||
"""
|
||||
|
||||
import json
|
||||
import csv
|
||||
import sys
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from pathlib import Path
|
||||
|
||||
try:
|
||||
import ldap3
|
||||
HAS_LDAP = True
|
||||
except ImportError:
|
||||
HAS_LDAP = False
|
||||
|
||||
try:
|
||||
import boto3
|
||||
HAS_BOTO = True
|
||||
except ImportError:
|
||||
HAS_BOTO = False
|
||||
|
||||
|
||||
class PrivilegedAccountDiscovery:
|
||||
"""Discovers privileged accounts across multiple platforms."""
|
||||
|
||||
def __init__(self):
|
||||
self.accounts = []
|
||||
|
||||
def discover_ad_privileged_accounts(self, server_address, domain_dn,
|
||||
bind_user, bind_password):
|
||||
"""Enumerate privileged accounts from Active Directory."""
|
||||
if not HAS_LDAP:
|
||||
print("[WARN] ldap3 not installed, skipping AD discovery")
|
||||
return []
|
||||
|
||||
server = ldap3.Server(server_address, use_ssl=True, get_info=ldap3.ALL)
|
||||
conn = ldap3.Connection(server, user=bind_user, password=bind_password,
|
||||
auto_bind=True)
|
||||
|
||||
privileged_groups = [
|
||||
"Domain Admins",
|
||||
"Enterprise Admins",
|
||||
"Schema Admins",
|
||||
"Administrators",
|
||||
"Account Operators",
|
||||
"Backup Operators",
|
||||
"Server Operators",
|
||||
"Print Operators",
|
||||
]
|
||||
|
||||
discovered = []
|
||||
|
||||
for group_name in privileged_groups:
|
||||
search_filter = f"(&(objectClass=group)(cn={group_name}))"
|
||||
conn.search(domain_dn, search_filter,
|
||||
attributes=["member", "distinguishedName"])
|
||||
|
||||
for entry in conn.entries:
|
||||
members = entry.member.values if hasattr(entry.member, "values") else []
|
||||
for member_dn in members:
|
||||
conn.search(member_dn, "(objectClass=user)",
|
||||
attributes=["sAMAccountName", "displayName",
|
||||
"mail", "lastLogonTimestamp",
|
||||
"whenCreated", "userAccountControl",
|
||||
"adminCount", "servicePrincipalName"])
|
||||
for user_entry in conn.entries:
|
||||
uac = int(str(user_entry.userAccountControl)) if user_entry.userAccountControl else 0
|
||||
is_disabled = bool(uac & 0x0002)
|
||||
is_service = bool(user_entry.servicePrincipalName)
|
||||
|
||||
account = {
|
||||
"platform": "Active Directory",
|
||||
"username": str(user_entry.sAMAccountName),
|
||||
"display_name": str(user_entry.displayName) if user_entry.displayName else "",
|
||||
"email": str(user_entry.mail) if user_entry.mail else "",
|
||||
"privileged_group": group_name,
|
||||
"account_type": "service" if is_service else "user",
|
||||
"is_disabled": is_disabled,
|
||||
"created_date": str(user_entry.whenCreated) if user_entry.whenCreated else "",
|
||||
"last_logon": str(user_entry.lastLogonTimestamp) if user_entry.lastLogonTimestamp else "Never",
|
||||
"admin_count": str(user_entry.adminCount) if user_entry.adminCount else "0",
|
||||
"risk_level": "Critical" if group_name in ["Domain Admins", "Enterprise Admins"] else "High",
|
||||
}
|
||||
discovered.append(account)
|
||||
|
||||
conn.unbind()
|
||||
self.accounts.extend(discovered)
|
||||
return discovered
|
||||
|
||||
def discover_aws_privileged_accounts(self, profile_name=None):
|
||||
"""Enumerate privileged IAM users and roles in AWS."""
|
||||
if not HAS_BOTO:
|
||||
print("[WARN] boto3 not installed, skipping AWS discovery")
|
||||
return []
|
||||
|
||||
session = boto3.Session(profile_name=profile_name)
|
||||
iam = session.client("iam")
|
||||
discovered = []
|
||||
|
||||
admin_policies = [
|
||||
"arn:aws:iam::aws:policy/AdministratorAccess",
|
||||
"arn:aws:iam::aws:policy/IAMFullAccess",
|
||||
"arn:aws:iam::aws:policy/PowerUserAccess",
|
||||
]
|
||||
|
||||
paginator = iam.get_paginator("list_users")
|
||||
for page in paginator.paginate():
|
||||
for user in page["Users"]:
|
||||
username = user["UserName"]
|
||||
create_date = user["CreateDate"]
|
||||
|
||||
attached_policies = iam.list_attached_user_policies(UserName=username)
|
||||
user_policies = [p["PolicyArn"] for p in attached_policies["AttachedPolicies"]]
|
||||
|
||||
is_admin = any(p in admin_policies for p in user_policies)
|
||||
|
||||
user_groups = iam.list_groups_for_user(UserName=username)
|
||||
for group in user_groups["Groups"]:
|
||||
group_policies = iam.list_attached_group_policies(GroupName=group["GroupName"])
|
||||
for gp in group_policies["AttachedPolicies"]:
|
||||
if gp["PolicyArn"] in admin_policies:
|
||||
is_admin = True
|
||||
|
||||
if is_admin:
|
||||
try:
|
||||
last_used = iam.get_user(UserName=username)
|
||||
password_last_used = user.get("PasswordLastUsed", "Never")
|
||||
except Exception:
|
||||
password_last_used = "Unknown"
|
||||
|
||||
mfa_devices = iam.list_mfa_devices(UserName=username)
|
||||
has_mfa = len(mfa_devices["MFADevices"]) > 0
|
||||
|
||||
access_keys = iam.list_access_keys(UserName=username)
|
||||
active_keys = [k for k in access_keys["AccessKeyMetadata"]
|
||||
if k["Status"] == "Active"]
|
||||
|
||||
account = {
|
||||
"platform": "AWS IAM",
|
||||
"username": username,
|
||||
"display_name": username,
|
||||
"email": "",
|
||||
"privileged_group": ", ".join(user_policies),
|
||||
"account_type": "user",
|
||||
"is_disabled": False,
|
||||
"created_date": create_date.isoformat(),
|
||||
"last_logon": str(password_last_used),
|
||||
"admin_count": str(len(active_keys)),
|
||||
"risk_level": "Critical",
|
||||
"mfa_enabled": has_mfa,
|
||||
"active_access_keys": len(active_keys),
|
||||
}
|
||||
discovered.append(account)
|
||||
|
||||
self.accounts.extend(discovered)
|
||||
return discovered
|
||||
|
||||
def generate_review_report(self, output_path):
|
||||
"""Generate CSV report of all discovered privileged accounts for review."""
|
||||
if not self.accounts:
|
||||
print("[INFO] No accounts discovered. Run discovery methods first.")
|
||||
return
|
||||
|
||||
fieldnames = [
|
||||
"platform", "username", "display_name", "email",
|
||||
"privileged_group", "account_type", "is_disabled",
|
||||
"created_date", "last_logon", "risk_level",
|
||||
"reviewer", "decision", "justification", "review_date"
|
||||
]
|
||||
|
||||
with open(output_path, "w", newline="", encoding="utf-8") as f:
|
||||
writer = csv.DictWriter(f, fieldnames=fieldnames, extrasaction="ignore")
|
||||
writer.writeheader()
|
||||
for account in self.accounts:
|
||||
account.setdefault("reviewer", "")
|
||||
account.setdefault("decision", "")
|
||||
account.setdefault("justification", "")
|
||||
account.setdefault("review_date", "")
|
||||
writer.writerow(account)
|
||||
|
||||
print(f"[OK] Review report generated: {output_path}")
|
||||
print(f"[OK] Total privileged accounts: {len(self.accounts)}")
|
||||
|
||||
critical = sum(1 for a in self.accounts if a["risk_level"] == "Critical")
|
||||
high = sum(1 for a in self.accounts if a["risk_level"] == "High")
|
||||
disabled = sum(1 for a in self.accounts if a.get("is_disabled"))
|
||||
|
||||
print(f" Critical: {critical} | High: {high} | Disabled: {disabled}")
|
||||
|
||||
|
||||
class AccessReviewTracker:
|
||||
"""Tracks review campaign progress and generates compliance reports."""
|
||||
|
||||
def __init__(self, review_file):
|
||||
self.review_file = Path(review_file)
|
||||
self.accounts = []
|
||||
if self.review_file.exists():
|
||||
self._load_reviews()
|
||||
|
||||
def _load_reviews(self):
|
||||
with open(self.review_file, "r", encoding="utf-8") as f:
|
||||
reader = csv.DictReader(f)
|
||||
self.accounts = list(reader)
|
||||
|
||||
def get_review_status(self):
|
||||
"""Calculate review campaign metrics."""
|
||||
total = len(self.accounts)
|
||||
reviewed = sum(1 for a in self.accounts if a.get("decision"))
|
||||
approved = sum(1 for a in self.accounts if a.get("decision") == "Approve")
|
||||
revoked = sum(1 for a in self.accounts if a.get("decision") == "Revoke")
|
||||
flagged = sum(1 for a in self.accounts if a.get("decision") == "Flag")
|
||||
pending = total - reviewed
|
||||
|
||||
return {
|
||||
"total_accounts": total,
|
||||
"reviewed": reviewed,
|
||||
"pending": pending,
|
||||
"approved": approved,
|
||||
"revoked": revoked,
|
||||
"flagged": flagged,
|
||||
"completion_rate": f"{(reviewed/total*100):.1f}%" if total else "0%",
|
||||
}
|
||||
|
||||
def identify_dormant_accounts(self, days_threshold=90):
|
||||
"""Find accounts not used within the threshold period."""
|
||||
cutoff = datetime.now(timezone.utc) - timedelta(days=days_threshold)
|
||||
dormant = []
|
||||
|
||||
for account in self.accounts:
|
||||
last_logon = account.get("last_logon", "")
|
||||
if last_logon in ("Never", "", "Unknown"):
|
||||
dormant.append(account)
|
||||
continue
|
||||
try:
|
||||
logon_date = datetime.fromisoformat(last_logon.replace("Z", "+00:00"))
|
||||
if logon_date < cutoff:
|
||||
dormant.append(account)
|
||||
except (ValueError, TypeError):
|
||||
continue
|
||||
|
||||
return dormant
|
||||
|
||||
def generate_compliance_report(self, output_path):
|
||||
"""Generate compliance-ready review summary."""
|
||||
status = self.get_review_status()
|
||||
dormant = self.identify_dormant_accounts()
|
||||
|
||||
report = {
|
||||
"report_title": "Privileged Account Access Review - Compliance Report",
|
||||
"generated_date": datetime.now(timezone.utc).isoformat(),
|
||||
"review_period": "Quarterly",
|
||||
"metrics": status,
|
||||
"dormant_accounts": len(dormant),
|
||||
"dormant_account_list": [
|
||||
{"username": a["username"], "platform": a["platform"],
|
||||
"last_logon": a.get("last_logon", "Unknown")}
|
||||
for a in dormant
|
||||
],
|
||||
"findings": [],
|
||||
}
|
||||
|
||||
if status["pending"] > 0:
|
||||
report["findings"].append({
|
||||
"finding": f"{status['pending']} accounts have not been reviewed",
|
||||
"severity": "High",
|
||||
"recommendation": "Complete reviews within SLA or auto-revoke"
|
||||
})
|
||||
|
||||
if dormant:
|
||||
report["findings"].append({
|
||||
"finding": f"{len(dormant)} dormant privileged accounts detected",
|
||||
"severity": "Critical",
|
||||
"recommendation": "Disable dormant accounts and rotate credentials"
|
||||
})
|
||||
|
||||
with open(output_path, "w", encoding="utf-8") as f:
|
||||
json.dump(report, f, indent=2)
|
||||
|
||||
print(f"[OK] Compliance report generated: {output_path}")
|
||||
return report
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
discovery = PrivilegedAccountDiscovery()
|
||||
|
||||
print("=" * 60)
|
||||
print("Privileged Account Access Review Tool")
|
||||
print("=" * 60)
|
||||
print()
|
||||
print("Usage:")
|
||||
print(" 1. Run discovery against your environment")
|
||||
print(" 2. Generate review CSV for reviewer certification")
|
||||
print(" 3. Track review progress and generate compliance report")
|
||||
print()
|
||||
print("Example:")
|
||||
print(" discovery = PrivilegedAccountDiscovery()")
|
||||
print(" discovery.discover_ad_privileged_accounts(server, dn, user, pw)")
|
||||
print(" discovery.discover_aws_privileged_accounts(profile='prod')")
|
||||
print(" discovery.generate_review_report('review_campaign.csv')")
|
||||
print()
|
||||
print(" tracker = AccessReviewTracker('review_campaign.csv')")
|
||||
print(" print(tracker.get_review_status())")
|
||||
print(" tracker.generate_compliance_report('compliance_report.json')")
|
||||
Reference in New Issue
Block a user