mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-08-01 00:37:42 +03:00
Complete folder anatomy for all 649 cybersecurity skills + update LICENSE to Mahipal
- 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
This commit is contained in:
@@ -0,0 +1,157 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Kubernetes Network Policy Agent - audits pod-to-pod communication and network policy coverage."""
|
||||
|
||||
import json
|
||||
import argparse
|
||||
import logging
|
||||
import subprocess
|
||||
from collections import defaultdict
|
||||
from datetime import datetime
|
||||
|
||||
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def kubectl_json(args_list):
|
||||
"""Execute kubectl command and return JSON output."""
|
||||
cmd = ["kubectl"] + args_list + ["-o", "json"]
|
||||
result = subprocess.run(cmd, capture_output=True, text=True)
|
||||
return json.loads(result.stdout) if result.returncode == 0 else {}
|
||||
|
||||
|
||||
def get_namespaces():
|
||||
return kubectl_json(["get", "namespaces"])
|
||||
|
||||
|
||||
def get_network_policies(namespace="--all-namespaces"):
|
||||
if namespace == "--all-namespaces":
|
||||
return kubectl_json(["get", "networkpolicies", "--all-namespaces"])
|
||||
return kubectl_json(["get", "networkpolicies", "-n", namespace])
|
||||
|
||||
|
||||
def get_pods(namespace="--all-namespaces"):
|
||||
if namespace == "--all-namespaces":
|
||||
return kubectl_json(["get", "pods", "--all-namespaces"])
|
||||
return kubectl_json(["get", "pods", "-n", namespace])
|
||||
|
||||
|
||||
def analyze_policy_coverage(policies, pods):
|
||||
"""Determine which pods are covered by network policies."""
|
||||
policy_selectors = []
|
||||
for item in policies.get("items", []):
|
||||
ns = item.get("metadata", {}).get("namespace", "")
|
||||
spec = item.get("spec", {})
|
||||
selector = spec.get("podSelector", {}).get("matchLabels", {})
|
||||
policy_types = spec.get("policyTypes", [])
|
||||
policy_selectors.append({
|
||||
"namespace": ns,
|
||||
"selector": selector,
|
||||
"ingress": "Ingress" in policy_types or spec.get("ingress") is not None,
|
||||
"egress": "Egress" in policy_types or spec.get("egress") is not None,
|
||||
})
|
||||
covered_pods = set()
|
||||
uncovered_pods = []
|
||||
for pod in pods.get("items", []):
|
||||
pod_ns = pod.get("metadata", {}).get("namespace", "")
|
||||
pod_name = pod.get("metadata", {}).get("name", "")
|
||||
pod_labels = pod.get("metadata", {}).get("labels", {})
|
||||
is_covered = False
|
||||
for policy in policy_selectors:
|
||||
if policy["namespace"] != pod_ns:
|
||||
continue
|
||||
if not policy["selector"]:
|
||||
is_covered = True
|
||||
break
|
||||
if all(pod_labels.get(k) == v for k, v in policy["selector"].items()):
|
||||
is_covered = True
|
||||
break
|
||||
if is_covered:
|
||||
covered_pods.add(f"{pod_ns}/{pod_name}")
|
||||
else:
|
||||
uncovered_pods.append({"namespace": pod_ns, "pod": pod_name, "labels": pod_labels})
|
||||
total = len(pods.get("items", []))
|
||||
return {
|
||||
"total_pods": total,
|
||||
"covered_pods": len(covered_pods),
|
||||
"uncovered_pods": len(uncovered_pods),
|
||||
"coverage_percent": round(len(covered_pods) / max(total, 1) * 100, 1),
|
||||
"uncovered_pod_list": uncovered_pods[:20],
|
||||
}
|
||||
|
||||
|
||||
def detect_overly_permissive_policies(policies):
|
||||
"""Find network policies that allow all traffic."""
|
||||
findings = []
|
||||
for item in policies.get("items", []):
|
||||
name = item.get("metadata", {}).get("name", "")
|
||||
ns = item.get("metadata", {}).get("namespace", "")
|
||||
spec = item.get("spec", {})
|
||||
if not spec.get("podSelector", {}).get("matchLabels"):
|
||||
ingress_rules = spec.get("ingress", [])
|
||||
for rule in ingress_rules:
|
||||
if not rule.get("from"):
|
||||
findings.append({"policy": name, "namespace": ns,
|
||||
"issue": "allows_all_ingress", "severity": "high"})
|
||||
egress_rules = spec.get("egress", [])
|
||||
for rule in egress_rules:
|
||||
if not rule.get("to"):
|
||||
findings.append({"policy": name, "namespace": ns,
|
||||
"issue": "allows_all_egress", "severity": "medium"})
|
||||
return findings
|
||||
|
||||
|
||||
def analyze_namespace_isolation(policies, namespaces):
|
||||
"""Check which namespaces have default-deny policies."""
|
||||
ns_with_deny = set()
|
||||
for item in policies.get("items", []):
|
||||
spec = item.get("spec", {})
|
||||
if (not spec.get("podSelector", {}).get("matchLabels") and
|
||||
not spec.get("ingress") and "Ingress" in spec.get("policyTypes", [])):
|
||||
ns_with_deny.add(item.get("metadata", {}).get("namespace", ""))
|
||||
all_ns = [ns.get("metadata", {}).get("name", "") for ns in namespaces.get("items", [])]
|
||||
system_ns = {"kube-system", "kube-public", "kube-node-lease"}
|
||||
user_ns = [ns for ns in all_ns if ns not in system_ns]
|
||||
return {
|
||||
"total_namespaces": len(user_ns),
|
||||
"namespaces_with_default_deny": len(ns_with_deny),
|
||||
"isolation_percent": round(len(ns_with_deny) / max(len(user_ns), 1) * 100, 1),
|
||||
"unprotected_namespaces": [ns for ns in user_ns if ns not in ns_with_deny],
|
||||
}
|
||||
|
||||
|
||||
def generate_report(policies, pods, namespaces):
|
||||
coverage = analyze_policy_coverage(policies, pods)
|
||||
permissive = detect_overly_permissive_policies(policies)
|
||||
isolation = analyze_namespace_isolation(policies, namespaces)
|
||||
report = {
|
||||
"timestamp": datetime.utcnow().isoformat(),
|
||||
"total_network_policies": len(policies.get("items", [])),
|
||||
"pod_coverage": coverage,
|
||||
"namespace_isolation": isolation,
|
||||
"overly_permissive_policies": permissive,
|
||||
"total_findings": len(permissive),
|
||||
}
|
||||
return report
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Kubernetes Network Policy Audit Agent")
|
||||
parser.add_argument("--namespace", default="--all-namespaces", help="Namespace to audit")
|
||||
parser.add_argument("--output", default="k8s_netpol_report.json")
|
||||
args = parser.parse_args()
|
||||
|
||||
policies = get_network_policies(args.namespace)
|
||||
pods = get_pods(args.namespace)
|
||||
namespaces = get_namespaces()
|
||||
report = generate_report(policies, pods, namespaces)
|
||||
with open(args.output, "w") as f:
|
||||
json.dump(report, f, indent=2, default=str)
|
||||
logger.info("K8s NetPol: %.1f%% pod coverage, %.1f%% namespace isolation, %d findings",
|
||||
report["pod_coverage"]["coverage_percent"],
|
||||
report["namespace_isolation"]["isolation_percent"],
|
||||
report["total_findings"])
|
||||
print(json.dumps(report, indent=2, default=str))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user