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