O Kubernetes mantém, desde a versão estável 1.30, um mecanismo nativo de admissão que dispensa serviço externo: a ValidatingAdmissionPolicy. A política valida requisições de admissão com expressões CEL dentro do próprio API server, sem depender de um webhook HTTP. A mudança interessa a equipes de plataforma que sustentam clusters com Gatekeeper, OPA ou Kyverno e pagam o custo operacional de manter um endpoint sempre disponível no caminho crítico. A ação prioritária é separar as regras de validação pura das que dependem de contexto externo, reescrever as primeiras em CEL e migrá-las em fases, começando pelo modo de aviso.
Como a política nativa funciona
A documentação oficial descreve o recurso como uma alternativa declarativa e em processo aos webhooks de validação. A lógica vive em um objeto ValidatingAdmissionPolicy, escrito em CEL, e ganha efeito quando um ValidatingAdmissionPolicyBinding o amarra a um escopo. Opcionalmente, um recurso de parâmetro — um ConfigMap ou um CRD próprio — carrega os limites concretos, como o número máximo de réplicas por ambiente, sem que a regra precise ser reescrita para cada caso.
O recorte de escopo vem do matchConstraints, que lista grupos de API, versões, operações e recursos afetados, e do binding, que adiciona seletores de namespace. É assim que uma mesma política aceita um parâmetro restritivo para produção e outro mais folgado para teste, com dois bindings apontando para o mesmo objeto. Quando mais de um binding casa com a requisição, ou quando um binding referencia vários parâmetros, todas as combinações precisam passar para a requisição ser admitida.
Um detalhe que economiza horas de depuração: o status do objeto devolve avisos de verificação de tipos. Ao criar a política, o servidor confere cada expressão contra o schema do recurso correspondente e sinaliza campos inexistentes antes de a regra entrar em vigor. Um campo digitado com a maiúscula errada aparece como aviso consultável, em vez de virar uma regra silenciosamente inócua que a equipe acredita estar ativa.
Do aviso à negação
O controle do comportamento fica nas validationActions, declaradas no binding. A documentação lista três ações possíveis: Deny nega a requisição, Warn devolve um aviso ao cliente e Audit registra a falha no evento de auditoria. É essa granularidade que viabiliza a migração sem sustos: a equipe pode começar em modo aviso e auditoria antes de passar a negar, observando quais manifests violariam as regras enquanto os desenvolvedores recebem feedback direto no kubectl.
Há uma restrição que evita ruído duplicado: Deny e Warn não podem ser combinados no mesmo binding, porque repetiriam a mesma falha no corpo da resposta e nos cabeçalhos de aviso. A ação Audit, por sua vez, deixa um rastro consultável de todas as tentativas que feriram a regra, o que transforma a fase de observação em um inventário real de débito de configuração, com namespace, workload e razão da violação.
Latência medida em produção
O argumento de desempenho não é teórico. No relatório técnico da Mercedes-Benz Tech Innovation apresentado no KubeCon Europe, os engenheiros descrevem a plataforma gerenciada que executava o Open Policy Agent como pod estático, respondendo pelo webhook de validação. Sob contenção, esse caminho chegou a atrasar requisições de API em até 11 segundos — um custo inaceitável para pipelines que criam objetos em lote e para qualquer time que dependa de resposta rápida da linha de comando.
A saída foi mover a validação para políticas nativas e tirar do caminho crítico o que exige processo externo. Como a política não é um processo dedicado, não expõe métricas próprias: a telemetria vem do API server, com séries como apiserver_validating_admission_policy_check_total para a taxa de avaliação e apiserver_validating_admission_policy_check_duration_seconds_bucket para a duração. Uma consulta de histograma sobre a série de duração mostra o custo real da política no percentil que importa para o acordo de serviço.
A mesma apresentação recomenda medir as próprias políticas antes de confiar nelas. Os testes de ponta a ponta precisam cobrir subrecursos como pods/ephemeralcontainers, onde atualizações de contêineres escapam do fluxo comum de implantação, e o comparativo entre soluções deve ser feito no próprio cluster, porque a carga e a versão do API server mudam o resultado.
O que migra, o que fica
Nem toda regra de webhook tem tradução direta. A política nativa avalia o objeto da requisição e parâmetros armazenados no cluster; ela não consulta registros externos, não valida assinaturas de imagem em um serviço remoto e não substitui um autorizador para decisões que dependem de contexto além da requisição. Mutações no mesmo formato pertencem às MutatingAdmissionPolicy, tratadas à parte na documentação. A divisão prática: validação de campos, limites e combinações proibidas migra; lógica com dependência de rede permanece no webhook, agora com menos tráfego.
| Critério | Webhook de validação | Política nativa |
|---|---|---|
| Execução | Processo externo chamado por HTTP | Dentro do API server |
| Linguagem | Código do serviço (Go, Rego etc.) | Expressões CEL no manifesto |
| Dependência | Disponibilidade do pod e da rede | Sem chamada externa na admissão |
| Comportamento em falha | failurePolicy do webhook | failurePolicy da política |
| Telemetria | Métricas do próprio serviço | Métricas do API server |
| Mutação | Comum em webhooks mutadores | Fica para as políticas de mutação |
Exceções continuam sendo o ponto sensível de qualquer controle de admissão. Rótulos de isenção e expressões com curto-circuito abrem espaço para casos especiais, mas cada abertura precisa de dono, justificativa e prazo de revisão — o mesmo rigor que o guia sobre acesso de emergência testável recomenda para situações em que a regra precisa ser atravessada. E a admissão não substitui a auditoria periódica do cluster: a análise de como auditar o cluster com critérios complementa o controle de entrada com a verificação contínua da configuração.
Checklist de adoção
- Inventariar as regras do webhook atual e separar validação pura de lógica com dependência externa.
- Reescrever as regras puras em CEL, usando variáveis para não repetir subexpressões longas.
- Criar a política em namespace de teste com ações de aviso e auditoria e conferir os avisos de verificação de tipos no status.
- Medir as violações por namespace com os eventos de auditoria e priorizar a correção dos manifests críticos.
- Trocar para Deny nos namespaces de menor risco, com janela de reversão documentada.
- Monitorar as métricas do API server e alertar sobre picos de rejeição ou de duração de avaliação.
Na priorização, trate como P1 a publicação das políticas em modo aviso e auditoria: não muda comportamento e produz o inventário de débito que a equipe precisa. Como P2, planeje a troca para Deny namespace por namespace e a aposentadoria do webhook nas regras já migradas, sempre com os testes de ponta a ponta cobrindo os subrecursos que escapam do fluxo comum. O resultado é um controle de admissão com menos peças móveis, decisões registradas no próprio cluster e um caminho mensurável até a remoção do serviço externo.