Building your own Kubernetes webhook
This blog is the 2nd part of a blog post on how to write custom logic for your kubernetes objects. The first post can be found here https://gauravsarma1992.medium.com/kubernetes-operators-using-kubebuilder-7db99559120c which covers the approach to building your own kubernetes controller using Golang.
In this post, we will cover the best approach to write your own kubernetes webhooks. Webhooks are usually interceptors which can be used in 2 ways here:
- Mutating — Changing the payload before the custom object is created
- Validating — Ensuring the payload is proper, if it’s not, the CRD can be prevent from being created
In this post, we will be covering only Validating Webhooks.
The logic for the webhook will be very simple. If the task
is set to True by default, we will reject the request.
Use kubebuilder, let’s scaffold the webhook logic.
kubebuilder create webhook –group todo –version v1 –kind TodoList –programmatic-validation
Modify the required files by uncommenting the parts for enabling the validating webhooks.
config/crd/kustomization.yaml
resources:
\- bases/todo.sarmag.co\_todolists.yaml
#+kubebuilder:scaffold:crdkustomizeresource
patchesStrategicMerge:
\# \[WEBHOOK\] To enable webhook, uncomment all the sections with \[WEBHOOK\] prefix.
\# patches here are for enabling the conversion webhook for each CRD
\- patches/webhook\_in\_todolists.yaml
#+kubebuilder:scaffold:crdkustomizewebhookpatch
\# \[CERTMANAGER\] To enable cert-manager, uncomment all the sections with \[CERTMANAGER\] prefix.
\# patches here are for enabling the CA injection for each CRD
\- patches/cainjection\_in\_todolists.yaml
#+kubebuilder:scaffold:crdkustomizecainjectionpatch
\# the following config is for teaching kustomize how to do kustomization for CRDs.
configurations:
\- kustomizeconfig.yaml
**_config/default/kustomization.yaml_**
namespace: custom-k8-controller-system
namePrefix: custom-k8-controller-
bases:
\- ../crd
\- ../rbac
\- ../manager
\# \[WEBHOOK\] To enable webhook, uncomment all the sections with \[WEBHOOK\] prefix including the one in
\# crd/kustomization.yaml
\- ../webhook
\# \[CERTMANAGER\] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. 'WEBHOOK' components are required.
\- ../certmanager
\# \[PROMETHEUS\] To enable prometheus monitor, uncomment all sections with 'PROMETHEUS'.
#- ../prometheus
patchesStrategicMerge:
\# Protect the /metrics endpoint by putting it behind auth.
\# If you want your controller-manager to expose the /metrics
\# endpoint w/o any authn/z, please comment the following line.
\- manager\_auth\_proxy\_patch.yaml
\# Mount the controller config file for loading manager configurations
\# through a ComponentConfig type
#- manager\_config\_patch.yaml
\# \[WEBHOOK\] To enable webhook, uncomment all the sections with \[WEBHOOK\] prefix including the one in
\# crd/kustomization.yaml
\- manager\_webhook\_patch.yaml
\# \[CERTMANAGER\] To enable cert-manager, uncomment all sections with 'CERTMANAGER'.
\# Uncomment 'CERTMANAGER' sections in crd/kustomization.yaml to enable the CA injection in the admission webhooks.
\# 'CERTMANAGER' needs to be enabled to use ca injection
\- webhookcainjection\_patch.yaml
\# the following config is for teaching kustomize how to do var substitution
vars:
\# \[CERTMANAGER\] To enable cert-manager, uncomment all sections with 'CERTMANAGER' prefix.
\- name: CERTIFICATE\_NAMESPACE \# namespace of the certificate CR
objref:
kind: Certificate
group: cert-manager.io
version: v1
name: serving-cert \# this name should match the one in certificate.yaml
fieldref:
fieldpath: metadata.namespace
\- name: CERTIFICATE\_NAME
objref:
kind: Certificate
group: cert-manager.io
version: v1
name: serving-cert \# this name should match the one in certificate.yaml
\- name: SERVICE\_NAMESPACE \# namespace of the service
objref:
kind: Service
version: v1
name: webhook-service
fieldref:
fieldpath: metadata.namespace
\- name: SERVICE\_NAME
objref:
kind: Service
version: v1
name: webhook-service
Modify the ValidateCreate
method in todolist_webhook.go
code
// ValidateCreate implements webhook.Validator so a webhook will be registered for the type
func (r \*TodoList) ValidateCreate() error {
todolistlog.Info("validate create", "name", r.Name)
if r.Spec.Task == "" {
err := errors.New("task cannot be empty")
return err
}
return nil
}
Once this is done, build the docker image, load it on the k8s cluster and then deploy it.
make docker-build IMG=gsarma/k8s-operators:v1
kind load docker-image gsarma/k8s-operators:v1 --name k8s-operators
make deploy IMG=gsarma/k8s-operators:v1
All that’s left is to create a todolist object with an empty task
and it should fail the request.
apiVersion: todo.sarmag.co/v1
kind: TodoList
metadata:
name: jack
namespace: operator-namespace
spec:
task: ""
Enjoy reading and implementing your own custom kubernetes webhook!!
I hope you liked the article. Please let me know if you have any queries regarding the article. Happy reading!!