Building an HTTP Validator Webhook for Kubernetes using Python

Matías Salinas
3 min readMar 14, 2023

--

Introduction

A validator webhook in Kubernetes is an HTTP callback that intercepts admission requests and can either allow or reject them based on custom logic. Now we will see how to build a validator webhook for Kubernetes using Python and Flask over HTTP. This webhook will validate that container images in new deployments start with the prefix “msalinasc_” (excluding the registry URL). We will cover the deployment of the webhook, creation of the Kubernetes Service, and implementation of the ValidatingWebhookConfiguration resource.

Prerequisites

To follow along with this tutorial, you should have:

  1. Basic knowledge of Kubernetes, Python, and Flask
  2. A running Kubernetes cluster with kubectl configured
  3. Python 3 installed on your local machine

Step 1: Implement the validator webhook using Flask

First, create a new Python script, validator_webhook.py, and add the following code:

from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route("/validate", methods=["POST"])
def validate():
request_data = request.get_json()
# Extract the container image name from the request data
container_image = request_data["request"]["object"]["spec"]["template"]["spec"]["containers"][0]["image"]
# Extract the image name without the registry URL
image_name = container_image.split("/")[-1]
# Check if the image name starts with "msalinasc_"
if image_name.startswith("msalinasc_"):
return jsonify({"response": {"allowed": True}})
else:
return jsonify({"response": {"allowed": False, "status": {"message": "Invalid image name"}}})
if __name__ == "__main__":
app.run(host="0.0.0.0", port=80)

Step 2: Create a Dockerfile for the webhook

Create a Dockerfile in the same directory as your validator_webhook.py script with the following content:

FROM python:3.9

WORKDIR /app

COPY requirements.txt .

RUN pip install --no-cache-dir -r requirements.txt

COPY validator_webhook.py .

CMD ["python", "/app/validator_webhook.py"]

Create a requirements.txt file that includes the required libraries:

flask==2.1.1

Step 3: Build and push the Docker image

Build the Docker image and push it to a container registry accessible by your Kubernetes cluster:

$ docker build -t <your-registry>/<your-repo>/validator-webhook:v1 .
$ docker push <your-registry>/<your-repo>/validator-webhook:v1

Step 4: Deploy the webhook as a Kubernetes Deployment

Create a new YAML file, validator-webhook-deployment.yaml, with the following content:

apiVersion: apps/v1
kind: Deployment
metadata:
name: validator-webhook
spec:
replicas: 1
selector:
matchLabels:
app: validator-webhook
template:
metadata:
labels:
app: validator-webhook
spec:
containers:
- name: validator-webhook
image: <your-registry>/<your-repo>/validator-webhook:v1
imagePullPolicy: Always
ports:
- containerPort: 80
name: webhook

Replace <your-registry> and <your-repo> with the appropriate values for your container registry. Apply the deployment to your cluster:

$ kubectl apply -f validator-webhook-deployment.yaml

Step 5: Create a Kubernetes Service for the webhook

Create a new YAML file, validator-webhook-service.yaml, with the following content:

apiVersion: v1
kind: Service
metadata:
name: validator-webhook-service
spec:
selector:
app: validator-webhook
ports:
- protocol: TCP
port: 80
targetPort: 80
type: ClusterIP

Apply the Service to your cluster:

$ kubectl apply -f validator-webhook-service.yaml

Step 6: Create the ValidatingWebhookConfiguration resource

Create a new YAML file, validator-webhook-config.yaml, with the following content:

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
name: validator-webhook-config
webhooks:
- name: validator-webhook.default.svc
clientConfig:
service:
name: validator-webhook-service
namespace: default
path: "/validate"
rules:
- operations: ["CREATE", "UPDATE"]
apiGroups: ["apps"]
apiVersions: ["v1"]
resources: ["deployments"]
admissionReviewVersions: ["v1"]
sideEffects: None
timeoutSeconds: 5
failurePolicy: Fail

Apply the configuration to your cluster:

$ kubectl apply -f validator-webhook-config.yaml

If the rule defined in the ValidatingWebhookConfiguration is not met, the user will receive an error message when trying to create or update a deployment. In our specific case, the error message returned is defined in the validator webhook code:

return jsonify({"response": {"allowed": False, "status": {"message": "Invalid image name"}}})

The error message would appear as follows:

Error from server (Invalid image name): error when creating "deployment.yaml": admission webhook "validator-webhook.default.svc" denied the request: Invalid image name

This message informs the user that the deployment request was denied by the admission webhook due to an invalid image name, and they should use a properly named image according to the defined rule in the webhook.

--

--

Matías Salinas
Matías Salinas

No responses yet