container security

Implementing OPA Gatekeeper for Policy Enforcement

Enforce Kubernetes admission policies using OPA Gatekeeper with ConstraintTemplates, Rego rules, and the Gatekeeper policy library.

admission-controlgatekeeperkubernetesopapolicy-as-coderego
Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-Skills
Framework mappings

Overview

OPA Gatekeeper is a Kubernetes admission controller that enforces policies written in Rego. It uses ConstraintTemplates (policy blueprints with Rego logic) and Constraints (instantiated policies with parameters) to validate, mutate, or deny Kubernetes resource requests at admission time.

When to Use

  • When deploying or configuring implementing opa gatekeeper for policy enforcement capabilities in your environment
  • When establishing security controls aligned to compliance requirements
  • When building or improving security architecture for this domain
  • When conducting security assessments that require this implementation

Prerequisites

  • Kubernetes cluster v1.24+
  • Helm 3
  • kubectl with cluster-admin access
  • Familiarity with Rego policy language

Installing Gatekeeper

# Install via Helm
helm repo add gatekeeper https://open-policy-agent.github.io/gatekeeper/charts
helm repo update
 
helm install gatekeeper gatekeeper/gatekeeper \
  --namespace gatekeeper-system --create-namespace \
  --set replicas=3 \
  --set audit.replicas=1 \
  --set audit.logLevel=INFO
 
# Verify
kubectl get pods -n gatekeeper-system
kubectl get crd | grep gatekeeper

Verify Installation

# Check webhook
kubectl get validatingwebhookconfigurations gatekeeper-validating-webhook-configuration
 
# Check CRDs
kubectl get crd constrainttemplates.templates.gatekeeper.sh
kubectl get crd configs.config.gatekeeper.sh

ConstraintTemplate Examples

1. Require Labels on Resources

# template-required-labels.yaml
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
  name: k8srequiredlabels
spec:
  crd:
    spec:
      names:
        kind: K8sRequiredLabels
      validation:
        openAPIV3Schema:
          type: object
          properties:
            labels:
              type: array
              items:
                type: string
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8srequiredlabels
 
        violation[{"msg": msg, "details": {"missing_labels": missing}}] {
          provided := {label | input.review.object.metadata.labels[label]}
          required := {label | label := input.parameters.labels[_]}
          missing := required - provided
          count(missing) > 0
          msg := sprintf("Missing required labels: %v", [missing])
        }
# constraint-require-team-label.yaml
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
  name: require-team-label
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Namespace"]
      - apiGroups: ["apps"]
        kinds: ["Deployment"]
  parameters:
    labels:
      - "team"
      - "environment"

2. Block Privileged Containers

# template-block-privileged.yaml
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
  name: k8sblockprivileged
spec:
  crd:
    spec:
      names:
        kind: K8sBlockPrivileged
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8sblockprivileged
 
        violation[{"msg": msg}] {
          container := input.review.object.spec.containers[_]
          container.securityContext.privileged == true
          msg := sprintf("Privileged container not allowed: %v", [container.name])
        }
 
        violation[{"msg": msg}] {
          container := input.review.object.spec.initContainers[_]
          container.securityContext.privileged == true
          msg := sprintf("Privileged init container not allowed: %v", [container.name])
        }
# constraint-block-privileged.yaml
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sBlockPrivileged
metadata:
  name: block-privileged-containers
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
    namespaces:
      - "production"
      - "staging"

3. Restrict Container Image Registries

# template-allowed-repos.yaml
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
  name: k8sallowedrepos
spec:
  crd:
    spec:
      names:
        kind: K8sAllowedRepos
      validation:
        openAPIV3Schema:
          type: object
          properties:
            repos:
              type: array
              items:
                type: string
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8sallowedrepos
 
        violation[{"msg": msg}] {
          container := input.review.object.spec.containers[_]
          not image_matches(container.image)
          msg := sprintf("Container image %v is not from an allowed registry. Allowed: %v", [container.image, input.parameters.repos])
        }
 
        violation[{"msg": msg}] {
          container := input.review.object.spec.initContainers[_]
          not image_matches(container.image)
          msg := sprintf("Init container image %v is not from an allowed registry. Allowed: %v", [container.image, input.parameters.repos])
        }
 
        image_matches(image) {
          repo := input.parameters.repos[_]
          startswith(image, repo)
        }
