Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-SkillsFramework mappings
MITRE ATT&CK
Overview
Conduct systematic access reviews and certifications to ensure users have appropriate access rights aligned with their roles. This skill covers review campaign design, reviewer selection, risk-based prioritization, micro-certification strategies, and remediation tracking for compliance with SOX, HIPAA, and PCI DSS requirements.
When to Use
- When conducting security assessments that involve performing access review and certification
- When following incident response procedures for related security events
- When performing scheduled security testing or auditing activities
- When validating security controls through hands-on testing
Prerequisites
- Familiarity with identity access management concepts and tools
- Access to a test or lab environment for safe execution
- Python 3.8+ with required dependencies installed
- Appropriate authorization for any testing activities
Objectives
- Design and execute access review campaigns across enterprise applications
- Implement risk-based prioritization for review scope
- Configure reviewer selection (manager, application owner, hybrid)
- Automate entitlement data collection and presentation
- Track remediation of inappropriate access findings
- Generate compliance evidence for auditors
Key Concepts
Access Review Types
- User Access Review: Manager certifies all entitlements for their direct reports
- Entitlement Review: Application owner certifies all users with specific entitlement
- Role Review: Role owner certifies role membership and permissions
- Privileged Access Review: Security team reviews high-risk/privileged access
- SOD Review: Verify no users have conflicting separation-of-duty violations
Risk-Based Prioritization
- High Risk: Privileged access, financial systems, PII/PHI systems, external-facing apps
- Medium Risk: Internal business applications, shared drives, collaboration tools
- Low Risk: Standard employee tools, read-only access, public information systems
Review Campaign Lifecycle
- Planning: Define scope, reviewers, timeline, escalation
- Data Collection: Aggregate entitlements from all identity sources
- Distribution: Assign review items to appropriate certifiers
- Certification: Reviewers approve or revoke each entitlement
- Remediation: Revoke inappropriate access, enforce timeline
- Reporting: Generate compliance evidence and metrics
- Closure: Archive campaign, feed findings into next cycle
Workflow
Step 1: Define Review Scope and Schedule
- Identify in-scope applications and systems
- Determine review frequency: quarterly (SOX), semi-annual, annual
- Define campaign timeline: review period, escalation dates, hard close
- Establish escalation chain for non-responsive reviewers
Step 2: Data Collection and Aggregation
- Extract user-entitlement mappings from each application
- Correlate with HR data (active employees, role, department, manager)
- Identify terminated/transferred users still holding access
- Flag high-risk entitlements (admin, DBA, system, privileged)
- Calculate risk scores based on entitlement sensitivity and user role
Step 3: Reviewer Assignment
- Manager Reviews: Direct manager certifies subordinate access
- Application Owner Reviews: App owner certifies all users of their application
- Hybrid Model: Manager reviews standard access, app owner reviews privileged
- Delegate Management: Allow reviewers to delegate with audit trail
Step 4: Execute Certification Campaign
- Send notifications to reviewers with clear instructions
- Present entitlements with context (last used date, risk level, role justification)
- Require reviewers to explicitly approve or revoke each item
- Track completion percentage and send reminders
- Escalate to management after deadline
Step 5: Remediation and Tracking
- Automatically ticket revocations to IT operations
- Set SLA for revocation execution (24-48 hours for high-risk)
- Verify revocation completed (re-check entitlement)
- Exception management for business-justified deviations
- Document all exceptions with expiration dates
Step 6: Reporting and Evidence
- Generate campaign completion metrics
- Produce per-application compliance reports
- Create audit-ready evidence packages
- Track trends across review cycles
- Feed findings into risk assessment process
Security Controls
| Control | NIST 800-53 | Description |
|---|---|---|
| Access Review | AC-2(3) | Periodic review of account privileges |
| Account Management | AC-2 | Account lifecycle management |
| Least Privilege | AC-6 | Minimum necessary access enforcement |
| Separation of Duties | AC-5 | SOD conflict identification |
| Audit Logging | AU-6 | Review of access audit records |
Common Pitfalls
- Rubber-stamping: reviewers approving all access without examination
- Incomplete scope: missing critical applications from review campaigns
- No remediation tracking: revoking access on paper but not in systems
- Inconsistent reviewer assignment causing gaps in coverage
- Not including service accounts and non-human identities
Verification
- All in-scope applications included in campaign
- Reviewers assigned for 100% of entitlements
- Campaign completion rate exceeds 95%
- Revocations executed within SLA
- Audit evidence package complete and archived
- SOD violations identified and documented
- Exceptions documented with business justification and expiry
Source materials
References and resources
Everything below is rendered for inspection. Script files are read-only and never run.
References 3
api-reference.md1.4 KB
API Reference: Access Review and Certification
CSV Input Format
username,entitlement,application,manager,status,last_used,risk_score
jsmith,Admin,SAP,mjones,active,2025-01-15T00:00:00Z,8SoD Rules JSON Format
[{"name": "Finance SoD", "role_a": "AP_Approver", "role_b": "AP_Creator"}]Key Review Checks
| Check | Description | Severity |
|---|---|---|
| Orphaned accounts | No manager or terminated status | HIGH |
| SoD violations | Conflicting entitlements held | CRITICAL |
| Excessive access | Entitlement count above threshold | MEDIUM |
| Stale entitlements | Unused beyond retention period | MEDIUM |
Compliance Frameworks
| Framework | Requirement |
|---|---|
| SOX Section 404 | Periodic access reviews for financial systems |
| SOC 2 CC6.1 | Logical access controls and reviews |
| HIPAA 164.312(a) | Access authorization and review |
| PCI DSS 7.2 | Restrict access based on need-to-know |
Review Campaign Design
| Parameter | Best Practice |
|---|---|
| Frequency | Quarterly for privileged, semi-annual for standard |
| Reviewer | Direct manager + application owner |
| Escalation | Auto-revoke if no response within 14 days |
| Evidence | Export decisions with timestamps and reviewer ID |
References
- NIST SP 800-53 AC-6: https://csrc.nist.gov/publications/detail/sp/800-53/rev-5/final
- ISACA Access Review: https://www.isaca.org/
standards.md1.0 KB
Standards and References - Access Review and Certification
NIST Standards
- NIST SP 800-53 Rev 5:
- AC-2: Account Management (periodic review requirement)
- AC-2(3): Disable accounts after inactivity period
- AC-5: Separation of Duties
- AC-6: Least Privilege
- AC-6(7): Review of User Privileges
- AU-6: Audit Record Review, Analysis, and Reporting
- NIST SP 800-171: 3.1.1 Authorized Access Control, 3.1.2 Transaction Control
Compliance Requirements
- SOX Section 404: Quarterly access reviews for financial systems
- PCI DSS 4.0: Requirement 7.2.5 - Review all access at least every six months
- HIPAA Security Rule: 45 CFR 164.312(a)(1) - Access control review
- ISO 27001: A.9.2.5 Review of user access rights
- GDPR Article 5(1)(f): Integrity and confidentiality of processing
Industry Frameworks
- CIS Controls v8: Control 6.2 - Establish an Access Revoking Process
- COBIT 2019: DSS05.04 - Manage user identity and logical access
- IGA Market: SailPoint, Saviynt, One Identity, Omada
workflows.md2.3 KB
Access Review and Certification Workflows
Workflow 1: Quarterly Access Review Campaign
Timeline:
- Week 1: Data collection and campaign configuration
- Week 2-4: Active review period
- Week 5: Escalation for non-responsive reviewers
- Week 6: Hard close and remediation initiation
- Week 7-8: Remediation execution and verification
- Week 8: Campaign closure and reporting
Steps:
- Extract entitlement data from all in-scope systems
- Correlate with HR data for active/inactive status
- Calculate risk scores for each user-entitlement pair
- Assign reviewers based on reviewer model
- Launch campaign with notifications
- Monitor completion daily, send reminders at 50% and 75% of timeline
- Escalate to VP level at deadline for incomplete reviews
- Force-close with auto-revoke or manager-override at hard deadline
- Process revocations through ticketing system
- Verify revocations completed in target systems
- Generate compliance report and evidence package
Workflow 2: Triggered Access Review (Role Change)
Steps:
- HR system notifies of employee role change (transfer, promotion)
- System identifies current access vs. new role entitlements
- Birthright access for new role automatically provisioned
- Legacy access flagged for new manager review
- New manager certifies which legacy access to retain/revoke
- Retained access documented with justification
- Revoked access removed within SLA
Workflow 3: Privileged Access Micro-Certification
Steps:
- Weekly extraction of privileged entitlements
- Privileged access grouped by system owner
- System owner reviews new privileged access grants since last certification
- Each privileged entitlement requires explicit approval with justification
- Non-certified privileged access auto-revoked after 48 hours
- Results forwarded to security team for trending
Workflow 4: SOD Violation Detection and Resolution
Steps:
- Define SOD rule matrix (e.g., AP create vs. AP approve)
- Scan entitlements against SOD rules
- Flag violations with risk level
- Route violations to compliance team
- Compliance team evaluates: revoke access or approve compensating control
- If compensating control: document control, set review frequency, assign monitor
- If revoke: process access removal and verify
Scripts 2
agent.py5.4 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""Agent for conducting access review and certification using identity governance APIs."""
import json
import argparse
import csv
from datetime import datetime, timezone, timedelta
def load_access_data(csv_path):
"""Load access entitlement data from CSV export."""
with open(csv_path) as f:
reader = csv.DictReader(f)
data = list(reader)
print(f"[*] Loaded {len(data)} entitlement records from {csv_path}")
return data
def identify_orphaned_accounts(records):
"""Find accounts with no manager or terminated status."""
findings = []
for r in records:
if not r.get("manager") or r.get("status", "").lower() == "terminated":
findings.append({"user": r.get("username"), "status": r.get("status"),
"manager": r.get("manager", "NONE"), "severity": "HIGH",
"issue": "Orphaned/terminated account with active access"})
print(f"\n[*] Orphaned/terminated accounts: {len(findings)}")
for f in findings[:10]:
print(f" [!] {f['user']} (status={f['status']}, manager={f['manager']})")
return findings
def check_sod_violations(records, sod_rules):
"""Check for separation of duties violations."""
user_entitlements = {}
for r in records:
user = r.get("username", "")
ent = r.get("entitlement", "")
user_entitlements.setdefault(user, set()).add(ent)
findings = []
for user, ents in user_entitlements.items():
for rule in sod_rules:
if rule["role_a"] in ents and rule["role_b"] in ents:
findings.append({"user": user, "conflict": f"{rule['role_a']} + {rule['role_b']}",
"severity": "CRITICAL", "rule": rule.get("name", "")})
print(f"\n[*] SoD violations: {len(findings)}")
for f in findings[:10]:
print(f" [!] {f['user']}: {f['conflict']}")
return findings
def identify_excessive_access(records, threshold=10):
"""Find users with entitlement counts above threshold."""
user_counts = {}
for r in records:
user = r.get("username", "")
user_counts[user] = user_counts.get(user, 0) + 1
excessive = [{"user": u, "count": c, "severity": "MEDIUM"}
for u, c in user_counts.items() if c > threshold]
excessive.sort(key=lambda x: -x["count"])
print(f"\n[*] Users with >{threshold} entitlements: {len(excessive)}")
for e in excessive[:10]:
print(f" [!] {e['user']}: {e['count']} entitlements")
return excessive
def check_last_used(records, stale_days=90):
"""Find entitlements not used within the stale period."""
cutoff = datetime.now(timezone.utc) - timedelta(days=stale_days)
stale = []
for r in records:
last_used = r.get("last_used", "")
if last_used:
try:
lu_dt = datetime.fromisoformat(last_used.replace("Z", "+00:00"))
if lu_dt < cutoff:
stale.append({"user": r.get("username"), "entitlement": r.get("entitlement"),
"last_used": last_used, "severity": "MEDIUM"})
except ValueError:
pass
print(f"\n[*] Stale entitlements (>{stale_days} days unused): {len(stale)}")
return stale
def generate_report(orphaned, sod, excessive, stale, output_path):
"""Generate access review report."""
report = {"review_date": datetime.now(timezone.utc).isoformat(),
"summary": {"orphaned_accounts": len(orphaned), "sod_violations": len(sod),
"excessive_access": len(excessive), "stale_entitlements": len(stale)},
"orphaned": orphaned, "sod_violations": sod,
"excessive_access": excessive[:50], "stale_entitlements": stale[:50]}
with open(output_path, "w") as f:
json.dump(report, f, indent=2, default=str)
total = len(orphaned) + len(sod) + len(excessive) + len(stale)
print(f"\n[*] Report saved to {output_path} | Total findings: {total}")
def main():
parser = argparse.ArgumentParser(description="Access Review and Certification Agent")
parser.add_argument("action", choices=["orphaned", "sod", "excessive", "stale", "full-review"])
parser.add_argument("--data", required=True, help="CSV file with access entitlements")
parser.add_argument("--sod-rules", help="JSON file with SoD rules")
parser.add_argument("--threshold", type=int, default=10, help="Excessive access threshold")
parser.add_argument("--stale-days", type=int, default=90)
parser.add_argument("-o", "--output", default="access_review.json")
args = parser.parse_args()
records = load_access_data(args.data)
sod_rules = []
if args.sod_rules:
with open(args.sod_rules) as f:
sod_rules = json.load(f)
if args.action == "orphaned":
identify_orphaned_accounts(records)
elif args.action == "sod":
check_sod_violations(records, sod_rules)
elif args.action == "excessive":
identify_excessive_access(records, args.threshold)
elif args.action == "stale":
check_last_used(records, args.stale_days)
elif args.action == "full-review":
o = identify_orphaned_accounts(records)
s = check_sod_violations(records, sod_rules)
e = identify_excessive_access(records, args.threshold)
st = check_last_used(records, args.stale_days)
generate_report(o, s, e, st, args.output)
if __name__ == "__main__":
main()
process.py12.1 KB
Display-only source. This catalog never executes bundled scripts.
#!/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()
Assets 1
template.mdtext/markdown · 1.3 KBKeep exploring