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