E-NO
Kubernetes 8 min de lecture

Webhooks d'admission Kubernetes : configuration d'un laboratoire local avec des exemples pratiques

calendar_today Publié : 2026-10-22
update Dernière mise à jour : 2026-10-22
analytics Efficacité SEO : 100%
Illustration du guide technique pour « Webhooks d'admission Kubernetes : configuration d'un laboratoire local avec des exemples pratiques ».

Introduction

Les webhooks d'admission Kubernetes sont des points d'extension puissants qui permettent de valider ou de muter les ressources avant leur persistance. Cependant, les tester directement sur un cluster partagé est risqué : un webhook mal configuré peut bloquer les déploiements, provoquer des défaillances en cascade, voire rendre le cluster partiellement inopérant. Un environnement de laboratoire local offre un bac à sable sûr et reproductible pour expérimenter la logique des webhooks, comprendre les modes de défaillance et gagner en confiance avant une mise en production.

Dans ce guide, nous allons configurer un laboratoire local à l'aide d'outils légers comme kind ou minikube, créer un webhook d'admission de validation et un webhook de mutation avec des exemples pratiques, vérifier leur comportement et couvrir les étapes de récupération. En suivant ce guide, vous disposerez d'un environnement pleinement fonctionnel pour développer et tester des webhooks d'admission sans risquer l'infrastructure partagée.

Une configuration claire réduit les retouches en séparant les étapes : préparation de l'environnement, gestion des certificats, déploiement du webhook et tests. Nous commencerons par un exemple restreint et mesurable pour que chaque étape soit observable.

Inventaire des versions et de l'environnement

Avant de commencer, confirmez les versions et les outils que vous utiliserez. Pour ce guide, nous supposons ce qui suit :

ComposantVersionRôle
Kubernetesv1.27+Serveur d'API du cluster local
kindv0.20.0+Cluster local léger
ou minikubev1.31.0+Cluster local alternatif
OpenSSL3.0+Génération de certificats TLS
Go1.20+Écriture du serveur webhook
curltoute version récenteTester les points de terminaison du webhook

Prérequis :

  • Une machine avec au moins 2 CPU et 4 Go de RAM disponibles.
  • Docker ou un conteneur runtime pris en charge par kind/minikube.
  • Une familiarité de base avec les manifestes Kubernetes et les outils en ligne de commande.

Topologie : Nous allons créer un cluster à nœud unique où le serveur d'API s'exécute dans un conteneur (kind) ou une machine virtuelle (minikube). Le serveur webhook sera déployé sous forme de pod dans le même cluster et exposé via un service. Le serveur d'API appellera le webhook en HTTPS à l'aide d'un certificat auto-signé.

Assurez-vous que votre cluster local est opérationnel :

kind create cluster --name webhook-lab

Sortie attendue :

Creating cluster "webhook-lab" ...
 ✓ Ensuring node image (kindest/node: v1.27.3) 🖼
 ✓ Preparing nodes 📦
 ✓ Writing configuration 📜
 ✓ Starting control-plane 🕹️
 ✓ Installing CNI 🔌
 ✓ Installing StorageClass 💾
Set kubectl context to "kind-webhook-lab"

Si vous utilisez minikube :

minikube start --driver=docker --kubernetes-version=v1.27.3

Vérifiez l'accès au cluster :

kubectl cluster-info

Question rapide 1 sur 2

Selon l'article, pourquoi est-il risqué de tester les webhooks d'admission directement sur un cluster partagé ?

L'introduction indique qu'un webhook mal configuré peut bloquer les déploiements, provoquer des défaillances en cascade, voire rendre le cluster partiellement inopérant, ce qui explique la recommandation d'un laboratoire local.

Chemin de configuration sécurisé

Nous allons maintenant implémenter deux webhooks : un webhook de mutation qui ajoute une étiquette à chaque pod, et un webhook de validation qui rejette les pods avec une valeur d'étiquette spécifique. Cette approche ciblée nous permet de vérifier chaque élément indépendamment.

Étape 1 : Générer les certificats TLS

Le serveur d'API doit faire confiance au serveur webhook. Comme nous sommes dans un laboratoire, nous pouvons utiliser une autorité de certification auto-signée et émettre un certificat de serveur. La configuration du webhook spécifiera le bundle de l'autorité de certification. Exécutez ces commandes pour générer les certificats (en utilisant un répertoire temporaire) :

mkdir -p /tmp/webhook-certs && cd /tmp/webhook-certs

# Générer la clé et le certificat de l'autorité de certification
openssl genrsa -out ca.key 2048
openssl req -x509 -new -nodes -key ca.key -subj "/CN=webhook-ca" -days 365 -out ca.crt

