Understanding Kyverno and Common Expression Language (CEL)

Yes, you have set up a platform on top of Kubernetes cluster and given appropriate access to your developers to deploy their apps. Cool! but now you face issues from a resources, security and maintenance point of view because your developers deploy them as they wish without following any set of rules, even if you have the rules, you are at their mercy to follow them.

To avoid this issue, Kyverno to the rescue. It is a policy engine that allows you to write policies to validate, generate and mutate Kubernetes workloads. It acts as an intermediary to check if the admitting resource is compliant with the policies or not.

Let us take a simple problem of pod definitions not having resource requests and limits set. This can cause problems in terms of pod eating up all the resources if it has bad code in it. So I will create a Kyverno policy to reject all such pods which does not have resources specified in pod definition file.

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-requests-limits
  annotations:
    policies.kyverno.io/title: Require Limits and Requests
    policies.kyverno.io/category: Best Practices, EKS Best Practices
    policies.kyverno.io/severity: medium
    policies.kyverno.io/subject: Pod
    policies.kyverno.io/minversion: 1.6.0
    policies.kyverno.io/description: >-
      As application workloads share cluster resources, it is important to limit resources
      requested and consumed by each Pod. It is recommended to require resource requests and
      limits per Pod, especially for memory and CPU. If a Namespace level request or limit is specified,
      defaults will automatically be applied to each Pod based on the LimitRange configuration.
      This policy validates that all containers have something specified for memory and CPU
      requests and memory limits.      
spec:
  validationFailureAction: audit
  background: true
  rules:
  - name: validate-resources
    match:
      any:
      - resources:
          kinds:
          - Pod
    validate:
      message: "CPU and memory resource requests and limits are required."
      pattern:
        spec:
          containers:
          - resources:
              requests:
              limits:
                memory: "?*"

This is how you create a Kyverno policy to check if the pod definition file have resource limits. But there are some scenarios where your policy spans 100's of lines due to complex conditionals.

CEL to the rescue

CEL is a light weight language created by Google for expression evaluation. This is a perfect fit for the Kubernetes validation because of its speed. By using CEL with Kyverno gives you a simpler policy definition file which is readable and universally similar. To rewrite the same policy as above I can write like

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-requests-limits  
spec:
  validationFailureAction: audit
  background: true
  rules:
  - name: validate-resources
    match:
      any:
      - resources:
          kinds:
          - Pod
    validate:
      cel:
        expressions:
          - message: "CPU and memory limits must have a value"
            expression: "object.spec.containers.all(container, has(container.resources.limits.cpu) && has(container.resources.limits.memory))"

Here are some of more policies from Kyverno blog

Conclusion

CEL can be an excellent way to write policies, there maybe an use-case where you can keep seperate source-code for CEL expressions and can create policies dynamically as per cluster-type(like test and prod) using automation.

Did you find this article valuable?

Support Srujan Reddy by becoming a sponsor. Any amount is appreciated!