Skip to main content
In the previous lesson we learned how to write basic CEL expressions for Kyverno validation rules. In this installment we expand that foundation and demonstrate practical patterns that make CEL-based policies maintainable, configurable, and content-aware. Quick recap:
  • CEL is the standard language Kyverno uses for validation logic.
  • Common built-in variables include object, oldObject, namespaceObject, and request.
  • You can write validate.cel expressions to block or allow admission requests.
The image is a "Quick Recap" slide summarizing key points about CEL language in Kubernetes, including writing a basic rule and exploring core variables.

1) Use parameter resources (params) to separate policy logic from environment configuration

Hard-coding environment-specific values inside policy expressions makes policies brittle and operationally expensive. For example, this simple enforce rule restricts Deployment replicas to fewer than 4:
Problem: different environments (dev, staging, prod) often require different replica limits. With the hard-coded approach you must maintain multiple policy manifests or reapply changes each time limits change. Kyverno supports parameter resources plus the params variable so you can keep logic in the policy and supply environment-specific configuration separately. Refactor the previous rule to use a parameter resource:
Example parameter resource referenced by the policy:
Benefits:
  • Adjust deployment limits by editing a single parameter resource — policy manifests remain unchanged.
  • Use different parameter resources per namespace or environment and bind policies accordingly.
  • You can use native Kubernetes resources (for example, a ConfigMap) as the parameter resource as long as Kyverno can read it.
Parameter resources can be a custom resource or native types like ConfigMap. Kyverno exposes the selected resource to CEL via the params variable so your policy logic remains environment-agnostic.

2) Filter by content with CEL preconditions

match and exclude select resources by metadata (kinds, names, labels), but they are limited when you need to inspect nested fields. Use celPreconditions as a content-aware gate: they evaluate after match and before the main validate logic runs. Goal: enforce that any Service of type NodePort must set externalTrafficPolicy: Local.
How this flows:
  1. match selects all Service resources.
  2. celPreconditions evaluates; only Services with object.spec.type == 'NodePort' proceed to validation.
    • Services that are ClusterIP or LoadBalancer will skip the rule entirely (no error).
  3. validate.cel runs for resources that pass preconditions and enforces the required field.
This lets you write concise validation expressions and avoid applying rules to irrelevant resources.
The image is a slide titled "Fine-Grained Matching: CEL Preconditions" with a goal stating that for service resources of type NodePort, the externalTrafficPolicy should be enforced as Local.

3) Reduce repetition with variables to build reusable expressions

Complex policies often need to aggregate fields like all containers in a Pod spec (containers, initContainers, ephemeralContainers). Repeating the same aggregation in multiple expressions makes rules verbose and error-prone. Example (repetitive, hard to read):
Solution: define the aggregation once with variables and reference it in expressions. This improves readability and maintainability.
The image explains the concept of a 'variables' block, which helps define an expression once and give it a name, enhancing readability, reusability, and maintainability. It includes text from KodeKloud.
Refactored using variables:
Advantages:
  • Single source of truth for the container aggregation logic.
  • Validation expressions become concise and self-documenting.
  • Changes (e.g., include/exclude ephemeral containers) require a single edit in variables.

Quick reference: common CEL/Kyverno built-ins

Summary — Patterns to make CEL policies robust and maintainable

The image is a summary of key concepts related to Kubernetes validation using Kyverno, including details about validate.cel, core variables, parameters, and preconditions, presented with a colorful numbered design.
Helpful links and references
When using paramKind with custom resources, ensure the referenced resource exists and Kyverno has permission to read it. A missing or inaccessible parameter resource will prevent the policy from evaluating as intended.
That’s it for this lesson — with params, celPreconditions, and variables you can author Kyverno CEL policies that are configurable, precise, and easy to maintain.

Watch Video

Practice Lab