# constraint-allowed-repos.yaml
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sAllowedRepos
metadata:
  name: restrict-image-repos
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
  parameters:
    repos:
      - "gcr.io/my-project/"
      - "ghcr.io/my-org/"
      - "registry.k8s.io/"

4. Enforce Resource Limits

# template-require-limits.yaml
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
  name: k8srequirelimits
spec:
  crd:
    spec:
      names:
        kind: K8sRequireLimits
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8srequirelimits
 
        violation[{"msg": msg}] {
          container := input.review.object.spec.containers[_]
          not container.resources.limits.cpu
          msg := sprintf("Container %v has no CPU limit", [container.name])
        }
 
        violation[{"msg": msg}] {
          container := input.review.object.spec.containers[_]
          not container.resources.limits.memory
          msg := sprintf("Container %v has no memory limit", [container.name])
        }

5. Block Latest Image Tag

# template-block-latest-tag.yaml
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
  name: k8sblocklatesttag
spec:
  crd:
    spec:
      names:
        kind: K8sBlockLatestTag
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8sblocklatesttag
 
        violation[{"msg": msg}] {
          container := input.review.object.spec.containers[_]
          endswith(container.image, ":latest")
          msg := sprintf("Container %v uses ':latest' tag. Use specific version tags.", [container.name])
        }
 
        violation[{"msg": msg}] {
          container := input.review.object.spec.containers[_]
          not contains(container.image, ":")
          msg := sprintf("Container %v has no tag (defaults to latest). Use specific version tags.", [container.name])
        }

6. Enforce Read-Only Root Filesystem

apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
  name: k8sreadonlyroot
spec:
  crd:
    spec:
      names:
        kind: K8sReadOnlyRoot
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8sreadonlyroot
 
        violation[{"msg": msg}] {
          container := input.review.object.spec.containers[_]
          not container.securityContext.readOnlyRootFilesystem
          msg := sprintf("Container %v must have readOnlyRootFilesystem set to true", [container.name])
        }

Audit and Enforcement Modes

# Dry-run mode (audit only, don't block)
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sBlockPrivileged
metadata:
  name: block-privileged-dryrun
spec:
  enforcementAction: dryrun   # dryrun | deny | warn
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]

Check Audit Violations

# List all constraint violations
kubectl get k8sblockprivileged block-privileged-containers -o yaml | grep -A 20 violations
 
# Check all constraints audit status
kubectl get constraints -o json | jq '.items[] | {name: .metadata.name, violations: (.status.violations // [] | length)}'

Gatekeeper Config (Exempt Namespaces)

apiVersion: config.gatekeeper.sh/v1alpha1
kind: Config
metadata:
  name: config
  namespace: gatekeeper-system
spec:
  match:
    - excludedNamespaces:
        - kube-system
        - gatekeeper-system
        - calico-system
      processes:
        - "*"

Monitoring

# Check Gatekeeper metrics
kubectl port-forward -n gatekeeper-system svc/gatekeeper-webhook-service 8443:443
 
# Prometheus metrics
kubectl get --raw /metrics | grep gatekeeper

Best Practices

  1. Start with dryrun - Deploy constraints in dryrun mode first, review violations, then switch to deny
  2. Use the policy library - Leverage https://github.com/open-policy-agent/gatekeeper-library for pre-built templates
  3. Exempt system namespaces - Always exclude kube-system and gatekeeper-system
  4. Version control policies - Store ConstraintTemplates and Constraints in Git
  5. Monitor audit results - Check constraint .status.violations regularly
  6. Test Rego policies - Use opa test or Rego Playground before deploying
  7. Combine with admission webhooks - Layer Gatekeeper with Pod Security Admission for defense in depth
Source materials

References and resources

Everything below is rendered for inspection. Script files are read-only and never run.

References 3

api-reference.md1.1 KB

API Reference: OPA Gatekeeper Policy Enforcement

OPA REST API (localhost:8181)

Endpoint Method Description
/v1/data/{path} GET/POST Query policy
/v1/policies/{id} PUT Create/update policy
/v1/data POST Evaluate input against policy

