mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-06-12 22:24:56 +03:00
Initial commit - 611 cybersecurity skills across all subdomains
This commit is contained in:
@@ -0,0 +1,372 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Tetragon Runtime Security Event Analyzer
|
||||
|
||||
Parses Tetragon JSON event logs and generates security reports
|
||||
including process execution anomalies, policy violations, and
|
||||
container escape attempt detection.
|
||||
"""
|
||||
|
||||
import json
|
||||
import sys
|
||||
import subprocess
|
||||
import argparse
|
||||
from datetime import datetime, timedelta
|
||||
from collections import Counter, defaultdict
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def run_kubectl_command(command: list[str]) -> str:
|
||||
"""Execute a kubectl command and return output."""
|
||||
try:
|
||||
result = subprocess.run(
|
||||
command, capture_output=True, text=True, timeout=30
|
||||
)
|
||||
if result.returncode != 0:
|
||||
print(f"[ERROR] kubectl command failed: {result.stderr.strip()}")
|
||||
return ""
|
||||
return result.stdout.strip()
|
||||
except subprocess.TimeoutExpired:
|
||||
print("[ERROR] kubectl command timed out")
|
||||
return ""
|
||||
except FileNotFoundError:
|
||||
print("[ERROR] kubectl not found in PATH")
|
||||
return ""
|
||||
|
||||
|
||||
def get_tetragon_status() -> dict:
|
||||
"""Check Tetragon DaemonSet health."""
|
||||
output = run_kubectl_command([
|
||||
"kubectl", "get", "ds", "tetragon", "-n", "kube-system",
|
||||
"-o", "jsonpath={.status.desiredNumberScheduled},{.status.numberReady}"
|
||||
])
|
||||
if not output:
|
||||
return {"healthy": False, "desired": 0, "ready": 0}
|
||||
parts = output.split(",")
|
||||
desired = int(parts[0]) if len(parts) > 0 and parts[0] else 0
|
||||
ready = int(parts[1]) if len(parts) > 1 and parts[1] else 0
|
||||
return {"healthy": desired == ready and desired > 0, "desired": desired, "ready": ready}
|
||||
|
||||
|
||||
def get_tracing_policies() -> list[dict]:
|
||||
"""List all TracingPolicies deployed in the cluster."""
|
||||
output = run_kubectl_command([
|
||||
"kubectl", "get", "tracingpolicies", "-o", "json"
|
||||
])
|
||||
if not output:
|
||||
return []
|
||||
try:
|
||||
data = json.loads(output)
|
||||
policies = []
|
||||
for item in data.get("items", []):
|
||||
policies.append({
|
||||
"name": item["metadata"]["name"],
|
||||
"created": item["metadata"].get("creationTimestamp", "unknown"),
|
||||
"kprobes": len(item.get("spec", {}).get("kprobes", [])),
|
||||
"tracepoints": len(item.get("spec", {}).get("tracepoints", []))
|
||||
})
|
||||
return policies
|
||||
except (json.JSONDecodeError, KeyError):
|
||||
return []
|
||||
|
||||
|
||||
def parse_tetragon_events(log_file: str) -> list[dict]:
|
||||
"""Parse Tetragon JSON event log file."""
|
||||
events = []
|
||||
path = Path(log_file)
|
||||
if not path.exists():
|
||||
print(f"[ERROR] Log file not found: {log_file}")
|
||||
return events
|
||||
|
||||
with open(path, "r") as f:
|
||||
for line_num, line in enumerate(f, 1):
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
try:
|
||||
event = json.loads(line)
|
||||
events.append(event)
|
||||
except json.JSONDecodeError:
|
||||
print(f"[WARN] Skipping malformed JSON at line {line_num}")
|
||||
return events
|
||||
|
||||
|
||||
def classify_event(event: dict) -> str:
|
||||
"""Classify a Tetragon event by type."""
|
||||
if "process_exec" in event:
|
||||
return "process_exec"
|
||||
elif "process_exit" in event:
|
||||
return "process_exit"
|
||||
elif "process_kprobe" in event:
|
||||
return "kprobe"
|
||||
elif "process_tracepoint" in event:
|
||||
return "tracepoint"
|
||||
elif "process_lsm" in event:
|
||||
return "lsm"
|
||||
return "unknown"
|
||||
|
||||
|
||||
def extract_process_info(event: dict) -> dict:
|
||||
"""Extract process information from a Tetragon event."""
|
||||
info = {"binary": "", "args": "", "namespace": "", "pod": "", "uid": 0, "action": ""}
|
||||
for event_type in ["process_exec", "process_kprobe", "process_tracepoint"]:
|
||||
if event_type in event:
|
||||
process = event[event_type].get("process", {})
|
||||
info["binary"] = process.get("binary", "")
|
||||
info["args"] = process.get("arguments", "")
|
||||
info["uid"] = process.get("uid", {}).get("value", 0)
|
||||
pod_info = process.get("pod", {})
|
||||
info["namespace"] = pod_info.get("namespace", "")
|
||||
info["pod"] = pod_info.get("name", "")
|
||||
if event_type == "process_kprobe":
|
||||
info["action"] = event[event_type].get("action", "")
|
||||
break
|
||||
return info
|
||||
|
||||
|
||||
def detect_suspicious_binaries(events: list[dict]) -> list[dict]:
|
||||
"""Detect execution of known suspicious binaries."""
|
||||
suspicious_binaries = {
|
||||
"/bin/sh", "/bin/bash", "/bin/dash", "/usr/bin/curl",
|
||||
"/usr/bin/wget", "/usr/bin/nc", "/usr/bin/ncat",
|
||||
"/usr/bin/nmap", "/usr/bin/python", "/usr/bin/python3",
|
||||
"/usr/bin/perl", "/usr/bin/ruby", "/usr/bin/gcc",
|
||||
"/usr/bin/cc", "/usr/bin/make", "/usr/bin/xmrig",
|
||||
"/tmp/xmrig", "/usr/bin/minerd",
|
||||
"/usr/bin/sudo", "/bin/su", "/usr/bin/passwd",
|
||||
"/usr/bin/nsenter", "/usr/bin/unshare"
|
||||
}
|
||||
findings = []
|
||||
for event in events:
|
||||
info = extract_process_info(event)
|
||||
if info["binary"] in suspicious_binaries:
|
||||
findings.append({
|
||||
"severity": "HIGH" if info["binary"] in {"/usr/bin/xmrig", "/usr/bin/nsenter", "/usr/bin/unshare"} else "MEDIUM",
|
||||
"binary": info["binary"],
|
||||
"args": info["args"],
|
||||
"namespace": info["namespace"],
|
||||
"pod": info["pod"],
|
||||
"description": f"Suspicious binary execution: {info['binary']}"
|
||||
})
|
||||
return findings
|
||||
|
||||
|
||||
def detect_privilege_escalation(events: list[dict]) -> list[dict]:
|
||||
"""Detect privilege escalation attempts from event data."""
|
||||
findings = []
|
||||
priv_esc_binaries = {"/usr/bin/sudo", "/bin/su", "/usr/bin/passwd", "/usr/bin/newgrp"}
|
||||
for event in events:
|
||||
info = extract_process_info(event)
|
||||
if info["binary"] in priv_esc_binaries and info["namespace"]:
|
||||
findings.append({
|
||||
"severity": "CRITICAL",
|
||||
"binary": info["binary"],
|
||||
"namespace": info["namespace"],
|
||||
"pod": info["pod"],
|
||||
"description": f"Privilege escalation attempt via {info['binary']} in pod {info['pod']}"
|
||||
})
|
||||
if info["uid"] == 0 and info["binary"] and info["namespace"]:
|
||||
findings.append({
|
||||
"severity": "HIGH",
|
||||
"binary": info["binary"],
|
||||
"namespace": info["namespace"],
|
||||
"pod": info["pod"],
|
||||
"description": f"Process running as root (UID 0): {info['binary']}"
|
||||
})
|
||||
return findings
|
||||
|
||||
|
||||
def detect_container_escape_attempts(events: list[dict]) -> list[dict]:
|
||||
"""Detect potential container escape attempts."""
|
||||
escape_indicators = {
|
||||
"__x64_sys_setns": "Namespace manipulation (potential container escape)",
|
||||
"__x64_sys_unshare": "Namespace unshare (potential privilege escalation)",
|
||||
"__x64_sys_mount": "Mount syscall (potential host filesystem access)",
|
||||
"__x64_sys_ptrace": "Ptrace syscall (potential process injection)",
|
||||
}
|
||||
findings = []
|
||||
for event in events:
|
||||
if "process_kprobe" in event:
|
||||
function_name = event["process_kprobe"].get("functionName", "")
|
||||
if function_name in escape_indicators:
|
||||
info = extract_process_info(event)
|
||||
findings.append({
|
||||
"severity": "CRITICAL",
|
||||
"function": function_name,
|
||||
"binary": info["binary"],
|
||||
"namespace": info["namespace"],
|
||||
"pod": info["pod"],
|
||||
"action": info["action"],
|
||||
"description": escape_indicators[function_name]
|
||||
})
|
||||
return findings
|
||||
|
||||
|
||||
def generate_event_summary(events: list[dict]) -> dict:
|
||||
"""Generate a statistical summary of Tetragon events."""
|
||||
event_types = Counter()
|
||||
namespaces = Counter()
|
||||
binaries = Counter()
|
||||
actions = Counter()
|
||||
|
||||
for event in events:
|
||||
event_type = classify_event(event)
|
||||
event_types[event_type] += 1
|
||||
info = extract_process_info(event)
|
||||
if info["namespace"]:
|
||||
namespaces[info["namespace"]] += 1
|
||||
if info["binary"]:
|
||||
binaries[info["binary"]] += 1
|
||||
if info["action"]:
|
||||
actions[info["action"]] += 1
|
||||
|
||||
return {
|
||||
"total_events": len(events),
|
||||
"event_types": dict(event_types.most_common(10)),
|
||||
"top_namespaces": dict(namespaces.most_common(10)),
|
||||
"top_binaries": dict(binaries.most_common(20)),
|
||||
"enforcement_actions": dict(actions),
|
||||
}
|
||||
|
||||
|
||||
def generate_report(events: list[dict], output_format: str = "text") -> str:
|
||||
"""Generate a comprehensive security report."""
|
||||
summary = generate_event_summary(events)
|
||||
suspicious = detect_suspicious_binaries(events)
|
||||
priv_esc = detect_privilege_escalation(events)
|
||||
escape_attempts = detect_container_escape_attempts(events)
|
||||
tetragon_status = get_tetragon_status()
|
||||
policies = get_tracing_policies()
|
||||
|
||||
if output_format == "json":
|
||||
report = {
|
||||
"report_generated": datetime.utcnow().isoformat(),
|
||||
"tetragon_status": tetragon_status,
|
||||
"tracing_policies": policies,
|
||||
"event_summary": summary,
|
||||
"findings": {
|
||||
"suspicious_binaries": suspicious,
|
||||
"privilege_escalation": priv_esc,
|
||||
"container_escape_attempts": escape_attempts
|
||||
},
|
||||
"risk_score": calculate_risk_score(suspicious, priv_esc, escape_attempts)
|
||||
}
|
||||
return json.dumps(report, indent=2)
|
||||
|
||||
lines = []
|
||||
lines.append("=" * 70)
|
||||
lines.append("TETRAGON RUNTIME SECURITY REPORT")
|
||||
lines.append(f"Generated: {datetime.utcnow().isoformat()}")
|
||||
lines.append("=" * 70)
|
||||
|
||||
lines.append("\n## Tetragon Health")
|
||||
lines.append(f" Status: {'HEALTHY' if tetragon_status['healthy'] else 'DEGRADED'}")
|
||||
lines.append(f" Nodes: {tetragon_status['ready']}/{tetragon_status['desired']} ready")
|
||||
|
||||
lines.append(f"\n## TracingPolicies Deployed: {len(policies)}")
|
||||
for p in policies:
|
||||
lines.append(f" - {p['name']} (kprobes: {p['kprobes']}, tracepoints: {p['tracepoints']})")
|
||||
|
||||
lines.append(f"\n## Event Summary")
|
||||
lines.append(f" Total Events: {summary['total_events']}")
|
||||
lines.append(" Event Types:")
|
||||
for etype, count in summary["event_types"].items():
|
||||
lines.append(f" {etype}: {count}")
|
||||
|
||||
lines.append("\n Top Namespaces:")
|
||||
for ns, count in summary["top_namespaces"].items():
|
||||
lines.append(f" {ns}: {count}")
|
||||
|
||||
lines.append("\n Top Binaries:")
|
||||
for binary, count in list(summary["top_binaries"].items())[:10]:
|
||||
lines.append(f" {binary}: {count}")
|
||||
|
||||
risk = calculate_risk_score(suspicious, priv_esc, escape_attempts)
|
||||
lines.append(f"\n## Risk Score: {risk['score']}/100 ({risk['level']})")
|
||||
|
||||
if escape_attempts:
|
||||
lines.append(f"\n## CRITICAL: Container Escape Attempts ({len(escape_attempts)})")
|
||||
for f in escape_attempts:
|
||||
lines.append(f" [{f['severity']}] {f['description']}")
|
||||
lines.append(f" Pod: {f['namespace']}/{f['pod']} | Binary: {f['binary']}")
|
||||
|
||||
if priv_esc:
|
||||
lines.append(f"\n## Privilege Escalation Findings ({len(priv_esc)})")
|
||||
for f in priv_esc[:20]:
|
||||
lines.append(f" [{f['severity']}] {f['description']}")
|
||||
|
||||
if suspicious:
|
||||
lines.append(f"\n## Suspicious Binary Executions ({len(suspicious)})")
|
||||
for f in suspicious[:20]:
|
||||
lines.append(f" [{f['severity']}] {f['description']}")
|
||||
lines.append(f" Namespace: {f['namespace']} | Pod: {f['pod']}")
|
||||
|
||||
lines.append("\n" + "=" * 70)
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def calculate_risk_score(suspicious: list, priv_esc: list, escapes: list) -> dict:
|
||||
"""Calculate overall risk score based on findings."""
|
||||
score = 0
|
||||
score += len(escapes) * 25
|
||||
score += len([f for f in priv_esc if f["severity"] == "CRITICAL"]) * 15
|
||||
score += len([f for f in priv_esc if f["severity"] == "HIGH"]) * 5
|
||||
score += len([f for f in suspicious if f["severity"] == "HIGH"]) * 10
|
||||
score += len([f for f in suspicious if f["severity"] == "MEDIUM"]) * 3
|
||||
score = min(score, 100)
|
||||
|
||||
if score >= 80:
|
||||
level = "CRITICAL"
|
||||
elif score >= 50:
|
||||
level = "HIGH"
|
||||
elif score >= 25:
|
||||
level = "MEDIUM"
|
||||
else:
|
||||
level = "LOW"
|
||||
|
||||
return {"score": score, "level": level}
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Tetragon Runtime Security Event Analyzer"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--log-file",
|
||||
help="Path to Tetragon JSON event log file"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--format", choices=["text", "json"], default="text",
|
||||
help="Output format (default: text)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--status-only", action="store_true",
|
||||
help="Only check Tetragon health and policy status"
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.status_only:
|
||||
status = get_tetragon_status()
|
||||
policies = get_tracing_policies()
|
||||
print(f"Tetragon Health: {'HEALTHY' if status['healthy'] else 'DEGRADED'}")
|
||||
print(f"Nodes Ready: {status['ready']}/{status['desired']}")
|
||||
print(f"TracingPolicies: {len(policies)}")
|
||||
for p in policies:
|
||||
print(f" - {p['name']}")
|
||||
return
|
||||
|
||||
if not args.log_file:
|
||||
print("[ERROR] --log-file is required (or use --status-only)")
|
||||
sys.exit(1)
|
||||
|
||||
events = parse_tetragon_events(args.log_file)
|
||||
if not events:
|
||||
print("[WARN] No events found in log file")
|
||||
return
|
||||
|
||||
report = generate_report(events, args.format)
|
||||
print(report)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user