GitHub EN PT

K8s em Exemplos: Admission Webhooks

Admission webhooks interceptam requests da API antes dos recursos serem persistidos. ValidatingWebhooks rejeitam recursos inválidos. MutatingWebhooks modificam recursos (injetam sidecars, adicionam labels). Webhooks mal configurados podem bloquear todos os deployments e quebrar clusters.

validatingwebhook.yaml

ValidatingWebhookConfiguration define quando chamar seu webhook. rules especifica quais recursos e operações disparam validação.

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
  name: pod-policy
webhooks:
  - name: pod-policy.example.com
    rules:
      - apiGroups: [""]
        apiVersions: ["v1"]
        operations: ["CREATE", "UPDATE"]
        resources: ["pods"]

Configure o endpoint do serviço webhook e TLS. O API server chama este serviço para cada request correspondente.

    clientConfig:
      service:
        name: pod-policy-webhook
        namespace: webhook-system
        path: /validate
        port: 443
      caBundle: LS0tLS1CRUd...  # Certificado CA em Base64
    admissionReviewVersions: ["v1"]
    sideEffects: None
    timeoutSeconds: 5
mutatingwebhook.yaml

MutatingWebhookConfiguration modifica recursos. Usos comuns: injetar sidecars (Istio), adicionar labels padrão, configurar security context. Mutations acontecem antes da validação.

apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
  name: sidecar-injector
webhooks:
  - name: sidecar.example.com
    rules:
      - apiGroups: [""]
        apiVersions: ["v1"]
        operations: ["CREATE"]
        resources: ["pods"]
    namespaceSelector:
      matchLabels:
        sidecar-injection: enabled

Use namespaceSelector ou objectSelector para limitar escopo. Isso previne o webhook de afetar namespaces do sistema.

    namespaceSelector:
      matchExpressions:
        - key: kubernetes.io/metadata.name
          operator: NotIn
          values:
            - kube-system
            - kube-public
    objectSelector:
      matchLabels:
        inject-sidecar: "true"
webhook-failurepolicy.yaml

failurePolicy controla o que acontece quando o webhook está indisponível. Fail: rejeita requests (seguro mas bloqueia deployments). Ignore: permite requests (arriscado mas não bloqueia).

webhooks:
  - name: critical-validation.example.com
    failurePolicy: Fail       # Bloqueia se webhook down
    timeoutSeconds: 10

  - name: optional-mutation.example.com
    failurePolicy: Ignore     # Permite se webhook down
    timeoutSeconds: 5

Crítico: Política Fail com webhooks quebrados bloqueia TODOS os requests correspondentes, incluindo pods do kube-system. Isso pode quebrar seu cluster. Sempre exclua namespaces do sistema.

# PERIGOSO: Falha em todos pods, incluindo sistema
rules:
  - resources: ["pods"]
failurePolicy: Fail

# SEGURO: Exclui namespaces do sistema
namespaceSelector:
  matchExpressions:
    - key: kubernetes.io/metadata.name
      operator: NotIn
      values: ["kube-system", "kube-public"]
terminal

Liste todos os webhooks no cluster. Quando deployments falham misteriosamente, verifique se um webhook está rejeitando-os.

$ kubectl get validatingwebhookconfigurations
NAME                        WEBHOOKS   AGE
pod-policy                  1          7d
gatekeeper-validating       1          30d

$ kubectl get mutatingwebhookconfigurations
NAME                        WEBHOOKS   AGE
istio-sidecar-injector      1          30d
cert-manager-webhook        1          30d

Verifique detalhes do webhook ao depurar. Observe rules, failure policy e endpoint do serviço.

$ kubectl get validatingwebhookconfiguration pod-policy -o yaml
webhooks:
- name: pod-policy.example.com
  failurePolicy: Fail
  clientConfig:
    service:
      name: pod-policy-webhook
      namespace: webhook-system
terminal

Rejeições de webhook aparecem nos eventos do pod. Procure mensagens admission webhook denied com a razão da rejeição.

$ kubectl describe pod failing-pod | grep -A10 Events
Events:
  Type     Reason     Message
  ----     ------     -------
  Warning  Failed     Error creating: admission webhook
           "pod-policy.example.com" denied the request:
           containers must not run as root

$ kubectl get events --field-selector reason=FailedCreate

Verifique logs do pod webhook para entender por que requests são rejeitados. O serviço webhook deve estar rodando e saudável.

$ kubectl logs -n webhook-system -l app=pod-policy-webhook
Validating pod default/myapp
Denied: runAsRoot not allowed in production namespace

$ kubectl get pods -n webhook-system
NAME                         READY   STATUS
pod-policy-webhook-abc123    1/1     Running
terminal

Correção de emergência: Delete a configuração do webhook para desbloquear deployments. Isso remove o webhook completamente até você corrigir e reimplantá-lo.

# Se webhook está bloqueando todos deployments:
$ kubectl delete validatingwebhookconfiguration broken-webhook
validatingwebhookconfiguration.admissionregistration.k8s.io "broken-webhook" deleted

# Deployments devem funcionar agora
$ kubectl get pods -n kube-system
# Pods iniciando novamente

Alternativa: faça patch do webhook para política Ignore temporariamente enquanto corrige o problema subjacente.

# Temporariamente permitir requests quando webhook falha
$ kubectl patch validatingwebhookconfiguration broken-webhook \
    --type='json' \
    -p='[{"op": "replace", "path": "/webhooks/0/failurePolicy", "value": "Ignore"}]'

# Corrija o serviço webhook, depois restaure política Fail
$ kubectl patch validatingwebhookconfiguration broken-webhook \
    --type='json' \
    -p='[{"op": "replace", "path": "/webhooks/0/failurePolicy", "value": "Fail"}]'
webhook-service.yaml

O webhook deve ser altamente disponível. Use múltiplas réplicas, resource limits adequados e PodDisruptionBudget. Um webhook down com política Fail bloqueia deployments.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: pod-policy-webhook
  namespace: webhook-system
spec:
  replicas: 3                    # HA
  selector:
    matchLabels:
      app: pod-policy-webhook
  template:
    spec:
      affinity:
        podAntiAffinity:         # Distribuir entre nodes
          requiredDuringSchedulingIgnoredDuringExecution:
            - topologyKey: kubernetes.io/hostname
      containers:
        - name: webhook
          resources:
            requests:
              cpu: 100m
              memory: 128Mi

Índice | Use as setas do teclado para navegar