Skip to content

Kyverno Reference: K8s Policy Engine — Validate, Mutate, Generate & Image Verification

Kyverno is a Kubernetes-native policy engine. Policies are written as K8s CRDs — no Rego required. It validates, mutates, and generates K8s resources, and integrates naturally with kubectl. Simpler to adopt than OPA/Gatekeeper for most K8s policy use cases.

1. Kyverno vs OPA Gatekeeper

When to choose Kyverno
Feature Kyverno OPA Gatekeeper
Policy language Kubernetes YAML (no new language) Rego (new language to learn)
Mutation Yes — first-class mutate rules Needs separate Mutation webhook
Generation Yes — generate resources on trigger No
Test tools kyverno test (built-in unit testing) opa test (separate tool)
Image verification Yes — verifyImages with Cosign No
Learning curve Low — already know YAML/JMESPath High — Rego is a new paradigm
Best for Teams wanting K8s-native policies without Rego Complex policies, existing Rego expertise, multi-service mesh
# Install Kyverno:
helm repo add kyverno https://kyverno.github.io/kyverno/
helm install kyverno kyverno/kyverno -n kyverno --create-namespace

# Verify:
kubectl get pods -n kyverno
kubectl get crds | grep kyverno.io   # ClusterPolicy, Policy, PolicyReport, etc.

2. Validate Policies

Block non-compliant resources at admission time
# Require resource limits on all containers:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-resource-limits
spec:
  validationFailureAction: Enforce    # Enforce=block, Audit=allow+report
  background: true                    # also check existing resources
  rules:
    - name: check-resource-limits
      match:
        any:
          - resources:
              kinds: [Pod]
      validate:
        message: "All containers must define CPU and memory limits."
        pattern:
          spec:
            containers:
              - resources:
                  limits:
                    cpu: "?*"          # must be set to anything
                    memory: "?*"

# Disallow privileged containers:
    - name: deny-privileged
      match:
        any:
          - resources: {kinds: [Pod]}
      validate:
        message: "Privileged containers are not allowed."
        pattern:
          spec:
            containers:
              - =(securityContext):
                  =(privileged): "false"
            initContainers:
              - =(securityContext):
                  =(privileged): "false"

# Require specific labels on Deployments:
    - name: require-labels
      match:
        any:
          - resources: {kinds: [Deployment]}
      validate:
        message: "Deployment must have 'app' and 'version' labels."
        pattern:
          metadata:
            labels:
              app: "?*"
              version: "?*"

3. Mutate Policies

Automatically patch resources on admission
# Add default resource limits if not set:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: add-default-limits
spec:
  rules:
    - name: add-cpu-memory-limits
      match:
        any:
          - resources: {kinds: [Pod]}
      mutate:
        patchStrategicMerge:
          spec:
            containers:
              - (name): "*"
                resources:
                  limits:
                    +(cpu): "500m"          # add only if missing (+ prefix)
                    +(memory): "256Mi"
                  requests:
                    +(cpu): "100m"
                    +(memory): "64Mi"

# Add namespace label to all Pods:
    - name: add-namespace-label
      match:
        any:
          - resources: {kinds: [Pod]}
      mutate:
        patchStrategicMerge:
          metadata:
            labels:
              +(namespace): "{{ request.namespace }}"  # JMESPath expression

# Force non-root user if runAsUser is 0:
    - name: force-non-root
      match:
        any:
          - resources: {kinds: [Pod]}
      mutate:
        patchStrategicMerge:
          spec:
            securityContext:
              +(runAsNonRoot): true
              +(runAsUser): 1000         # set only if missing

4. Generate Policies

Auto-create resources (NetworkPolicy, RoleBinding) when namespace is created
# Auto-create default NetworkPolicy in every new namespace:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: add-default-networkpolicy
spec:
  rules:
    - name: default-deny-ingress
      match:
        any:
          - resources:
              kinds: [Namespace]
      generate:
        apiVersion: networking.k8s.io/v1
        kind: NetworkPolicy
        name: default-deny-ingress
        namespace: "{{ request.object.metadata.name }}"   # target namespace
        synchronize: true             # keep in sync (update if policy changes)
        data:
          spec:
            podSelector: {}
            policyTypes: [Ingress]

# Auto-copy a Secret to every new namespace (e.g. Docker registry credentials):
    - name: copy-regcred
      match:
        any:
          - resources: {kinds: [Namespace]}
      generate:
        apiVersion: v1
        kind: Secret
        name: regcred
        namespace: "{{ request.object.metadata.name }}"
        synchronize: true
        clone:
          namespace: default          # clone from this source namespace
          name: regcred

5. Testing & Operations

Unit test policies, check reports, verify images
# Test policies locally (no cluster needed):
# Create kyverno-test.yaml next to your policy:
policies:
  - policy.yaml
resources:
  - resources/good-pod.yaml
  - resources/bad-pod.yaml
results:
  - policy: require-resource-limits
    rule: check-resource-limits
    resource: good-pod
    result: pass
  - policy: require-resource-limits
    rule: check-resource-limits
    resource: bad-pod
    result: fail

kyverno test .                 # runs all tests in directory

# Check policy reports (what's currently failing in cluster):
kubectl get policyreport -A    # namespace-scoped results
kubectl get clusterpolicyreport   # cluster-scoped

# PolicyReport shows: which resources fail which rules (for background audit mode)

# Image signature verification with Cosign:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: verify-image-signature
spec:
  rules:
    - name: check-signature
      match:
        any:
          - resources: {kinds: [Pod]}
      verifyImages:
        - imageReferences: ["registry.example.com/my-app:*"]
          attestors:
            - entries:
                - keys:
                    publicKeys: |
                      -----BEGIN PUBLIC KEY-----
                      MFkwEwYH...
                      -----END PUBLIC KEY-----

# Dry-run a resource against policies:
kubectl apply --dry-run=server -f my-pod.yaml
# Kyverno webhook will return validation errors without creating the resource

Track Kyverno, Kubernetes, and policy tooling releases.
ReleaseRun monitors Kubernetes, Docker, and 13+ DevOps technologies.

Related: OPA & Gatekeeper Reference | Kubernetes RBAC Reference | Cilium Reference | Kubernetes EOL Tracker

🔍 Free tool: K8s YAML Security Linter — check the manifests Kyverno policies enforce against for baseline security misconfigurations.

Founded

2023 in London, UK

Contact

hello@releaserun.com