Gatekeeper CRDs

CRD Description
ConstraintTemplate Define policy schema + Rego
Constraint Instantiate a template
Config Audit/sync configuration

ConstraintTemplate Example

apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
  name: k8srequiredlabels
spec:
  crd:
    spec:
      names:
        kind: K8sRequiredLabels
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8srequiredlabels
        violation[{"msg": msg}] {
          not input.review.object.metadata.labels["app"]
          msg := "Missing required label: app"
        }

Key Libraries

Library Use
kubernetes K8s API client
requests OPA REST queries
subprocess kubectl commands
standards.md2.1 KB

Standards and References - OPA Gatekeeper Policy Enforcement

Industry Standards

NIST SP 800-190

  • Section 4.1: Image vulnerabilities - Enforce image registry restrictions
  • Section 4.2: Image configuration defects - Enforce security context requirements
  • Section 5.2: Registry security - Restrict allowed image sources

CIS Kubernetes Benchmark v1.8

  • 5.2.1: Ensure Pods cannot run with privileged containers
  • 5.2.2: Ensure Pods cannot share host PID namespace
  • 5.2.3: Ensure Pods cannot share host IPC namespace
  • 5.2.4: Ensure Pods cannot share host network namespace
  • 5.2.5: Ensure containers do not allow privilege escalation
  • 5.2.6: Ensure containers do not run as root
  • 5.2.7: Ensure Pods use seccomp profile
  • 5.2.8: Ensure Pods restrict volume types
  • 5.2.9: Ensure Pods restrict host path volumes
  • 5.7.1: Create administrative boundaries using namespaces
  • 5.7.2: Ensure seccomp profile is set
  • 5.7.3: Apply security context to pods

NSA/CISA Kubernetes Hardening Guide

  • Section 2: Pod Security - Admission control enforcement
  • Recommends admission controllers to enforce security baselines

Gatekeeper Policy Library

Template Purpose CIS Mapping
K8sPSPPrivilegedContainer Block privileged containers 5.2.1
K8sPSPHostNamespace Block host PID/IPC/Network 5.2.2-5.2.4
K8sPSPAllowPrivilegeEscalation Prevent privilege escalation 5.2.5
K8sPSPRunAsNonRoot Require non-root 5.2.6
K8sPSPSeccomp Require seccomp profiles 5.2.7
K8sPSPVolumeTypes Restrict volume types 5.2.8
K8sPSPHostFilesystem Restrict hostPath 5.2.9
K8sAllowedRepos Restrict image registries 5.1.1
K8sRequiredLabels Enforce labeling standards Organizational
K8sContainerLimits Enforce resource limits Operational

Compliance Mappings

PCI DSS v4.0

  • Req 2.2: Secure system components per configuration standards
  • Req 6.3.2: Develop software securely with automated controls

SOC 2

  • CC6.1: Logical access to system components is restricted
  • CC8.1: Changes to infrastructure are controlled
workflows.md2.7 KB

Workflow - OPA Gatekeeper Policy Enforcement

Phase 1: Install Gatekeeper

helm repo add gatekeeper https://open-policy-agent.github.io/gatekeeper/charts
helm repo update
helm install gatekeeper gatekeeper/gatekeeper \
  --namespace gatekeeper-system --create-namespace \
  --set replicas=3 --set audit.replicas=1
 
kubectl -n gatekeeper-system rollout status deployment/gatekeeper-controller-manager

Phase 2: Deploy ConstraintTemplates

# Clone Gatekeeper policy library
git clone https://github.com/open-policy-agent/gatekeeper-library.git
 
# Apply common templates
kubectl apply -f gatekeeper-library/library/pod-security-policy/privileged-containers/template.yaml
kubectl apply -f gatekeeper-library/library/pod-security-policy/host-namespaces/template.yaml
kubectl apply -f gatekeeper-library/library/pod-security-policy/allow-privilege-escalation/template.yaml
kubectl apply -f gatekeeper-library/library/general/allowedrepos/template.yaml
kubectl apply -f gatekeeper-library/library/general/requiredlabels/template.yaml
kubectl apply -f gatekeeper-library/library/general/containerlimits/template.yaml

