mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-07-15 20:25:18 +03:00
Initial commit - 611 cybersecurity skills across all subdomains
This commit is contained in:
@@ -0,0 +1,312 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Access Review and Certification Engine
|
||||
|
||||
Automates access review campaigns by collecting entitlement data,
|
||||
assigning reviewers, tracking certification decisions, generating
|
||||
compliance reports, and identifying SOD violations.
|
||||
"""
|
||||
|
||||
import json
|
||||
import datetime
|
||||
import csv
|
||||
import io
|
||||
from typing import Dict, List, Optional, Set, Tuple
|
||||
from dataclasses import dataclass, field
|
||||
from collections import defaultdict
|
||||
|
||||
|
||||
@dataclass
|
||||
class UserEntitlement:
|
||||
"""A user-to-entitlement mapping for review."""
|
||||
user_id: str
|
||||
user_name: str
|
||||
department: str
|
||||
manager: str
|
||||
application: str
|
||||
entitlement: str
|
||||
risk_level: str # critical, high, medium, low
|
||||
last_used: Optional[str] = None
|
||||
granted_date: Optional[str] = None
|
||||
review_status: str = "pending" # pending, approved, revoked, escalated
|
||||
reviewer: str = ""
|
||||
decision_date: Optional[str] = None
|
||||
justification: str = ""
|
||||
|
||||
|
||||
@dataclass
|
||||
class SODRule:
|
||||
"""Separation of Duties conflict rule."""
|
||||
rule_id: str
|
||||
description: str
|
||||
entitlement_a: str
|
||||
application_a: str
|
||||
entitlement_b: str
|
||||
application_b: str
|
||||
severity: str # critical, high, medium
|
||||
|
||||
|
||||
@dataclass
|
||||
class CampaignConfig:
|
||||
"""Access review campaign configuration."""
|
||||
campaign_id: str
|
||||
name: str
|
||||
start_date: str
|
||||
end_date: str
|
||||
review_model: str # manager, app_owner, hybrid
|
||||
scope_applications: List[str] = field(default_factory=list)
|
||||
escalation_days: int = 21
|
||||
auto_revoke_unreviewed: bool = False
|
||||
|
||||
|
||||
class AccessReviewEngine:
|
||||
"""Manages access review and certification campaigns."""
|
||||
|
||||
def __init__(self, config: CampaignConfig):
|
||||
self.config = config
|
||||
self.entitlements: List[UserEntitlement] = []
|
||||
self.sod_rules: List[SODRule] = []
|
||||
self.sod_violations: List[Dict] = []
|
||||
|
||||
def load_entitlements(self, entitlements: List[Dict]):
|
||||
"""Load user-entitlement data for review."""
|
||||
for e in entitlements:
|
||||
ue = UserEntitlement(**e)
|
||||
if not self.config.scope_applications or \
|
||||
ue.application in self.config.scope_applications:
|
||||
self.entitlements.append(ue)
|
||||
|
||||
def load_sod_rules(self, rules: List[Dict]):
|
||||
"""Load SOD conflict rules."""
|
||||
for r in rules:
|
||||
self.sod_rules.append(SODRule(**r))
|
||||
|
||||
def assign_reviewers(self):
|
||||
"""Assign reviewers based on campaign review model."""
|
||||
for ent in self.entitlements:
|
||||
if ent.review_status != "pending":
|
||||
continue
|
||||
if self.config.review_model == "manager":
|
||||
ent.reviewer = ent.manager
|
||||
elif self.config.review_model == "app_owner":
|
||||
ent.reviewer = f"owner_{ent.application}"
|
||||
elif self.config.review_model == "hybrid":
|
||||
if ent.risk_level in ("critical", "high"):
|
||||
ent.reviewer = f"owner_{ent.application}"
|
||||
else:
|
||||
ent.reviewer = ent.manager
|
||||
|
||||
def detect_sod_violations(self) -> List[Dict]:
|
||||
"""Detect separation of duties violations."""
|
||||
self.sod_violations = []
|
||||
user_entitlements = defaultdict(list)
|
||||
|
||||
for ent in self.entitlements:
|
||||
user_entitlements[ent.user_id].append(ent)
|
||||
|
||||
for user_id, ents in user_entitlements.items():
|
||||
for rule in self.sod_rules:
|
||||
has_a = any(
|
||||
e.application == rule.application_a and e.entitlement == rule.entitlement_a
|
||||
for e in ents
|
||||
)
|
||||
has_b = any(
|
||||
e.application == rule.application_b and e.entitlement == rule.entitlement_b
|
||||
for e in ents
|
||||
)
|
||||
if has_a and has_b:
|
||||
user_name = next(e.user_name for e in ents)
|
||||
self.sod_violations.append({
|
||||
"user_id": user_id,
|
||||
"user_name": user_name,
|
||||
"rule_id": rule.rule_id,
|
||||
"description": rule.description,
|
||||
"severity": rule.severity,
|
||||
"entitlement_a": f"{rule.application_a}:{rule.entitlement_a}",
|
||||
"entitlement_b": f"{rule.application_b}:{rule.entitlement_b}"
|
||||
})
|
||||
|
||||
return self.sod_violations
|
||||
|
||||
def identify_stale_access(self, days_threshold: int = 90) -> List[UserEntitlement]:
|
||||
"""Identify entitlements not used within threshold."""
|
||||
stale = []
|
||||
now = datetime.datetime.now()
|
||||
|
||||
for ent in self.entitlements:
|
||||
if ent.last_used:
|
||||
try:
|
||||
last = datetime.datetime.fromisoformat(ent.last_used)
|
||||
if (now - last).days > days_threshold:
|
||||
stale.append(ent)
|
||||
except ValueError:
|
||||
pass
|
||||
else:
|
||||
stale.append(ent)
|
||||
|
||||
return stale
|
||||
|
||||
def identify_orphaned_access(self, active_users: Set[str]) -> List[UserEntitlement]:
|
||||
"""Identify entitlements belonging to inactive/terminated users."""
|
||||
return [e for e in self.entitlements if e.user_id not in active_users]
|
||||
|
||||
def process_decision(self, user_id: str, application: str, entitlement: str,
|
||||
decision: str, justification: str = ""):
|
||||
"""Process a reviewer's certification decision."""
|
||||
for ent in self.entitlements:
|
||||
if (ent.user_id == user_id and ent.application == application and
|
||||
ent.entitlement == entitlement):
|
||||
ent.review_status = decision
|
||||
ent.decision_date = datetime.datetime.now().isoformat()
|
||||
ent.justification = justification
|
||||
break
|
||||
|
||||
def get_campaign_metrics(self) -> Dict:
|
||||
"""Calculate campaign progress metrics."""
|
||||
total = len(self.entitlements)
|
||||
if total == 0:
|
||||
return {"total": 0, "completion_rate": 0}
|
||||
|
||||
by_status = defaultdict(int)
|
||||
by_risk = defaultdict(lambda: defaultdict(int))
|
||||
by_reviewer = defaultdict(lambda: {"total": 0, "completed": 0})
|
||||
|
||||
for ent in self.entitlements:
|
||||
by_status[ent.review_status] += 1
|
||||
by_risk[ent.risk_level][ent.review_status] += 1
|
||||
by_reviewer[ent.reviewer]["total"] += 1
|
||||
if ent.review_status in ("approved", "revoked"):
|
||||
by_reviewer[ent.reviewer]["completed"] += 1
|
||||
|
||||
completed = by_status.get("approved", 0) + by_status.get("revoked", 0)
|
||||
revocation_rate = by_status.get("revoked", 0) / max(completed, 1) * 100
|
||||
|
||||
return {
|
||||
"total": total,
|
||||
"pending": by_status.get("pending", 0),
|
||||
"approved": by_status.get("approved", 0),
|
||||
"revoked": by_status.get("revoked", 0),
|
||||
"escalated": by_status.get("escalated", 0),
|
||||
"completion_rate": round(completed / total * 100, 1),
|
||||
"revocation_rate": round(revocation_rate, 1),
|
||||
"by_risk": dict(by_risk),
|
||||
"sod_violations": len(self.sod_violations),
|
||||
"reviewer_progress": {k: v for k, v in by_reviewer.items()}
|
||||
}
|
||||
|
||||
def generate_compliance_report(self) -> str:
|
||||
"""Generate compliance-ready access review report."""
|
||||
metrics = self.get_campaign_metrics()
|
||||
stale = self.identify_stale_access()
|
||||
|
||||
lines = [
|
||||
"=" * 70,
|
||||
"ACCESS REVIEW AND CERTIFICATION REPORT",
|
||||
"=" * 70,
|
||||
f"Campaign: {self.config.name} ({self.config.campaign_id})",
|
||||
f"Period: {self.config.start_date} to {self.config.end_date}",
|
||||
f"Review Model: {self.config.review_model}",
|
||||
f"Report Generated: {datetime.datetime.now().isoformat()}",
|
||||
"-" * 70,
|
||||
"",
|
||||
"CAMPAIGN METRICS",
|
||||
f" Total Entitlements Reviewed: {metrics['total']}",
|
||||
f" Completion Rate: {metrics['completion_rate']}%",
|
||||
f" Approved: {metrics['approved']}",
|
||||
f" Revoked: {metrics['revoked']}",
|
||||
f" Pending: {metrics['pending']}",
|
||||
f" Escalated: {metrics['escalated']}",
|
||||
f" Revocation Rate: {metrics['revocation_rate']}%",
|
||||
f" Stale Access Items: {len(stale)}",
|
||||
f" SOD Violations: {metrics['sod_violations']}",
|
||||
""
|
||||
]
|
||||
|
||||
if self.sod_violations:
|
||||
lines.append("SOD VIOLATIONS:")
|
||||
lines.append("-" * 40)
|
||||
for v in self.sod_violations:
|
||||
lines.append(f" [{v['severity'].upper()}] {v['user_name']} ({v['user_id']})")
|
||||
lines.append(f" Rule: {v['description']}")
|
||||
lines.append(f" Conflict: {v['entitlement_a']} <-> {v['entitlement_b']}")
|
||||
lines.append("")
|
||||
|
||||
# Reviewer progress
|
||||
lines.append("REVIEWER PROGRESS:")
|
||||
lines.append("-" * 40)
|
||||
for reviewer, progress in metrics["reviewer_progress"].items():
|
||||
pct = round(progress["completed"] / max(progress["total"], 1) * 100, 1)
|
||||
lines.append(f" {reviewer}: {progress['completed']}/{progress['total']} ({pct}%)")
|
||||
lines.append("")
|
||||
|
||||
# Revoked access details
|
||||
revoked = [e for e in self.entitlements if e.review_status == "revoked"]
|
||||
if revoked:
|
||||
lines.append("REVOKED ACCESS:")
|
||||
lines.append("-" * 40)
|
||||
for e in revoked:
|
||||
lines.append(f" {e.user_name} - {e.application}:{e.entitlement} [{e.risk_level}]")
|
||||
lines.append("")
|
||||
|
||||
lines.append("=" * 70)
|
||||
overall = "COMPLIANT" if metrics["completion_rate"] >= 95 else "NON-COMPLIANT"
|
||||
lines.append(f"COMPLIANCE STATUS: {overall}")
|
||||
lines.append("=" * 70)
|
||||
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def main():
|
||||
"""Run access review with sample data."""
|
||||
config = CampaignConfig(
|
||||
campaign_id="AR-2026-Q1",
|
||||
name="Q1 2026 Quarterly Access Review",
|
||||
start_date="2026-01-01",
|
||||
end_date="2026-03-31",
|
||||
review_model="hybrid",
|
||||
scope_applications=["SAP", "Salesforce", "AWS", "GitHub"]
|
||||
)
|
||||
|
||||
engine = AccessReviewEngine(config)
|
||||
|
||||
sample_entitlements = [
|
||||
{"user_id": "U001", "user_name": "Alice Johnson", "department": "Finance",
|
||||
"manager": "Bob Smith", "application": "SAP", "entitlement": "AP_Create",
|
||||
"risk_level": "high", "last_used": "2026-02-20", "granted_date": "2024-06-15"},
|
||||
{"user_id": "U001", "user_name": "Alice Johnson", "department": "Finance",
|
||||
"manager": "Bob Smith", "application": "SAP", "entitlement": "AP_Approve",
|
||||
"risk_level": "critical", "last_used": "2026-02-18", "granted_date": "2025-01-10"},
|
||||
{"user_id": "U002", "user_name": "Charlie Brown", "department": "Engineering",
|
||||
"manager": "Diana Prince", "application": "AWS", "entitlement": "AdminAccess",
|
||||
"risk_level": "critical", "last_used": "2025-10-01", "granted_date": "2024-03-20"},
|
||||
{"user_id": "U003", "user_name": "Eve Wilson", "department": "Sales",
|
||||
"manager": "Frank Castle", "application": "Salesforce", "entitlement": "Standard_User",
|
||||
"risk_level": "low", "last_used": "2026-02-22", "granted_date": "2025-08-01"},
|
||||
{"user_id": "U004", "user_name": "Grace Lee", "department": "Engineering",
|
||||
"manager": "Diana Prince", "application": "GitHub", "entitlement": "Org_Admin",
|
||||
"risk_level": "high", "last_used": "2026-02-21", "granted_date": "2025-05-15"},
|
||||
]
|
||||
|
||||
sod_rules = [
|
||||
{"rule_id": "SOD-001", "description": "AP Create and AP Approve conflict",
|
||||
"entitlement_a": "AP_Create", "application_a": "SAP",
|
||||
"entitlement_b": "AP_Approve", "application_b": "SAP",
|
||||
"severity": "critical"}
|
||||
]
|
||||
|
||||
engine.load_entitlements(sample_entitlements)
|
||||
engine.load_sod_rules(sod_rules)
|
||||
engine.assign_reviewers()
|
||||
engine.detect_sod_violations()
|
||||
|
||||
# Simulate some decisions
|
||||
engine.process_decision("U001", "SAP", "AP_Create", "approved", "Required for daily AP processing")
|
||||
engine.process_decision("U002", "AWS", "AdminAccess", "revoked", "Stale access - user no longer needs admin")
|
||||
engine.process_decision("U003", "Salesforce", "Standard_User", "approved", "Active sales team member")
|
||||
|
||||
report = engine.generate_compliance_report()
|
||||
print(report)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user