mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-09-04 15:30:50 +03:00
chore: fix license, add disclaimer, quick start, GitHub topics, issue templates
This commit is contained in:
@@ -1,173 +1,99 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Kubernetes Pod Privilege Escalation Detection Agent
|
||||
Audits Kubernetes pods for privilege escalation risks including privileged
|
||||
containers, host namespace access, and dangerous capabilities.
|
||||
Authorized security monitoring use only.
|
||||
"""Kubernetes pod privilege escalation detection agent.
|
||||
|
||||
Audits pod security contexts, capabilities, and service account permissions
|
||||
to detect misconfigurations enabling container privilege escalation.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
from datetime import datetime, timezone
|
||||
from datetime import datetime
|
||||
|
||||
from kubernetes import client, config
|
||||
DANGEROUS_CAPABILITIES = {
|
||||
"SYS_ADMIN", "SYS_PTRACE", "SYS_MODULE", "NET_ADMIN",
|
||||
"NET_RAW", "DAC_READ_SEARCH", "SYS_RAWIO",
|
||||
}
|
||||
|
||||
|
||||
DANGEROUS_CAPABILITIES = [
|
||||
"SYS_ADMIN", "SYS_PTRACE", "NET_ADMIN", "NET_RAW",
|
||||
"DAC_OVERRIDE", "SETUID", "SETGID", "SYS_RAWIO",
|
||||
]
|
||||
def get_pods(namespace="--all-namespaces"):
|
||||
try:
|
||||
cmd = ["kubectl", "get", "pods", "-o", "json"]
|
||||
if namespace == "--all-namespaces":
|
||||
cmd.append("--all-namespaces")
|
||||
else:
|
||||
cmd.extend(["-n", namespace])
|
||||
result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
|
||||
if result.returncode == 0:
|
||||
return json.loads(result.stdout).get("items", [])
|
||||
except (subprocess.TimeoutExpired, FileNotFoundError, json.JSONDecodeError):
|
||||
pass
|
||||
return []
|
||||
|
||||
|
||||
def load_k8s_config(kubeconfig=None, in_cluster=False):
|
||||
"""Load Kubernetes configuration."""
|
||||
if in_cluster:
|
||||
config.load_incluster_config()
|
||||
else:
|
||||
config.load_kube_config(config_file=kubeconfig)
|
||||
|
||||
|
||||
def audit_pod_security(namespace=None):
|
||||
"""Audit pods for privilege escalation vectors."""
|
||||
v1 = client.CoreV1Api()
|
||||
if namespace:
|
||||
pods = v1.list_namespaced_pod(namespace)
|
||||
else:
|
||||
pods = v1.list_pod_for_all_namespaces()
|
||||
|
||||
def audit_pod(pod):
|
||||
findings = []
|
||||
for pod in pods.items:
|
||||
pod_name = pod.metadata.name
|
||||
pod_ns = pod.metadata.namespace
|
||||
for container in (pod.spec.containers or []):
|
||||
sc = container.security_context
|
||||
if not sc:
|
||||
findings.append({
|
||||
"pod": pod_name, "namespace": pod_ns,
|
||||
"container": container.name,
|
||||
"issue": "no_security_context",
|
||||
"severity": "medium",
|
||||
"detail": "Container has no security context defined",
|
||||
})
|
||||
continue
|
||||
if sc.privileged:
|
||||
findings.append({
|
||||
"pod": pod_name, "namespace": pod_ns,
|
||||
"container": container.name,
|
||||
"issue": "privileged_container",
|
||||
"severity": "critical",
|
||||
"detail": "Container runs in privileged mode",
|
||||
})
|
||||
if sc.allow_privilege_escalation is not False:
|
||||
findings.append({
|
||||
"pod": pod_name, "namespace": pod_ns,
|
||||
"container": container.name,
|
||||
"issue": "allow_privilege_escalation",
|
||||
"severity": "high",
|
||||
"detail": "allowPrivilegeEscalation is not explicitly set to false",
|
||||
})
|
||||
if sc.run_as_user == 0 or (sc.run_as_non_root is not True and not sc.run_as_user):
|
||||
findings.append({
|
||||
"pod": pod_name, "namespace": pod_ns,
|
||||
"container": container.name,
|
||||
"issue": "runs_as_root",
|
||||
"severity": "high",
|
||||
"detail": "Container may run as root",
|
||||
})
|
||||
if sc.capabilities and sc.capabilities.add:
|
||||
dangerous = [c for c in sc.capabilities.add if c in DANGEROUS_CAPABILITIES]
|
||||
if dangerous:
|
||||
findings.append({
|
||||
"pod": pod_name, "namespace": pod_ns,
|
||||
"container": container.name,
|
||||
"issue": "dangerous_capabilities",
|
||||
"severity": "high",
|
||||
"detail": f"Dangerous capabilities: {dangerous}",
|
||||
})
|
||||
spec = pod.spec
|
||||
if spec.host_pid:
|
||||
findings.append({
|
||||
"pod": pod_name, "namespace": pod_ns,
|
||||
"issue": "host_pid_namespace", "severity": "critical",
|
||||
"detail": "Pod shares host PID namespace",
|
||||
})
|
||||
if spec.host_network:
|
||||
findings.append({
|
||||
"pod": pod_name, "namespace": pod_ns,
|
||||
"issue": "host_network", "severity": "high",
|
||||
"detail": "Pod shares host network namespace",
|
||||
})
|
||||
if spec.host_ipc:
|
||||
findings.append({
|
||||
"pod": pod_name, "namespace": pod_ns,
|
||||
"issue": "host_ipc", "severity": "high",
|
||||
"detail": "Pod shares host IPC namespace",
|
||||
})
|
||||
for vol in (spec.volumes or []):
|
||||
if vol.host_path:
|
||||
findings.append({
|
||||
"pod": pod_name, "namespace": pod_ns,
|
||||
"issue": "host_path_volume",
|
||||
"severity": "high",
|
||||
"detail": f"hostPath volume: {vol.host_path.path}",
|
||||
})
|
||||
return findings
|
||||
pod_name = pod.get("metadata", {}).get("name", "")
|
||||
namespace = pod.get("metadata", {}).get("namespace", "")
|
||||
spec = pod.get("spec", {})
|
||||
|
||||
if spec.get("hostPID"):
|
||||
findings.append({"check": "hostPID", "severity": "CRITICAL", "desc": "Host PID namespace"})
|
||||
if spec.get("hostNetwork"):
|
||||
findings.append({"check": "hostNetwork", "severity": "HIGH", "desc": "Host network"})
|
||||
if spec.get("hostIPC"):
|
||||
findings.append({"check": "hostIPC", "severity": "MEDIUM", "desc": "Host IPC"})
|
||||
|
||||
for container in spec.get("containers", []) + spec.get("initContainers", []):
|
||||
ctx = container.get("securityContext", {})
|
||||
c_name = container.get("name", "")
|
||||
if ctx.get("privileged"):
|
||||
findings.append({"container": c_name, "check": "privileged",
|
||||
"severity": "CRITICAL", "desc": "Privileged container"})
|
||||
if ctx.get("allowPrivilegeEscalation", True):
|
||||
findings.append({"container": c_name, "check": "allowPrivilegeEscalation",
|
||||
"severity": "HIGH", "desc": "Privilege escalation allowed"})
|
||||
run_as = ctx.get("runAsUser")
|
||||
if run_as == 0 or (run_as is None and not ctx.get("runAsNonRoot")):
|
||||
findings.append({"container": c_name, "check": "runAsRoot",
|
||||
"severity": "HIGH", "desc": "May run as root"})
|
||||
if not ctx.get("readOnlyRootFilesystem"):
|
||||
findings.append({"container": c_name, "check": "mutableFS",
|
||||
"severity": "MEDIUM", "desc": "Writable root FS"})
|
||||
caps = ctx.get("capabilities", {})
|
||||
for cap in set(caps.get("add", [])) & DANGEROUS_CAPABILITIES:
|
||||
findings.append({"container": c_name, "check": "dangerous_cap",
|
||||
"capability": cap, "severity": "CRITICAL"})
|
||||
for vm in container.get("volumeMounts", []):
|
||||
if vm.get("mountPath") in ("/var/run/docker.sock", "/run/containerd/containerd.sock"):
|
||||
findings.append({"container": c_name, "check": "runtime_socket",
|
||||
"severity": "CRITICAL", "desc": f"Socket: {vm['mountPath']}"})
|
||||
|
||||
risk = "CRITICAL" if any(f["severity"] == "CRITICAL" for f in findings) else \
|
||||
"HIGH" if any(f["severity"] == "HIGH" for f in findings) else "MEDIUM"
|
||||
return {"pod": pod_name, "namespace": namespace, "findings": findings, "risk": risk}
|
||||
|
||||
|
||||
def audit_rbac_escalation(namespace=None):
|
||||
"""Check RBAC for privilege escalation paths."""
|
||||
rbac = client.RbacAuthorizationV1Api()
|
||||
findings = []
|
||||
if namespace:
|
||||
bindings = rbac.list_namespaced_role_binding(namespace)
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="K8s Pod PrivEsc Detector")
|
||||
parser.add_argument("--namespace", default="--all-namespaces")
|
||||
parser.add_argument("--json-file", help="Pod JSON file instead of kubectl")
|
||||
args = parser.parse_args()
|
||||
if args.json_file:
|
||||
with open(args.json_file) as f:
|
||||
data = json.load(f)
|
||||
pods = data.get("items", [data]) if "items" in data else [data]
|
||||
else:
|
||||
bindings = rbac.list_cluster_role_binding()
|
||||
for binding in bindings.items:
|
||||
role_ref = binding.role_ref
|
||||
if role_ref.name in ("cluster-admin", "admin", "edit"):
|
||||
for subject in (binding.subjects or []):
|
||||
if subject.kind == "ServiceAccount":
|
||||
findings.append({
|
||||
"binding": binding.metadata.name,
|
||||
"role": role_ref.name,
|
||||
"subject": f"{subject.namespace}/{subject.name}",
|
||||
"issue": "overprivileged_service_account",
|
||||
"severity": "high",
|
||||
"detail": f"ServiceAccount bound to {role_ref.name}",
|
||||
})
|
||||
return findings
|
||||
|
||||
|
||||
def generate_report(pod_findings, rbac_findings):
|
||||
"""Generate Kubernetes privilege escalation report."""
|
||||
all_findings = pod_findings + rbac_findings
|
||||
return {
|
||||
"report_title": "Kubernetes Privilege Escalation Detection",
|
||||
"generated_at": datetime.now(timezone.utc).isoformat(),
|
||||
"total_findings": len(all_findings),
|
||||
"critical": len([f for f in all_findings if f.get("severity") == "critical"]),
|
||||
"high": len([f for f in all_findings if f.get("severity") == "high"]),
|
||||
"pod_findings": pod_findings,
|
||||
"rbac_findings": rbac_findings,
|
||||
}
|
||||
pods = get_pods(args.namespace)
|
||||
results = {"timestamp": datetime.utcnow().isoformat() + "Z", "pod_audits": []}
|
||||
for pod in pods:
|
||||
audit = audit_pod(pod)
|
||||
if audit["findings"]:
|
||||
results["pod_audits"].append(audit)
|
||||
results["total_pods_with_issues"] = len(results["pod_audits"])
|
||||
print(json.dumps(results, indent=2))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description="Detect K8s pod privilege escalation")
|
||||
parser.add_argument("--namespace", "-n", help="Kubernetes namespace to audit")
|
||||
parser.add_argument("--kubeconfig", help="Path to kubeconfig file")
|
||||
parser.add_argument("--in-cluster", action="store_true", help="Use in-cluster config")
|
||||
parser.add_argument("--output", default="k8s_privesc_audit.json", help="Output file")
|
||||
args = parser.parse_args()
|
||||
|
||||
load_k8s_config(args.kubeconfig, args.in_cluster)
|
||||
print("[*] Auditing pod security contexts...")
|
||||
pod_findings = audit_pod_security(args.namespace)
|
||||
print("[*] Auditing RBAC bindings...")
|
||||
rbac_findings = audit_rbac_escalation(args.namespace)
|
||||
|
||||
report = generate_report(pod_findings, rbac_findings)
|
||||
with open(args.output, "w") as f:
|
||||
json.dump(report, f, indent=2)
|
||||
print(json.dumps(report, indent=2))
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user