# Générer la clé du serveur et la CSR (demande de signature de certificat)
openssl genrsa -out server.key 2048
openssl req -new -key server.key -subj "/CN=webhook-server.default.svc" -out server.csr

# Signer le certificat du serveur avec notre autorité de certification
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 365

Le CN du certificat doit correspondre au nom DNS du service : webhook-server.default.svc.

Créez un secret Kubernetes avec le certificat et la clé du serveur :

kubectl create secret tls webhook-server-cert --cert=server.crt --key=server.key

Vous aurez également besoin du certificat de l'autorité de certification encodé en base64 pour la configuration du webhook. Nous l'utiliserons lors de la création de la configuration du webhook.

Étape 2 : Déployer le serveur webhook

Créez un serveur HTTP simple qui répond aux demandes d'examen d'admission. Voici un exemple en Go. Enregistrez-le sous le nom main.go :

package main

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "net/http"
    "crypto/tls"

    admissionv1 "k8s.io/api/admission/v1"
    corev1 "k8s.io/api/core/v1"
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func mutatePods(w http.ResponseWriter, r *http.Request) {
    var admissionReview admissionv1.AdmissionReview
    body, _ := ioutil.ReadAll(r.Body)
    if err := json.Unmarshal(body, &admissionReview); err != nil {
        http.Error(w, "could not parse admission review", http.StatusBadRequest)
        return
    }

    // Construire le patch pour ajouter une étiquette
    patchType := admissionv1.PatchTypeJSONPatch
    pod := corev1.Pod{}
    if err := json.Unmarshal(admissionReview.Request.Object.Raw, &pod); err != nil {
        http.Error(w, "could not unmarshal pod", http.StatusBadRequest)
        return
    }

    // Si les étiquettes sont nil, créer une carte vide
    if pod.Labels == nil {
        pod.Labels = map[string]string{}
    }
    pod.Labels["webhook-lab"] = "mutated"

    // Créer le patch
    patch := []map[string]interface{}{
        {"op": "add", "path": "/metadata/labels/webhook-lab", "value": "mutated"},
    }
    patchBytes, _ := json.Marshal(patch)

    admissionResponse := &admissionv1.AdmissionResponse{
        UID:       admissionReview.Request.UID,
        Allowed:   true,
        PatchType: &patchType,
        Patch:     patchBytes,
    }

    response := admissionv1.AdmissionReview{
        TypeMeta: metav1.TypeMeta{
            APIVersion: "admission.k8s.io/v1",
            Kind:       "AdmissionReview",
        },
        Response: admissionResponse,
    }
    respBytes, _ := json.Marshal(response)
    w.Header().Set("Content-Type", "application/json")
    w.Write(respBytes)
}

func main() {
    http.HandleFunc("/mutate", mutatePods)
    server := &http.Server{
        Addr: ":8443",
        TLSConfig: &tls.Config{
            Certificates: []tls.Certificate{loadX509KeyPair("/etc/webhook/certs/tls.crt", "/etc/webhook/certs/tls.key")},
        },
    }
    fmt.Println("Starting webhook server on :8443")
    server.ListenAndServeTLS("", "")
}

func loadX509KeyPair(certFile, keyFile string) tls.Certificate {
    cert, err := tls.LoadX509KeyPair(certFile, keyFile)
    if err != nil {
        panic(err)
    }
    return cert
}

Construisez l'image Docker et chargez-la dans kind :

docker build -t webhook-server:latest .
kind load docker-image webhook-server:latest --name webhook-lab

Créez un déploiement et un service :

# webhook-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: webhook-server
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: webhook-server
  template:
    metadata:
      labels:
        app: webhook-server
    spec:
      containers:
      - name: server
        image: webhook-server:latest
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8443
        volumeMounts:
        - name: certs
          mountPath: /etc/webhook/certs
          readOnly: true
      volumes:
      - name: certs
        secret:
          secretName: webhook-server-cert
# webhook-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: webhook-server
  namespace: default
spec:
  selector:
    app: webhook-server
  ports:
  - port: 443
    targetPort: 8443

Appliquez :

kubectl apply -f webhook-deployment.yaml
kubectl apply -f webhook-service.yaml

Vérifiez que le pod est en cours d'exécution :

kubectl get pods -l app=webhook-server

Sortie attendue :

NAME                            READY   STATUS    RESTARTS   AGE
webhook-server-79c4f4c9b7-9x2kq 1/1     Running   0          5s

Étape 3 : Créer la MutatingWebhookConfiguration

Créez une configuration qui indique au serveur d'API d'appeler notre webhook lors de la création de pods. Remplacez CA_BUNDLE par le base64 de ca.crt :

CA_BUNDLE=$(cat /tmp/webhook-certs/ca.crt | base64 | tr -d '\n')
# mutating-webhook.yaml
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
  name: pod-mutator