Phase 3: Deploy Constraints in Dryrun Mode

kubectl apply -f - <<EOF
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPPrivilegedContainer
metadata:
  name: block-privileged-dryrun
spec:
  enforcementAction: dryrun
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
    excludedNamespaces:
      - kube-system
      - gatekeeper-system
EOF

Phase 4: Review Audit Violations

# Check violations for each constraint
kubectl get constraints -o json | jq '.items[] | {
  name: .metadata.name,
  enforcement: .spec.enforcementAction,
  violations: (.status.violations // [] | length),
  total_violations: .status.totalViolations
}'
 
# Get detailed violations
kubectl get k8spsprivilegedcontainer block-privileged-dryrun -o json | jq '.status.violations[]'

Phase 5: Switch to Enforcement

# After reviewing violations and remediating, switch to deny
kubectl patch k8spsprivilegedcontainer block-privileged-dryrun \
  --type=merge -p '{"spec":{"enforcementAction":"deny"}}'

Phase 6: Test Enforcement

# This should be denied
kubectl run test-priv --image=nginx --overrides='{"spec":{"containers":[{"name":"test","image":"nginx","securityContext":{"privileged":true}}]}}'
# Expected: Error from server (Forbidden): admission webhook denied the request
 
kubectl delete pod test-priv --ignore-not-found

Phase 7: Monitor and Maintain

# Regular audit check
kubectl get constraints -o wide
 
# Check Gatekeeper health
kubectl get pods -n gatekeeper-system
kubectl logs -n gatekeeper-system -l control-plane=controller-manager --tail=20

Scripts 2

agent.py4.2 KB
Display-only source. This catalog never executes bundled scripts.
#!/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()
process.py6.6 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""
OPA Gatekeeper Policy Manager - Generate ConstraintTemplates, audit
constraint violations, and manage policy lifecycle.
"""

import json
import subprocess
import sys
import argparse
import yaml


CONSTRAINT_TEMPLATES = {
    "required-labels": {
        "kind": "K8sRequiredLabels",
        "rego": """
package k8srequiredlabels

violation[{"msg": msg, "details": {"missing_labels": missing}}] {
  provided := {label | input.review.object.metadata.labels[label]}
  required := {label | label := input.parameters.labels[_]}
  missing := required - provided
  count(missing) > 0
  msg := sprintf("Missing required labels: %v", [missing])
}
""",
        "params_schema": {
            "type": "object",
            "properties": {
                "labels": {"type": "array", "items": {"type": "string"}}
            },
        },
    },
    "block-privileged": {
        "kind": "K8sBlockPrivileged",
        "rego": """
package k8sblockprivileged

violation[{"msg": msg}] {
  container := input.review.object.spec.containers[_]
  container.securityContext.privileged == true
  msg := sprintf("Privileged container not allowed: %v", [container.name])
}

violation[{"msg": msg}] {
  container := input.review.object.spec.initContainers[_]
  container.securityContext.privileged == true
  msg := sprintf("Privileged init container not allowed: %v", [container.name])
}
""",
        "params_schema": None,
    },
    "allowed-repos": {
        "kind": "K8sAllowedRepos",
        "rego": """
package k8sallowedrepos

violation[{"msg": msg}] {
  container := input.review.object.spec.containers[_]
  not image_matches(container.image)
  msg := sprintf("Image %v not from allowed registry. Allowed: %v", [container.image, input.parameters.repos])
}

image_matches(image) {
  repo := input.parameters.repos[_]
  startswith(image, repo)
}
""",
        "params_schema": {
            "type": "object",
            "properties": {
                "repos": {"type": "array", "items": {"type": "string"}}
            },
        },
    },
    "block-latest-tag": {
        "kind": "K8sBlockLatestTag",
        "rego": """
package k8sblocklatesttag

violation[{"msg": msg}] {
  container := input.review.object.spec.containers[_]
  endswith(container.image, ":latest")
  msg := sprintf("Container %v uses ':latest' tag", [container.name])
}

violation[{"msg": msg}] {
  container := input.review.object.spec.containers[_]
  not contains(container.image, ":")
  msg := sprintf("Container %v has no tag (defaults to latest)", [container.name])
}
""",
        "params_schema": None,
    },
    "require-limits": {
        "kind": "K8sRequireLimits",
        "rego": """
