Gatekeeper vs Kyverno

Jul 21, 2023·

5 min read

Gatekeeper is a general-purpose policy engine based on Open Policy Agent (OPA). It allows you to define and enforce custom policies across various Kubernetes resources.

Kyverno is specifically designed for Kubernetes policy management. It focuses on validating and mutating resources in Kubernetes to enforce desired configurations and security policies.

Small Comparison of both tools that gives you a clear picture,

GatekeeperKyverno
It acts as an admission controller which means it evaluates policies during the admission of resourcesIt is built using Custom Resource Definitions (CRDs) and operates as a validating and mutating webhook.
It uses the powerful Rego language, part of the OPA project, for defining policiesIt uses a YAML or JSON-based declarative policy language that is easier to read and write for many users
Users should have prior knowledge to understand and write rego policiesUsers are familiar with Kubernetes YAML or JSON which makes it easier to write policies
It does not provide built-in policies out of the box, but there are community-contributed policies available to get startedKyverno comes with a set of built-in policies and examples that cover common use cases
It is more extensible and can be used to enforce policy beyond Kubernetes since it’s general-purpose natureIts primary focus is Kubernetes, making it highly optimised for handling Kubernetes resources and scenarios

Key Points that you don’t miss!!

  • Gatekeeper is a general-purpose open policy agent whereas Kyverno is specifically designed for Kubernetes

  • Gatekeeper supports only validating webhooks but Kyverno supports validating, mutating, generating and image verification webhooks

  • Gatekeeper makes you feel complex for writing a simple policy but Kyverno is easier to implement

  • Some complex requirement to write custom policies in Kyverno is difficult where rego plays in the background of the OPA gatekeeper makes possible to solve those requirements

  • Kyverno is a straightforward method for the implementation of policies but in the case of gatekeeper we need to create the CRDs like templates and constraints

Implementation of Gatekeeper

  1. Installation: Gatekeeper supports three methods of installation.

    1. Install using releases to deploy:

       kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper/master/deploy/gatekeeper.yaml
      
    2. Deploy using Helm:

       helm repo add gatekeeper https://open-policy-agent.github.io/gatekeeper/charts
       helm install gatekeeper/gatekeeper --name-template=gatekeeper --namespace gatekeeper-system --create-namespace
      
    3. Deploy HEAD using make:

       git clone https://github.com/open-policy-agent/gatekeeper.git
       export DESTINATION_GATEKEEPER_IMAGE=<add registry like "myregistry.docker.io/gatekeeper">
       make docker-buildx REPOSITORY=$DESTINATION_GATEKEEPER_DOCKER_IMAGE OUTPUT_TYPE=type=registry
       make deploy REPOSITORY=$DESTINATION_GATEKEEPER_DOCKER_IMAGE
      
  2. After successful installation, you can create templates and constraints to implement the policies. Here we are trying to restrict Deployment if the deployment is not having the label “app”. If the specified label is not present it should not be allowed to deploy.

    1. Create a template.yaml file and paste this YAML and apply the file

       apiVersion: templates.gatekeeper.sh/v1beta1
       kind: ConstraintTemplate
       metadata:
         name: kubernetesvalidatinglabel
       spec:
         crd:
           spec:
             names:
               kind: KubernetesValidatingLabel
         targets:
           - target: admission.k8s.gatekeeper.sh
             rego: |
               package kubernetes.validating.labels
               import future.keywords.contains
               import future.keywords.if
               import future.keywords.in
               violation[{"msg": msg, "details": {"missing_labels": missing}}] {
                 provided := {label | input.review.object.metadata.labels[label]}
                 required := {label | label := input.parameters.labels[_]}
                 missing := required - provided
                 count(missing) > 0
                 msg := sprintf("you must provide labels: %v", [missing])
               }
      
    2. Create a constraint.yaml file and paste this YAML and apply the file

       apiVersion: constraints.gatekeeper.sh/v1beta1
       kind: KubernetesValidatingLabel
       metadata:
         name: require-deployment-labels
       spec:
         match:
           kinds:
             - apiGroups:
               kinds:
                 - Deployment
         parameters:
           labels:
             - app
      

      After successfully applying the template and constraints we will try to create a deployment without the label app such that we can see the error message.

       apiVersion: apps/v1
       kind: Deployment
       metadata:
         name: nginx-deployment
         labels:
           test: prod
       spec:
         replicas: 2
         selector:
           matchLabels:
             test: prod
         template:
           metadata:
             labels:
               test: prod
           spec:
             containers:
             - name: nginx-container
               image: nginx
               ports:
               - containerPort: 80
      

      While applying this YAML you will get a message like this

       Error from server (Forbidden): error when creating "deploy.yaml": admission webhook "validation.gatekeeper.sh" denied the request: [require-deployment-labels]
       [require-deployment-labels] you must provide labels: {"app"}
      

Implementation of Kyverno

  1. Installation:

    1. Installation using Helm:

       helm repo add kyverno https://kyverno.github.io/kyverno/
       helm install kyverno-policies kyverno/kyverno-policies -n kyverno -- create-namespace
      
    2. Install using YAMLs:

       kubectl create -f https://github.com/kyverno/kyverno/releases/download/v1.10.0/install.yaml
      
    3. Testing unreleased code:

       kubectl create -f https://github.com/kyverno/kyverno/raw/main/config/install-latest-testing.yaml
      
  2. Here, you can directly create policies using the YAML files. We will create a cluster policy using Kyverno’s CRDs

     apiVersion: kyverno.io/v1
     # The `ClusterPolicy` kind applies to the entire cluster.
     kind: ClusterPolicy
     metadata:
       name: require-ns-purpose-label
     # The `spec` defines properties of the policy.
     spec:
       # The `validationFailureAction` tells Kyverno if the resource being validated should be allowed but reported (`Audit`) or blocked (`Enforce`).
       validationFailureAction: Enforce
       # The `rules` is one or more rules which must be true.
       rules:
       - name: require-ns-purpose-label
         # The `match` statement sets the scope of what will be checked. In this case, it is any `Namespace` resource.
         match:
           any:
           - resources:
               kinds:
               - Namespace
         # The `validate` statement tries to positively check what is defined. If the statement, when compared with the requested resource, is true, it is allowed. If false, it is blocked.
         validate:
           # The `message` is what gets displayed to a user if this rule fails validation.
           message: "You must have label `purpose` with value `production` set on all new namespaces."
           # The `pattern` object defines what pattern will be checked in the resource. In this case, it is looking for `metadata.labels` with `purpose=production`.
           pattern:
             metadata:
               labels:
                 app: test
    

    We are using only one file to apply the policies rather than creating templates and constraints in the gatekeeper.

    After applying this policy try to create the same deployment using the deployment file and you will get the error message like this.

     Error from server: error when creating "deploy.yaml": admission webhook "validate.kyverno.svc-fail" denied the request: 
     resource Deployment/default/nginx-deployment was blocked due to the following policies 
     require-ns-purpose-label:
       require-ns-purpose-label: 'validation error: You must have label `purpose` with
         value `production` set on all new namespaces. rule require-ns-purpose-label failed
         at path /metadata/labels/jk/'
    

    If you want to pass the deployment then you should add the label “app” in the metadata of your deployment file.

Summary

I hope now you have a good understanding of Gatekeeper and Kyverno and how it’s working.

As of my understanding for simple and general usage of policies we can go with Kyverno if you need some complex security policies to be implemented in your k8s then you can use Gatekeeper. Both Gatekeeper and Kyverno have their pros and cons, you can use any one of the tools based on your requirement.

Author: Jayakumar S