Skip to content

Policy Engines Cheat Sheet

Remember: Kyverno vs OPA Gatekeeper decision shortcut: if your team already knows Rego, use Gatekeeper. If not, use Kyverno — its YAML-native policies have a much lower learning curve. Kyverno also does mutation and generation (auto-create resources), which Gatekeeper does not support natively. Both work as Kubernetes admission webhooks that intercept API requests before they are persisted.

Kyverno vs OPA Gatekeeper

Feature Kyverno OPA Gatekeeper
Language YAML (native K8s) Rego (custom DSL)
Learning curve Low High
Policy types Validate, Mutate, Generate, VerifyImages Validate only (+ mutation in beta)
Policy format ClusterPolicy CRD ConstraintTemplate + Constraint
Audit mode validationFailureAction: Audit enforcementAction: dryrun

Kyverno

Validate — Block Non-Compliant Resources

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-labels
spec:
  validationFailureAction: Enforce  # Enforce | Audit
  rules:
  - name: check-team-label
    match:
      any:
      - resources:
          kinds: ["Deployment", "StatefulSet"]
    validate:
      message: "Label 'team' is required."
      pattern:
        metadata:
          labels:
            team: "?*"

Mutate — Auto-Fix Resources

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: add-default-requests
spec:
  rules:
  - name: add-cpu-memory-requests
    match:
      any:
      - resources:
          kinds: ["Pod"]
    mutate:
      patchStrategicMerge:
        spec:
          containers:
          - (name): "*"
            resources:
              requests:
                cpu: "100m"
                memory: "128Mi"

Generate — Auto-Create Resources

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: generate-networkpolicy
spec:
  rules:
  - name: default-deny
    match:
      any:
      - resources:
          kinds: ["Namespace"]
    generate:
      kind: NetworkPolicy
      apiVersion: networking.k8s.io/v1
      name: default-deny
      namespace: "{{request.object.metadata.name}}"
      data:
        spec:
          podSelector: {}
          policyTypes: ["Ingress", "Egress"]

Image Verification

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: verify-images
spec:
  rules:
  - name: verify-cosign
    match:
      any:
      - resources:
          kinds: ["Pod"]
    verifyImages:
    - imageReferences: ["registry.example.com/*"]
      attestors:
      - entries:
        - keys:
            publicKeys: |-
              -----BEGIN PUBLIC KEY-----
              ...
              -----END PUBLIC KEY-----

OPA Gatekeeper

ConstraintTemplate (Define the Rule)

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}] {
        provided := {label | input.review.object.metadata.labels[label]}
        required := {label | label := input.parameters.labels[_]}
        missing := required - provided
        count(missing) > 0
        msg := sprintf("Missing labels: %v", [missing])
      }

Constraint (Apply the Rule)

apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
  name: require-team-label
spec:
  enforcementAction: deny  # deny | dryrun | warn
  match:
    kinds:
    - apiGroups: ["apps"]
      kinds: ["Deployment"]
  parameters:
    labels: ["team", "env"]

Pod Security Standards (Built-in)

# Label-based enforcement (no extra tools needed)
apiVersion: v1
kind: Namespace
metadata:
  name: production
  labels:
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/audit: restricted
    pod-security.kubernetes.io/warn: restricted

Levels: privilegedbaselinerestricted

Useful Commands

# Kyverno
kubectl get clusterpolicy
kubectl get policyreport -A          # Audit results
kubectl get clusterpolicyreport      # Cluster-scoped results

# Gatekeeper
kubectl get constrainttemplates
kubectl get constraints              # All constraint types
kubectl get k8srequiredlabels -o yaml  # Specific constraint + violations

# Test a resource against policies (Kyverno CLI)
kyverno apply policy.yaml --resource resource.yaml

Gotcha: Policy engine webhooks are a single point of failure for the entire cluster. If the webhook pod is down and failurePolicy: Fail (the secure default), no resources can be created in the cluster — including the webhook pod itself (deadlock). Always run policy engine pods with high priority, anti-affinity across nodes, and consider failurePolicy: Ignore for non-critical policies in non-production clusters.

Rollout Strategy

1. Deploy policies in Audit mode
2. Review violations in policy reports
3. Fix existing violations
4. Switch to Enforce mode
5. Monitor for new violations