mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-07-14 03:15:16 +03:00
c21af3347e
- Add scripts/agent.py and references/api-reference.md to all remaining skills - Update all 648 LICENSE files: copyright now reads 'Mahipal' - Add implementing-security-monitoring-with-datadog (new skill with full anatomy) - All 649 skills now have: SKILL.md, LICENSE, scripts/agent.py, references/api-reference.md
172 lines
7.8 KiB
Python
172 lines
7.8 KiB
Python
#!/usr/bin/env python3
|
|
"""Agent for performing Kubernetes CIS benchmark assessment with kube-bench."""
|
|
|
|
import json
|
|
import argparse
|
|
import subprocess
|
|
from datetime import datetime
|
|
|
|
|
|
def run_kube_bench(target="node", benchmark=None):
|
|
"""Execute kube-bench CIS benchmark scan."""
|
|
cmd = ["kube-bench", "run", "--json"]
|
|
if target in ("master", "controlplane"):
|
|
cmd += ["--targets", "master"]
|
|
elif target == "node":
|
|
cmd += ["--targets", "node"]
|
|
elif target == "etcd":
|
|
cmd += ["--targets", "etcd"]
|
|
elif target == "policies":
|
|
cmd += ["--targets", "policies"]
|
|
if benchmark:
|
|
cmd += ["--benchmark", benchmark]
|
|
try:
|
|
result = subprocess.run(cmd, capture_output=True, text=True, timeout=120)
|
|
data = json.loads(result.stdout)
|
|
tests = data.get("Tests", data.get("tests", []))
|
|
summary = {"pass": 0, "fail": 0, "warn": 0, "info": 0}
|
|
failures = []
|
|
for section in tests:
|
|
for test in section.get("results", section.get("Results", [])):
|
|
status = test.get("status", "").lower()
|
|
summary[status] = summary.get(status, 0) + 1
|
|
if status == "fail":
|
|
failures.append({
|
|
"id": test.get("test_number", test.get("TestNumber", "")),
|
|
"desc": test.get("test_desc", test.get("TestDesc", ""))[:200],
|
|
"remediation": test.get("remediation", test.get("Remediation", ""))[:300],
|
|
"scored": test.get("scored", test.get("IsScored", True)),
|
|
})
|
|
return {
|
|
"target": target, "timestamp": datetime.utcnow().isoformat(),
|
|
"summary": summary, "total_checks": sum(summary.values()),
|
|
"compliance_pct": round(summary["pass"] / max(sum(summary.values()), 1) * 100, 1),
|
|
"failures": failures,
|
|
}
|
|
except FileNotFoundError:
|
|
return {"error": "kube-bench not found — install from github.com/aquasecurity/kube-bench"}
|
|
except json.JSONDecodeError:
|
|
return {"error": "Failed to parse kube-bench output", "raw": result.stdout[:500]}
|
|
except Exception as e:
|
|
return {"error": str(e)}
|
|
|
|
|
|
def check_pod_security(namespace="default"):
|
|
"""Check pod security settings via kubectl."""
|
|
cmd = ["kubectl", "get", "pods", "-n", namespace, "-o", "json"]
|
|
try:
|
|
result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
|
|
data = json.loads(result.stdout)
|
|
pods = data.get("items", [])
|
|
findings = []
|
|
for pod in pods:
|
|
name = pod.get("metadata", {}).get("name", "")
|
|
for container in pod.get("spec", {}).get("containers", []):
|
|
sc = container.get("securityContext", {})
|
|
issues = []
|
|
if sc.get("privileged"):
|
|
issues.append("PRIVILEGED_CONTAINER")
|
|
if sc.get("runAsUser") == 0 or not sc.get("runAsNonRoot"):
|
|
issues.append("RUNS_AS_ROOT")
|
|
if not sc.get("readOnlyRootFilesystem"):
|
|
issues.append("WRITABLE_ROOT_FS")
|
|
caps = sc.get("capabilities", {})
|
|
if caps.get("add") and any(c in caps["add"] for c in ["SYS_ADMIN", "NET_ADMIN", "ALL"]):
|
|
issues.append("DANGEROUS_CAPABILITIES")
|
|
if not sc.get("allowPrivilegeEscalation") is False:
|
|
issues.append("PRIVILEGE_ESCALATION_ALLOWED")
|
|
if issues:
|
|
findings.append({"pod": name, "container": container.get("name"), "issues": issues})
|
|
return {
|
|
"namespace": namespace, "total_pods": len(pods),
|
|
"pods_with_issues": len(findings), "findings": findings,
|
|
}
|
|
except FileNotFoundError:
|
|
return {"error": "kubectl not found"}
|
|
except Exception as e:
|
|
return {"error": str(e)}
|
|
|
|
|
|
def check_rbac_config():
|
|
"""Audit RBAC configuration for overly permissive roles."""
|
|
findings = []
|
|
for resource in ["clusterroles", "clusterrolebindings"]:
|
|
cmd = ["kubectl", "get", resource, "-o", "json"]
|
|
try:
|
|
result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
|
|
data = json.loads(result.stdout)
|
|
for item in data.get("items", []):
|
|
name = item.get("metadata", {}).get("name", "")
|
|
if resource == "clusterroles":
|
|
for rule in item.get("rules", []):
|
|
verbs = rule.get("verbs", [])
|
|
resources = rule.get("resources", [])
|
|
if "*" in verbs and "*" in resources:
|
|
findings.append({"type": "clusterrole", "name": name, "issue": "WILDCARD_ALL_PERMISSIONS"})
|
|
elif "create" in verbs and "pods" in resources:
|
|
findings.append({"type": "clusterrole", "name": name, "issue": "CAN_CREATE_PODS"})
|
|
elif resource == "clusterrolebindings":
|
|
subjects = item.get("subjects", [])
|
|
role_ref = item.get("roleRef", {}).get("name", "")
|
|
if role_ref == "cluster-admin":
|
|
for subj in subjects:
|
|
findings.append({
|
|
"type": "clusterrolebinding", "name": name,
|
|
"issue": f"CLUSTER_ADMIN_BOUND_TO_{subj.get('kind', '')}:{subj.get('name', '')}",
|
|
})
|
|
except Exception as e:
|
|
findings.append({"type": resource, "error": str(e)})
|
|
return {"total_findings": len(findings), "findings": findings}
|
|
|
|
|
|
def check_network_policies(namespace="default"):
|
|
"""Verify network policies exist and cover pods."""
|
|
cmd = ["kubectl", "get", "networkpolicies", "-n", namespace, "-o", "json"]
|
|
try:
|
|
result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
|
|
data = json.loads(result.stdout)
|
|
policies = data.get("items", [])
|
|
if not policies:
|
|
return {"namespace": namespace, "finding": "NO_NETWORK_POLICIES", "severity": "HIGH",
|
|
"recommendation": "Implement default-deny NetworkPolicy"}
|
|
return {
|
|
"namespace": namespace, "policy_count": len(policies),
|
|
"policies": [{"name": p["metadata"]["name"],
|
|
"pod_selector": p.get("spec", {}).get("podSelector", {}),
|
|
"ingress_rules": len(p.get("spec", {}).get("ingress", [])),
|
|
"egress_rules": len(p.get("spec", {}).get("egress", []))}
|
|
for p in policies],
|
|
}
|
|
except Exception as e:
|
|
return {"error": str(e)}
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="Kubernetes CIS Benchmark Agent (kube-bench)")
|
|
sub = parser.add_subparsers(dest="command")
|
|
b = sub.add_parser("bench", help="Run kube-bench CIS scan")
|
|
b.add_argument("--target", default="node", choices=["master", "controlplane", "node", "etcd", "policies"])
|
|
b.add_argument("--benchmark", help="CIS benchmark version")
|
|
p = sub.add_parser("pods", help="Check pod security settings")
|
|
p.add_argument("--namespace", default="default")
|
|
sub.add_parser("rbac", help="Audit RBAC configuration")
|
|
n = sub.add_parser("netpol", help="Check network policies")
|
|
n.add_argument("--namespace", default="default")
|
|
args = parser.parse_args()
|
|
if args.command == "bench":
|
|
result = run_kube_bench(args.target, args.benchmark)
|
|
elif args.command == "pods":
|
|
result = check_pod_security(args.namespace)
|
|
elif args.command == "rbac":
|
|
result = check_rbac_config()
|
|
elif args.command == "netpol":
|
|
result = check_network_policies(args.namespace)
|
|
else:
|
|
parser.print_help()
|
|
return
|
|
print(json.dumps(result, indent=2, default=str))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|