mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-07-17 05:05:16 +03:00
Initial commit - 611 cybersecurity skills across all subdomains
This commit is contained in:
@@ -0,0 +1,257 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Kubernetes RBAC Permissions Auditor
|
||||
|
||||
Audits RBAC configurations for overly permissive roles,
|
||||
dangerous permission combinations, and privilege escalation paths.
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
import json
|
||||
import sys
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
DANGEROUS_VERBS = {"*", "escalate", "bind", "impersonate"}
|
||||
DANGEROUS_RESOURCES = {"*", "secrets", "pods", "clusterroles", "clusterrolebindings", "roles", "rolebindings"}
|
||||
HIGH_RISK_COMBINATIONS = [
|
||||
({"*"}, {"*"}, "CRITICAL", "Wildcard access on all resources (cluster-admin equivalent)"),
|
||||
({"create", "update", "patch"}, {"clusterrolebindings", "rolebindings"}, "CRITICAL", "Can create role bindings for privilege escalation"),
|
||||
({"escalate"}, {"clusterroles", "roles"}, "CRITICAL", "Can escalate role permissions beyond own level"),
|
||||
({"impersonate"}, {"users", "groups", "serviceaccounts"}, "CRITICAL", "Can impersonate any identity"),
|
||||
({"get", "list", "watch"}, {"secrets"}, "HIGH", "Can read all secrets in scope"),
|
||||
({"create"}, {"pods"}, "HIGH", "Can create pods (deploy workloads)"),
|
||||
({"create"}, {"pods/exec"}, "HIGH", "Can exec into pods (command execution)"),
|
||||
({"delete"}, {"pods", "nodes", "namespaces"}, "HIGH", "Can delete critical resources"),
|
||||
]
|
||||
|
||||
|
||||
@dataclass
|
||||
class RBACFinding:
|
||||
resource_type: str
|
||||
resource_name: str
|
||||
namespace: str
|
||||
severity: str
|
||||
issue: str
|
||||
details: str
|
||||
remediation: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class RBACAuditReport:
|
||||
findings: list = field(default_factory=list)
|
||||
cluster_roles: int = 0
|
||||
roles: int = 0
|
||||
cluster_role_bindings: int = 0
|
||||
role_bindings: int = 0
|
||||
service_accounts: int = 0
|
||||
|
||||
|
||||
def run_kubectl_json(args: list):
|
||||
cmd = ["kubectl"] + args + ["-o", "json"]
|
||||
try:
|
||||
result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
|
||||
if result.returncode != 0:
|
||||
return None
|
||||
return json.loads(result.stdout)
|
||||
except (subprocess.TimeoutExpired, json.JSONDecodeError, FileNotFoundError):
|
||||
return None
|
||||
|
||||
|
||||
def check_role_rules(rules: list, role_name: str, role_type: str, namespace: str, report: RBACAuditReport):
|
||||
"""Analyze role rules for dangerous permissions."""
|
||||
for rule in rules:
|
||||
verbs = set(rule.get("verbs", []))
|
||||
resources = set(rule.get("resources", []))
|
||||
api_groups = rule.get("apiGroups", [])
|
||||
|
||||
for req_verbs, req_resources, severity, description in HIGH_RISK_COMBINATIONS:
|
||||
verb_match = "*" in verbs or bool(verbs & req_verbs)
|
||||
resource_match = "*" in resources or bool(resources & req_resources)
|
||||
|
||||
if verb_match and resource_match:
|
||||
report.findings.append(RBACFinding(
|
||||
resource_type=role_type,
|
||||
resource_name=role_name,
|
||||
namespace=namespace,
|
||||
severity=severity,
|
||||
issue=description,
|
||||
details=f"verbs={list(verbs)}, resources={list(resources)}, apiGroups={api_groups}",
|
||||
remediation=f"Restrict {role_type} '{role_name}' to minimum required permissions"
|
||||
))
|
||||
break
|
||||
|
||||
|
||||
def audit_cluster_roles(report: RBACAuditReport):
|
||||
"""Audit all ClusterRoles."""
|
||||
print("[*] Auditing ClusterRoles...")
|
||||
data = run_kubectl_json(["get", "clusterroles"])
|
||||
if not data:
|
||||
return
|
||||
|
||||
items = data.get("items", [])
|
||||
report.cluster_roles = len(items)
|
||||
|
||||
for cr in items:
|
||||
name = cr["metadata"]["name"]
|
||||
# Skip well-known system roles
|
||||
if name.startswith("system:") and name not in ("system:aggregate-to-admin", "system:aggregate-to-edit"):
|
||||
continue
|
||||
|
||||
rules = cr.get("rules", [])
|
||||
check_role_rules(rules, name, "ClusterRole", "cluster-wide", report)
|
||||
|
||||
|
||||
def audit_roles(report: RBACAuditReport):
|
||||
"""Audit all namespace Roles."""
|
||||
print("[*] Auditing Roles...")
|
||||
data = run_kubectl_json(["get", "roles", "-A"])
|
||||
if not data:
|
||||
return
|
||||
|
||||
items = data.get("items", [])
|
||||
report.roles = len(items)
|
||||
|
||||
for role in items:
|
||||
name = role["metadata"]["name"]
|
||||
namespace = role["metadata"]["namespace"]
|
||||
rules = role.get("rules", [])
|
||||
check_role_rules(rules, name, "Role", namespace, report)
|
||||
|
||||
|
||||
def audit_bindings(report: RBACAuditReport):
|
||||
"""Audit ClusterRoleBindings for dangerous subject assignments."""
|
||||
print("[*] Auditing ClusterRoleBindings...")
|
||||
|
||||
data = run_kubectl_json(["get", "clusterrolebindings"])
|
||||
if not data:
|
||||
return
|
||||
|
||||
items = data.get("items", [])
|
||||
report.cluster_role_bindings = len(items)
|
||||
|
||||
dangerous_subjects = {"system:anonymous", "system:unauthenticated"}
|
||||
admin_roles = {"cluster-admin", "admin", "edit"}
|
||||
|
||||
for crb in items:
|
||||
name = crb["metadata"]["name"]
|
||||
role_ref = crb.get("roleRef", {}).get("name", "")
|
||||
subjects = crb.get("subjects", []) or []
|
||||
|
||||
for subject in subjects:
|
||||
s_name = subject.get("name", "")
|
||||
s_kind = subject.get("kind", "")
|
||||
|
||||
if s_name in dangerous_subjects and role_ref in admin_roles:
|
||||
report.findings.append(RBACFinding(
|
||||
resource_type="ClusterRoleBinding",
|
||||
resource_name=name,
|
||||
namespace="cluster-wide",
|
||||
severity="CRITICAL",
|
||||
issue=f"Dangerous subject '{s_name}' bound to '{role_ref}'",
|
||||
details=f"Subject {s_kind}/{s_name} has {role_ref} access",
|
||||
remediation=f"Remove or restrict ClusterRoleBinding '{name}'"
|
||||
))
|
||||
|
||||
# Check for system:authenticated bound to admin roles
|
||||
if s_name == "system:authenticated" and role_ref in admin_roles:
|
||||
report.findings.append(RBACFinding(
|
||||
resource_type="ClusterRoleBinding",
|
||||
resource_name=name,
|
||||
namespace="cluster-wide",
|
||||
severity="CRITICAL",
|
||||
issue=f"All authenticated users have '{role_ref}' access",
|
||||
details=f"Group system:authenticated bound to {role_ref}",
|
||||
remediation=f"Remove binding, use specific user/group bindings"
|
||||
))
|
||||
|
||||
|
||||
def audit_service_accounts(report: RBACAuditReport):
|
||||
"""Audit service accounts for over-permissioning."""
|
||||
print("[*] Auditing Service Accounts...")
|
||||
|
||||
data = run_kubectl_json(["get", "serviceaccounts", "-A"])
|
||||
if not data:
|
||||
return
|
||||
|
||||
items = data.get("items", [])
|
||||
report.service_accounts = len(items)
|
||||
|
||||
# Check default SAs that have non-default bindings
|
||||
crbs = run_kubectl_json(["get", "clusterrolebindings"])
|
||||
rbs = run_kubectl_json(["get", "rolebindings", "-A"])
|
||||
|
||||
if crbs:
|
||||
for crb in crbs.get("items", []):
|
||||
for subject in crb.get("subjects", []) or []:
|
||||
if subject.get("kind") == "ServiceAccount" and subject.get("name") == "default":
|
||||
report.findings.append(RBACFinding(
|
||||
resource_type="ServiceAccount",
|
||||
resource_name=f"default ({subject.get('namespace', 'unknown')})",
|
||||
namespace=subject.get("namespace", "unknown"),
|
||||
severity="HIGH",
|
||||
issue=f"Default SA bound to ClusterRole '{crb['roleRef']['name']}'",
|
||||
details="Default service account should not have additional permissions",
|
||||
remediation="Create dedicated service account, remove default SA binding"
|
||||
))
|
||||
|
||||
|
||||
def print_report(report: RBACAuditReport):
|
||||
print("\n" + "=" * 70)
|
||||
print("KUBERNETES RBAC AUDIT REPORT")
|
||||
print("=" * 70)
|
||||
print(f"ClusterRoles: {report.cluster_roles}")
|
||||
print(f"Roles: {report.roles}")
|
||||
print(f"ClusterRoleBindings: {report.cluster_role_bindings}")
|
||||
print(f"RoleBindings: {report.role_bindings}")
|
||||
print(f"ServiceAccounts: {report.service_accounts}")
|
||||
print(f"Total Findings: {len(report.findings)}")
|
||||
print("=" * 70)
|
||||
|
||||
for severity in ["CRITICAL", "HIGH", "MEDIUM", "LOW"]:
|
||||
findings = [f for f in report.findings if f.severity == severity]
|
||||
if findings:
|
||||
print(f"\n{severity} ({len(findings)}):")
|
||||
print("-" * 70)
|
||||
for f in findings:
|
||||
print(f" [{f.resource_type}] {f.resource_name}")
|
||||
print(f" Issue: {f.issue}")
|
||||
print(f" Details: {f.details}")
|
||||
print(f" Fix: {f.remediation}")
|
||||
print()
|
||||
|
||||
|
||||
def main():
|
||||
print("[*] Kubernetes RBAC Permissions Auditor\n")
|
||||
|
||||
report = RBACAuditReport()
|
||||
audit_cluster_roles(report)
|
||||
audit_roles(report)
|
||||
audit_bindings(report)
|
||||
audit_service_accounts(report)
|
||||
print_report(report)
|
||||
|
||||
output = {
|
||||
"summary": {
|
||||
"cluster_roles": report.cluster_roles,
|
||||
"roles": report.roles,
|
||||
"findings": len(report.findings),
|
||||
},
|
||||
"findings": [
|
||||
{"type": f.resource_type, "name": f.resource_name, "namespace": f.namespace,
|
||||
"severity": f.severity, "issue": f.issue, "remediation": f.remediation}
|
||||
for f in report.findings
|
||||
],
|
||||
}
|
||||
|
||||
with open("rbac_audit_report.json", "w") as f:
|
||||
json.dump(output, f, indent=2)
|
||||
print("[*] Report saved to rbac_audit_report.json")
|
||||
|
||||
critical = sum(1 for f in report.findings if f.severity == "CRITICAL")
|
||||
if critical > 0:
|
||||
print(f"\n[!] {critical} CRITICAL findings found")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user