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

  1. Inventariar as regras do webhook atual e separar validação pura de lógica com dependência externa.
  2. Reescrever as regras puras em CEL, usando variáveis para não repetir subexpressões longas.
  3. 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.
  4. Medir as violações por namespace com os eventos de auditoria e priorizar a correção dos manifests críticos.
  5. Trocar para Deny nos namespaces de menor risco, com janela de reversão documentada.
  6. 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.

Fontes