Admission controllers: validando e mutando recursos antes do deploy
1. Introdução aos Admission Controllers no Kubernetes
Admission controllers são componentes essenciais do Kubernetes que interceptam requisições à API após a autenticação e autorização, mas antes da persistência no etcd. Eles funcionam como gatekeepers que podem modificar ou rejeitar objetos antes que sejam armazenados.
O fluxo completo de uma requisição é:
kubectl apply → Autenticação → Autorização → Admission Controllers → Persistência no etcd
Existem duas categorias principais:
- Mutating Admission Controllers: modificam o recurso antes da validação. Executam primeiro.
- Validating Admission Controllers: aprovam ou rejeitam o recurso após a mutação.
Os admission controllers podem ser built-in (embutidos no kube-apiserver) ou webhooks externos que estendem essa funcionalidade.
2. Tipos de Admission Controllers e Seus Mecanismos
MutatingAdmissionWebhook permite que você escreva código externo para modificar recursos. Por exemplo, injetar automaticamente um sidecar de logging em todo Pod.
ValidatingAdmissionWebhook rejeita recursos que não atendem a políticas específicas, como falta de labels obrigatórios.
Além dos webhooks, existem controllers built-in importantes:
PodSecurityPolicy: define políticas de segurança para Pods
LimitRanger: define limites padrão de recursos
ResourceQuota: restringe uso agregado de recursos por namespace
3. Construindo um Mutating Admission Webhook
Vamos construir um webhook que injeta automaticamente um sidecar de logging em todo Pod. A estrutura necessária inclui:
- Deployment do webhook
- Service para expor o endpoint
- Configuração TLS
- MutatingWebhookConfiguration
Servidor webhook em Go:
package main
import (
"encoding/json"
"fmt"
"net/http"
admissionv1 "k8s.io/api/admission/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func mutatePod(w http.ResponseWriter, r *http.Request) {
var review admissionv1.AdmissionReview
json.NewDecoder(r.Body).Decode(&review)
pod := &corev1.Pod{}
json.Unmarshal(review.Request.Object.Raw, pod)
// Adiciona sidecar de logging
sidecar := corev1.Container{
Name: "log-sidecar",
Image: "fluentd:latest",
VolumeMounts: []corev1.VolumeMount{
{Name: "varlog", MountPath: "/var/log"},
},
}
pod.Spec.Containers = append(pod.Spec.Containers, sidecar)
// Cria patch JSON
patchBytes, _ := json.Marshal([]map[string]interface{}{
{"op": "add", "path": "/spec/containers/-", "value": sidecar},
})
review.Response = &admissionv1.AdmissionResponse{
UID: review.Request.UID,
Allowed: true,
Patch: patchBytes,
PatchType: func() *admissionv1.PatchType {
pt := admissionv1.PatchTypeJSONPatch
return &pt
}(),
}
json.NewEncoder(w).Encode(review)
}
func main() {
http.HandleFunc("/mutate", mutatePod)
http.ListenAndServeTLS(":8443", "tls.crt", "tls.key", nil)
}
Configuração do webhook no Kubernetes:
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
name: sidecar-injector-webhook
webhooks:
- name: sidecar-injector.example.com
clientConfig:
service:
name: sidecar-injector
namespace: default
path: /mutate
caBundle: <base64-ca-cert>
rules:
- operations: ["CREATE"]
apiGroups: [""]
apiVersions: ["v1"]
resources: ["pods"]
admissionReviewVersions: ["v1"]
sideEffects: None
4. Construindo um Validating Admission Webhook
Agora, um webhook que rejeita Pods usando imagens sem tag fixa ou com vulnerabilidades conhecidas:
func validatePod(w http.ResponseWriter, r *http.Request) {
var review admissionv1.AdmissionReview
json.NewDecoder(r.Body).Decode(&review)
pod := &corev1.Pod{}
json.Unmarshal(review.Request.Object.Raw, pod)
var allowed bool = true
var message string
for _, container := range pod.Spec.Containers {
// Verifica se a imagem tem tag fixa
if !strings.Contains(container.Image, ":") {
allowed = false
message = "Imagem sem tag fixa: " + container.Image
break
}
// Verifica se não é latest
if strings.HasSuffix(container.Image, ":latest") {
allowed = false
message = "Uso de tag latest não permitido: " + container.Image
break
}
}
review.Response = &admissionv1.AdmissionResponse{
UID: review.Request.UID,
Allowed: allowed,
Result: &metav1.Status{
Message: message,
},
}
json.NewEncoder(w).Encode(review)
}
Configuração com parâmetros de resiliência:
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
name: image-validator
webhooks:
- name: image-validator.example.com
clientConfig:
service:
name: image-validator
namespace: default
path: /validate
caBundle: <base64-ca-cert>
rules:
- operations: ["CREATE", "UPDATE"]
apiGroups: [""]
apiVersions: ["v1"]
resources: ["pods"]
failurePolicy: Fail
timeoutSeconds: 5
admissionReviewVersions: ["v1"]
sideEffects: None
5. Segurança e Boas Práticas em Webhooks
Certificados TLS com cert-manager:
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: webhook-tls
namespace: default
spec:
secretName: webhook-tls-secret
duration: 2160h
renewBefore: 360h
dnsNames:
- sidecar-injector.default.svc
issuerRef:
name: selfsigned-issuer
kind: Issuer
Evitando loops infinitos: Use labels ou anotações específicas para marcar recursos que já foram processados pelo seu webhook. Configure objectSelector para ignorar certos namespaces ou recursos.
Monitoramento: Exporte métricas Prometheus do seu webhook:
# Métricas recomendadas
admission_webhook_requests_total{status="allowed|denied|error"}
admission_webhook_duration_seconds
admission_webhook_errors_total
6. Testando e Depurando Admission Controllers
Simulando requisições com curl dentro do cluster:
# Teste manual do webhook
kubectl run test-pod --image=nginx
# Verificar logs do webhook
kubectl logs -l app=sidecar-injector
# Testar diretamente o endpoint
curl -k -X POST https://sidecar-injector.default.svc:8443/mutate \
-H "Content-Type: application/json" \
-d @test-request.json
Ferramentas úteis:
# admission-webhook-boot: framework para testes
go get github.com/openshift/admission-webhook-boot
# kubectl admission-webhook: plugin para depuração
kubectl krew install admission-webhook
kubectl admission-webhook inspect
7. Casos de Uso Avançados e Integração com DevOps
OPA/Gatekeeper como Validating Admission Controller:
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
name: require-team-label
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Namespace"]
parameters:
labels:
- key: "team"
allowedRegex: "^[a-zA-Z]+$"
Integração com GitOps (Flux/ArgoCD):
# Pipeline de validação antes do merge
steps:
- name: validate-manifests
run: |
kubectl admission-webhook simulate \
--webhook image-validator \
--manifest deployment.yaml
8. Considerações Finais e Próximos Passos
Admission controllers são ferramentas poderosas para governança e automação no Kubernetes. Comparado a outras abordagens:
- PodSecurity: mais simples, mas menos flexível que webhooks
- Kyverno: alternativa declarativa que não requer codificação
- OPA/Gatekeeper: ideal para políticas complexas de compliance
Impacto na performance: Cada webhook adiciona latência ao kube-apiserver. Configure timeoutSeconds adequadamente (5-10s) e use failurePolicy: Ignore para webhooks não críticos.
Próximos passos: Explore CRDs e controller pattern para criar operadores que vão além da validação, automatizando operações complexas baseadas em eventos do cluster.
Referências
- Kubernetes Official Documentation: Admission Controllers — Documentação oficial completa sobre todos os admission controllers built-in e webhooks
- Kubernetes Webhook Tutorial: Mutating and Validating — Guia prático do blog oficial do Kubernetes sobre construção de webhooks
- Gatekeeper Library: OPA Constraint Templates — Repositório oficial com templates de políticas OPA/Gatekeeper prontos para uso
- Cert-Manager Documentation: Securing Webhooks — Tutorial oficial sobre como usar cert-manager para gerenciar certificados TLS de webhooks
- Kyverno: Policy Engine for Kubernetes — Documentação oficial do Kyverno, alternativa declarativa a webhooks customizados
- Prometheus Monitoring for Admission Webhooks — Guia de boas práticas para monitoramento e alertas de serviços Kubernetes, incluindo webhooks
- Admission Webhook Boot: Testing Framework — Ferramenta open-source para testar admission webhooks localmente