webhooks:
- name: pod-mutator.default.svc
  clientConfig:
    service:
      name: webhook-server
      namespace: default
      path: "/mutate"
      port: 443
    caBundle: ${CA_BUNDLE}
  rules:
  - operations: ["CREATE"]
    apiGroups: [""]
    apiVersions: ["v1"]
    resources: ["pods"]
  admissionReviewVersions: ["v1"]
  sideEffects: None
  failurePolicy: Fail

Appliquez :

envsubst < mutating-webhook.yaml | kubectl apply -f -

Étape 4 : Tester le webhook de mutation

Créez un pod simple :

kubectl run test-pod --image=nginx

Vérifiez les étiquettes :

kubectl get pod test-pod --show-labels

La sortie attendue inclut webhook-lab=mutated.

Étape 5 : Ajouter un webhook de validation

Ajoutez maintenant un webhook de validation qui rejette les pods si l'étiquette webhook-lab est définie sur mutated (pour démontrer le refus). Vous pouvez étendre le serveur ou en créer un séparé. Par souci de concision, supposez un serveur similaire avec un point de terminaison /validate. La configuration :

# validating-webhook.yaml
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
  name: pod-validator
webhooks:
- name: pod-validator.default.svc
  clientConfig:
    service:
      name: webhook-server
      namespace: default
      path: "/validate"
      port: 443
    caBundle: ${CA_BUNDLE}
  rules:
  - operations: ["CREATE"]
    apiGroups: [""]
    apiVersions: ["v1"]
    resources: ["pods"]
  admissionReviewVersions: ["v1"]
  sideEffects: None
  failurePolicy: Fail

Appliquez et testez : la création du pod doit être refusée avec un message.

Vérification et diagnostics

Pour vérifier que les webhooks fonctionnent correctement, effectuez ces contrôles :

  • Vérifiez que les configurations de webhook existent :
kubectl get mutatingwebhookconfigurations, validatingwebhookconfigurations
  • Inspectez les journaux du webhook :
kubectl logs deployment/webhook-server

Vous devriez voir les demandes d'examen d'admission entrantes.

  • Utilisez kubectl apply --dry-run=server pour voir si le webhook est appelé sans persister l'objet.
  • Testez avec un dry-run :
kubectl run test-pod --image=nginx --dry-run=server
  • Utilisez kubectl describe sur la configuration du webhook pour voir le bundle CA et les règles.

Si le webhook n'est pas appelé, vérifiez les journaux du serveur d'API (pour kind, voir les journaux du conteneur) pour des messages d'erreur comme x509: certificate signed by unknown authority ou connection refused.

Modes de défaillance et récupération

Les webhooks d'admission peuvent causer des problèmes. Modes de défaillance courants :

  • Serveur webhook indisponible : Si failurePolicy est Fail, toutes les requêtes correspondantes seront rejetées. Pour récupérer, vous pouvez soit supprimer la configuration du webhook, soit mettre à l'échelle le déploiement pour restaurer la disponibilité. Si le serveur d'API ne peut pas être joint pour supprimer le webhook (peu probable mais possible), vous devrez peut-être modifier le manifeste du serveur d'API pour désactiver les plugins d'admission.
  • Bundle CA incorrect : Le serveur d'API rejettera l'appel du webhook, et avec failurePolicy: Fail, la création de ressources échouera. Corrigez le bundle CA dans la configuration du webhook.
  • Délai d'attente : Si le serveur webhook ne répond pas dans le délai imparti (10 secondes par défaut), le serveur d'API appliquera la politique d'échec.

Étapes de récupération :

# Désactiver temporairement le webhook en supprimant sa configuration
kubectl delete mutatingwebhookconfiguration pod-mutator
kubectl delete validatingwebhookconfiguration pod-validator

Ensuite, corrigez le problème sous-jacent et réappliquez.

Exemple de retour en arrière : si un nouveau webhook cause des problèmes, revenez à une version précédente en réappliquant l'ancienne configuration ou en utilisant kubectl apply avec le manifeste connu comme bon.

Question rapide 2 sur 2

Quels outils l'article recommande-t-il pour créer un petit cluster de test local pour les modifications de webhooks ?

Le passage recommande de tester les modifications de webhooks dans un environnement de préproduction et, au minimum, d'utiliser un outil comme minikube ou kind pour créer un petit cluster de test.

Pièges courants et comment les éviter