package k8srequirelimits

violation[{"msg": msg}] {
  container := input.review.object.spec.containers[_]
  not container.resources.limits.cpu
  msg := sprintf("Container %v has no CPU limit", [container.name])
}

violation[{"msg": msg}] {
  container := input.review.object.spec.containers[_]
  not container.resources.limits.memory
  msg := sprintf("Container %v has no memory limit", [container.name])
}
""",
        "params_schema": None,
    },
}


def generate_constraint_template(template_name: str) -> str:
    """Generate a ConstraintTemplate YAML."""
    tmpl = CONSTRAINT_TEMPLATES.get(template_name)
    if not tmpl:
        print(f"Unknown template: {template_name}", file=sys.stderr)
        sys.exit(1)

    ct = {
        "apiVersion": "templates.gatekeeper.sh/v1",
        "kind": "ConstraintTemplate",
        "metadata": {"name": tmpl["kind"].lower()},
        "spec": {
            "crd": {
                "spec": {
                    "names": {"kind": tmpl["kind"]},
                }
            },
            "targets": [{
                "target": "admission.k8s.gatekeeper.sh",
                "rego": tmpl["rego"].strip(),
            }],
        },
    }

    if tmpl["params_schema"]:
        ct["spec"]["crd"]["spec"]["validation"] = {
            "openAPIV3Schema": tmpl["params_schema"]
        }

    return yaml.dump(ct, default_flow_style=False)


def audit_constraints() -> list:
    """Fetch all constraint violations from the cluster."""
    result = subprocess.run(
        ["kubectl", "get", "constraints", "-o", "json"],
        capture_output=True, text=True,
    )
    if result.returncode != 0:
        print(f"Error: {result.stderr}", file=sys.stderr)
        return []

    data = json.loads(result.stdout)
    results = []
    for item in data.get("items", []):
        name = item["metadata"]["name"]
        kind = item["kind"]
        enforcement = item.get("spec", {}).get("enforcementAction", "deny")
        violations = item.get("status", {}).get("violations", [])
        total = item.get("status", {}).get("totalViolations", 0)
        results.append({
            "name": name,
            "kind": kind,
            "enforcement": enforcement,
            "violation_count": total,
            "violations": violations[:10],
        })
    return results


def print_audit_report(results: list):
    """Print audit report."""
    print("\n=== OPA Gatekeeper Audit Report ===\n")
    total_violations = sum(r["violation_count"] for r in results)
    print(f"Total Constraints: {len(results)}")
    print(f"Total Violations: {total_violations}\n")

    print(f"{'Constraint':<40} {'Kind':<25} {'Mode':<10} {'Violations'}")
    print("-" * 90)
    for r in sorted(results, key=lambda x: -x["violation_count"]):
        print(f"{r['name']:<40} {r['kind']:<25} {r['enforcement']:<10} {r['violation_count']}")

    if total_violations > 0:
        print("\n--- Top Violations ---")
        for r in results:
            for v in r["violations"][:3]:
                print(f"  [{r['name']}] {v.get('message', 'No message')}")


def main():
    parser = argparse.ArgumentParser(description="OPA Gatekeeper Policy Manager")
    subparsers = parser.add_subparsers(dest="command")

    gen = subparsers.add_parser("generate", help="Generate ConstraintTemplate")
    gen.add_argument("--template", required=True,
                    choices=list(CONSTRAINT_TEMPLATES.keys()),
                    help="Template name")

    subparsers.add_parser("list-templates", help="List available templates")
    subparsers.add_parser("audit", help="Audit all constraint violations")

    args = parser.parse_args()

    if args.command == "generate":
        print(generate_constraint_template(args.template))

    elif args.command == "list-templates":
        print("Available ConstraintTemplates:")
        for name, tmpl in CONSTRAINT_TEMPLATES.items():
            print(f"  {name}: {tmpl['kind']}")

    elif args.command == "audit":
        results = audit_constraints()
        print_audit_report(results)

    else:
        parser.print_help()


if __name__ == "__main__":
    main()

Assets 1

template.mdtext/markdown · 1.4 KB
Keep exploring