Write constraints for OPA gatekeeper

Kubernetes OPA gatekeeper custom rule

3 min read | by Jordi Prats

Once we have OPA gatekeeper installed we might want to start writing our own rules if we cannot find it in the gatekeeper library.

To create a custom rule we'll have to create a ConstraintTemplate that will contain the relevant rego code and an instance of it to really start using it.

Browsing the gatekeeper library can be a great source of inspiration, even if the rules it contains doesn't do what you need you can still find code that can be adapted to do what you need:

The following code is making sure a Pod uses a set of tags:

 violation[{"msg": msg, "details": {"missing_labels": missing}}] {  provided := {label | input.review.object.metadata.labels[label]}  required := {label | label := input.parameters.labels[_].key}  missing := required - provided  count(missing) > 0  def_msg := sprintf("you must provide labels: %v", [missing])  msg := get_message(input.parameters, def_msg)  } 

If what we need is to disallow some tolerations, we can change it's logic to fit our needs:

 violation[{"msg": msg, "details": {"restricted annotations": "found"}}] {  provided := {toleration_in | toleration_in := input.review.object.spec.tolerations[_].key}  excluded := {toleration_ex | toleration_ex := input.parameters.tolerations[_].key}  diff := provided - excluded  count(provided) != count(diff)  msg := "found restricted toleration(s)"  } 

Having the code we just need to insert it on a ConstraintTemplate object with the proper openAPIV3Schema to hold the tolerations we want to restrict:

apiVersion: templates.gatekeeper.sh/v1 kind: ConstraintTemplate metadata:  name: restricttolerations spec:  crd:  spec:  names:  kind: RestrictTolerations  validation:  openAPIV3Schema:  type: object  properties:  message:  type: string  tolerations:  type: array  description: A list of tolerations to deny  items:  type: object  properties:  key:  type: string  description: Toleration key  targets:  - target: admission.k8s.gatekeeper.sh  rego: |  package restricttolerations   violation[{"msg": msg, "details": {"restricted annotations": "found"}}] {  provided := {toleration_in | toleration_in := input.review.object.spec.tolerations[_].key}  excluded := {toleration_ex | toleration_ex := input.parameters.tolerations[_].key}  diff := provided - excluded  count(provided) != count(diff)  msg := "found restricted toleration(s)"  } 

Once we have this object available we'll be able to create instances of it configuring it:

apiVersion: constraints.gatekeeper.sh/v1beta1 kind: RestrictTolerations metadata:  name: restrict-tolerations  annotations:  "helm.sh/hook": "post-install,post-upgrade"  "helm.sh/hook-delete-policy": "before-hook-creation"  "helm.sh/hook-weight": "1" spec:  enforcementAction: deny  match:  kinds:  - apiGroups: [""]  kinds: ["Pod"]  parameters:  tolerations:  - key: node-role.kubernetes.io/demo  - key: node-role.kubernetes.io/another  - key: node-role.kubernetes.io/yetanother 

We can now try creating a Pod with one of the disallowed tolerations

apiVersion: v1 kind: Pod metadata:  name: pod-tolerations-test spec:  containers:  - name: nginx  image: nginx  tolerations:  - key: "node-role.kubernetes.io/demo"  operator: "Equal"  value: "whatever"  effect: "NoSchedule" 

When trying to apply this Pod definition, we'll get an error from the gatekeeper's admission webhook disallowing the creation of this Pod:

$ kubectl apply -f testPod.yaml Error from server (Forbidden): error when creating "testPod.yaml": admission webhook "validation.gatekeeper.sh" denied the request: [restrict-tolerations] found restricted toleration(s) 

Posted on 01/11/2022