Au-delà des modes de défaillance déjà couverts, plusieurs autres pièges peuvent vous faire trébucher lorsque vous travaillez avec des webhooks d'admission. Être conscient de ceux-ci vous fera gagner du temps de débogage.

  • Versions admissionReviewVersions incompatibles : Le serveur d'API envoie les demandes d'admission dans les versions listées dans la configuration du webhook. Si votre serveur webhook ne comprend que v1beta1 mais que la configuration liste v1, la demande échouera. Déclarez toujours au moins v1 et assurez-vous que votre serveur la gère. Testez avec un point de terminaison d'écho simple pour voir quelle version est envoyée.
  • Oublier sideEffects: None : Si votre webhook n'a pas d'effets secondaires (il ne modifie pas l'état externe), définissez sideEffects: None. Cela permet au serveur d'API de l'appeler pendant les demandes de dry-run et l'empêche d'être ignoré lorsque la fonctionnalité dry-run est utilisée. Si votre webhook a des effets secondaires, documentez-les et envisagez sideEffects: NoneOnDryRun.
  • Règles trop larges : Faire correspondre toutes les ressources avec / peut amener le webhook à interférer avec les composants système. Limitez vos règles au minimum nécessaire, comme des ressources, des groupes et des opérations spécifiques. Par exemple, au lieu de faire correspondre tous les pods, faites correspondre uniquement les pods avec une étiquette spécifique ou dans un espace de noms particulier.
  • Espace de noms manquant dans clientConfig : Si vous omettez namespace dans clientConfig.service, le serveur d'API suppose le même espace de noms que la configuration du webhook, ce qui n'est souvent pas là où vit votre service. Spécifiez toujours l'espace de noms explicitement.
  • Renouvellement du certificat : Les certificats auto-signés ont une date d'expiration. Si le certificat expire, le webhook échouera. En production, utilisez une solution de gestion des certificats comme cert-manager avec renouvellement automatique. Dans le laboratoire, notez la date d'expiration et régénérez si nécessaire.
  • Ignorer les délais d'attente des webhooks : Le délai par défaut est de 10 secondes, mais certaines opérations peuvent prendre plus de temps. Définissez un timeoutSeconds approprié dans la configuration du webhook et assurez-vous que votre webhook répond dans ce délai. Si votre webhook a besoin de plus de temps, ajustez le délai, mais soyez prudent quant au ralentissement de toutes les requêtes correspondantes.

Liste de contrôle des opérations

Utilisez cette liste de contrôle pour votre laboratoire local et votre future utilisation en production. Chaque tâche a un seul responsable redevable et une fréquence de révision. Dans un cadre de production, attribuez un responsable tel que le responsable de l'ingénierie de plateforme.

TâcheCommande / ActionRésultat attenduResponsableFréquence de révision
Vérifier que les pods du webhook s'exécutentkubectl get pods -l app=webhook-server1/1 En cours d'exécutionIngénieur DevOps de gardeÀ chaque déploiement, ou hebdomadaire
Vérifier les configurations de webhookkubectl get mutatingwebhookconfigurations, validatingwebhookconfigurationsLa liste montre les configurationsResponsable de plateformeMensuel
Tester le webhook de mutationCréer un pod et inspecter les étiquettesÉtiquette ajoutéeDéveloppeurÀ chaque modification
Tester le webhook de validationCréer un pod avec une étiquette interditeDemande rejetéeDéveloppeurÀ chaque modification
Surveiller les journaux du webhookkubectl logs deployment/webhook-serverDemandes d'admission journaliséesSREQuotidien pendant un incident, hebdomadaire sinon
Vérifier les journaux du serveur d'API pour les erreursVariable selon le clusterAucune erreur TLS ou de connexionAdministrateur de clusterHebdomadaire
Tester la politique d'échecMettre à l'échelle le déploiement du webhook à 0, créer un podLa création du pod échoue avec une erreurIngénieur QAAvant chaque version
Restaurer le webhookRemettre à l'échelle à 1La création du pod réussitIngénieur QAAprès le test d'échec

Conclusion

Vous disposez maintenant d'un laboratoire local fonctionnel pour les webhooks d'admission Kubernetes. Vous avez appris à générer des certificats, déployer un serveur webhook, créer des configurations de webhooks de mutation et de validation, vérifier le comportement et récupérer après des défaillances. Utilisez cet environnement pour développer et tester en toute sécurité une logique d'admission plus complexe avant de la déployer en production. Commencez par de petits changements mesurables, et testez toujours les scénarios de défaillance pour comprendre l'impact. Les compétences que vous avez pratiquées ici—configuration TLS, enregistrement de webhook et récupération après défaillance—sont directement transférables aux environnements de production, où des tests minutieux et un plan de retour en arrière solide sont essentiels.

Recherches connexes

Score de qualité de l’article

Utilité pour le lecteur 100%
  • check_circle Guide prêt à lire
  • check_circle Exemples pratiques inclus
  • check_circle URL d’article optimisée pour le SEO