Introducing the CEL policy
Author:
Published:
Updated:
We are pleased to announce a new policy by the Kubewarden team: cel-policy.
This new policy uses the Common Expression Language (CEL). For those new to CEL, it is a general-purpose expression language designed to be fast, portable, and safe to execute. CEL as a language is memory-safe, side-effect free, terminating (as in “programs cannot loop forever”), and strong & dynamically typed.
CEL is a perfect candidate for extending the Kubernetes API, as CEL expressions can be easily inlined into CRD schemas, and compiled and type-checked “ahead-of-time” (when CRDs are created and updated). With Kubernetes 1.30, CEL features such as ValidatingAdmissionPolicies and other validation rules are now marked as stable.
cel-policy: What’s inside
For including CEL functionality, Kubernetes API server uses the upstream
cel-go. In addition, Kubernetes
also provides different CEL libraries that live in apiextensions-apiserver
and enrich the CEL experience. These range from standard functions and macros,
to supplemental functions for strings, lists, regex, URls, etcetera.
In Kubewarden, policies are Wasm modules. And in particular, we have WASI policies. Hence with all the pieces falling in place, it is only logical that we compile both the usptream CEL Go interpreter Go and the additional Kubernetes CEL libraries, and ship it as a Go WASI policy: cel-policy. You can find it as always in artifacthub.io.
A CEL superset, backwards-compatible
The new cel-policy
provides a new DSL approach to Kubewarden, and thanks to
reusing the exact same codebase, has backwards-compatibility for CEL Kubernetes
code such as the one used in ValidatingAdmissionPolicies
and matchConditions.
But this is not all. In addition, cel-policy
bundles a Kubewarden CEL extension library that exposes
Kubewarden’s host capabilities as native
CEL. This includes:
- Sigstore verification
- OCI interaction
- Cryptographic functions
- Network operations
- Access to Kubernetes resources
What does this mean for me?
As a Kubewarden policy user, you now have a new DSL that is backwards
compatible with CEL Kubernetes code. This policy doesn’t need to be compiled,
and can be used with different CEL code by instantiating it with different
spec.settings
.
And since it is a Kubewarden policy, we get all the Kubewarden features:
- Information about resources already in-cluster via Audit Scanner, and not only about CREATE/UPDATE/DELETE requests.
- Deployed as (Cluster)AdmissionPolicy, with PolicyServer segregations.
- Benefits from Kubewarden’s tracing and telemetry on policies.
- Can be developed and tested out-of-cluster thanks to kwctl.
- And more.
If you would like to see examples of Kubewarden-only functionality with the
cel-policy
, have a look at our docs.
Reusing a ValidatingAdmissionPolicy
An example is worth a thousand self-written YAML lines. Let’s reuse the following ValidatingAdmissionPolicy that checks for the amount of replicas in a Deployment:
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
name: "replicalimit-policy.example.com"
spec:
failurePolicy: Fail
matchConstraints: # (1)
resourceRules:
- apiGroups: ["apps"]
apiVersions: ["v1"]
operations: ["CREATE", "UPDATE"]
resources: ["deployments"]
variables: # (2)
- name: maxreplicas
expression: int(5)
validations: # (3)
- expression: "object.spec.replicas <= variables.maxreplicas"
messageExpression: "'the number of replicast must be less than or equal to ' + string(variables.maxreplicas)"
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicyBinding
metadata:
name: "replicalimit-binding-test.example.com"
spec:
policyName: "replicalimit-policy.example.com"
validationActions: [Deny]
matchResources:
namespaceSelector: # (4)
matchLabels:
environment: test
Let’s write an equivalent Kubewarden policy. You can notice that rules
(1), settings.variables
(2), settings.validations
(3), and
namespaceSelector
(4) are directly lifted and copy-pasted from the VAP
counterpart:
apiVersion: policies.kubewarden.io/v1
kind: ClusterAdmissionPolicy
metadata:
annotations:
io.kubewarden.policy.category: Resource validation
io.kubewarden.policy.severity: low
name: "cel-policy-replica-example"
spec:
module: registry://ghcr.io/kubewarden/policies/cel-policy:v1.0.0
failurePolicy: Fail
mode: protect
rules: # (1)
- apiGroups: ["apps"]
apiVersions: ["v1"]
operations: ["CREATE", "UPDATE"]
resources: ["deployments"]
settings:
variables: # (2)
- name: maxreplicas
expression: int(5)
validations: # (3)
- expression: "object.spec.replicas <= variables.maxreplicas"
messageExpression: "'the number of replicast must be less than or equal to ' + string(variables.maxreplicas)"
backgroundAudit: true
namespaceSelector: # (4)
matchLabels:
environment: test
To see a full-featured comparison, head to our docs.
Let’s stay in touch!
We hope you are as excited as we are about this new policy!
As always, we are curious about what features you would like next and how you are enjoying Kubewarden. Reach out on Slack or join our monthly community meeting to talk all things Kubewarden.