#!/usr/bin/env python3 """OPA Gatekeeper Policy Enforcement Agent - audits constraint templates and violation status.""" 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): cmd = ["kubectl"] + args_list + ["-o", "json"] result = subprocess.run(cmd, capture_output=True, text=True, timeout=120) return json.loads(result.stdout) if result.returncode == 0 else {} def get_constraint_templates(): return kubectl_json(["get", "constrainttemplates"]) def get_constraints(): templates = get_constraint_templates() constraints = [] for item in templates.get("items", []): kind = item.get("metadata", {}).get("name", "") result = kubectl_json(["get", kind]) for c in result.get("items", []): constraints.append(c) return constraints def audit_constraint_violations(constraints): violations = [] for constraint in constraints: name = constraint.get("metadata", {}).get("name", "") kind = constraint.get("kind", "") status = constraint.get("status", {}) total = status.get("totalViolations", 0) violation_list = status.get("violations", []) if total > 0: violations.append({ "constraint": name, "kind": kind, "total_violations": total, "enforcement_action": constraint.get("spec", {}).get("enforcementAction", "deny"), "sample_violations": violation_list[:5], }) return sorted(violations, key=lambda x: x["total_violations"], reverse=True) def analyze_policy_coverage(constraints): categories = defaultdict(int) enforcement = defaultdict(int) for c in constraints: categories[c.get("kind", "unknown")] += 1 enforcement[c.get("spec", {}).get("enforcementAction", "deny")] += 1 return {"total_constraints": len(constraints), "by_template": dict(categories), "by_enforcement_action": dict(enforcement)} def check_audit_status(): cmd = ["kubectl", "get", "pods", "-n", "gatekeeper-system", "-o", "json"] result = subprocess.run(cmd, capture_output=True, text=True, timeout=120) pods = json.loads(result.stdout) if result.returncode == 0 else {} pod_status = [] for pod in pods.get("items", []): name = pod.get("metadata", {}).get("name", "") phase = pod.get("status", {}).get("phase", "") ready = all(c.get("ready", False) for c in pod.get("status", {}).get("containerStatuses", [])) pod_status.append({"name": name, "phase": phase, "ready": ready}) return pod_status def generate_report(templates, constraints, violations, coverage, pod_status): return { "timestamp": datetime.utcnow().isoformat(), "constraint_templates": len(templates.get("items", [])), "active_constraints": len(constraints), "policy_coverage": coverage, "total_violations": sum(v["total_violations"] for v in violations), "constraints_with_violations": len(violations), "top_violations": violations[:15], "gatekeeper_pods": pod_status, "gatekeeper_healthy": all(p["ready"] for p in pod_status) if pod_status else False, } def main(): parser = argparse.ArgumentParser(description="OPA Gatekeeper Policy Enforcement Audit Agent") parser.add_argument("--output", default="gatekeeper_audit_report.json") args = parser.parse_args() templates = get_constraint_templates() constraints = get_constraints() violations = audit_constraint_violations(constraints) coverage = analyze_policy_coverage(constraints) pod_status = check_audit_status() report = generate_report(templates, constraints, violations, coverage, pod_status) with open(args.output, "w") as f: json.dump(report, f, indent=2, default=str) logger.info("Gatekeeper: %d templates, %d constraints, %d violations", report["constraint_templates"], report["active_constraints"], report["total_violations"]) print(json.dumps(report, indent=2, default=str)) if __name__ == "__main__": main()