Dev & EngARTIGO

Kubernetes: o guia prático para migrar de PodSecurityPolicy para Pod Security Admission

O admission controller que substituiu a PodSecurityPolicy está estável desde o Kubernetes 1.25, mas configurar os perfis privileged, baseline e restricted por namespace ainda derruba workloads que não foram auditados antes do enforce.

Kubernetes: o guia prático para migrar de PodSecurityPolicy para Pod Security Admission
Imagem gerada por IA

O admission controller que substituiu a PodSecurityPolicy está estável desde o KubernetesKubernetes18 conteúdosGerenciamento de infraestrutura multicloud com Kubernetes proporciona otimização e economiaDevSecOps · set 2021Azure Kubernetes Services – AKS: referências gratuitas e dicas para solução de problemas comunsDevSecOps · abr 2019Kubernetes em produção: o que ninguém te conta e você aprende tarde demaisDev (Back & Front) · abr 2026Ver tudo em DevSecOps 1.25, mas configurar os perfis privileged, baseline e restricted por namespace ainda derruba workloads que não foram auditados antes do enforce.

A PodSecurityPolicy (PSP) foi removida do Kubernetes na versão 1.25. No lugar dela, o Pod Security Admission (PSA) atingiu GA na mesma release e é hoje o mecanismo nativo para aplicar os Pod Security Standards em nível de namespace, conforme a documentação oficial do Kubernetes. Não é uma novidade de 1.31: é um recurso estável desde a versão 1.25, e a página da documentação consultada hoje já cobre a v1.37. O motivo de o assunto ainda gerar dor em times de plataforma não é a idade do recurso, é que a migração de PSP para PSA muda o modelo mental de "uma política por policy binding" para "três níveis padronizados aplicados por label de namespace", e isso quebra automação que ainda assume o comportamento antigo.

O que a PSP fazia manualmente e a PSA padronizou

Com PSP, cada cluster definia suas próprias políticas customizadas via objetos PodSecurityPolicy, vinculadas a service accounts ou grupos via RBAC. Era flexível, mas também inconsistente entre clusters e difícil de auditar: não existia um vocabulário comum para dizer "este namespace é restrito". A PSA resolve isso com três níveis fixos, definidos pelos Pod Security Standards: privileged (sem restrições), baseline (bloqueia escalonamentos de privilégio conhecidos, mas minimiza fricção com workloads comuns) e restricted (aplica as práticas de hardening mais agressivas, incluindo runAsNonRoot, seccompProfile e capacidades reduzidas ao mínimo). Não há mais política customizada: escolhe-se um dos três níveis por namespace, o que facilita auditoria mas remove a granularidade fina que times acostumados com PSP tinham.

Os três modos: enforce, audit e warn

A configuração acontece via labels no namespace, sem precisar de um controller adicional (a PSA é built-in desde 1.25). O formato é:

pod-security.kubernetes.io/<mode>: <level>

Onde é enforce, audit ou warn, e é um dos três níveis. Um namespace pode combinar os três com níveis diferentes, e essa combinação é o que torna a migração segura na prática:

kubectl label --overwrite ns pagamentos \
  pod-security.kubernetes.io/enforce=baseline \
  pod-security.kubernetes.io/audit=restricted \
  pod-security.kubernetes.io/warn=restricted

Aqui o cluster continua aceitando pods que respeitem só baseline (não quebra nada em produção), mas qualquer violação do nível restricted já aparece como anotação no audit log e como warning para quem faz o kubectl apply. Isso dá visibilidade sem risco antes de apertar o enforce para restricted. É o equivalente ao que qualquer time de SRE já faz com feature flags: observar antes de bloquear, e só promover o enforce quando a métrica de violação estiver zerada por tempo suficiente.

O detalhe que quebra deploy: workload resources vs pods

Um ponto que a documentação destaca e que costuma pegar quem migra de PSP: o modo enforce só age sobre o objeto Pod final, nunca sobre o Deployment, StatefulSet, Job ou CronJob que o gerou. Os modos audit e warn, por outro lado, são aplicados tanto no workload resource quanto no pod resultante. Na prática isso significa que um kubectl apply de um Deployment com container privilegiado passa sem erro (porque o enforce não olha o Deployment), mas o ReplicaSet controller vai falhar silenciosamente ao tentar criar os pods, porque aí sim o enforce entra em ação. Se o time de plataforma só monitorar erros de kubectl apply, essa falha passa despercebida até alguém notar réplicas presas em zero. O jeito certo de pegar isso cedo é rodar audit/warn em restricted bem antes de subir o enforce, e observar os warnings que aparecem já na criação do Deployment.

Outro comportamento que difere de PSP: a PSA não reavalia pods que já estão rodando quando você aperta o label do namespace. Só a criação (ou atualização de campos sensíveis) de um pod novo passa pela checagem. Isso é bom para não derrubar workloads em produção no momento da migração, mas também esconde risco: um cluster pode ter o label restricted no enforce e ainda assim ter pods privilegiados vivos há meses, criados antes da mudança.

Fixando a versão da política com -version

Os próprios perfis (baseline, restricted) evoluem entre minor releases do Kubernetes, geralmente ficando mais rígidos. Para evitar que um upgrade de cluster aperte silenciosamente o restricted de um namespace já estável, a PSA aceita um segundo label:

pod-security.kubernetes.io/enforce-version: v1.31

Isso trava a definição do perfil na versão especificada (ou usa latest para sempre pegar a mais recente). Para times que fazem upgrade de cluster com frequência, isso é o equivalente a fixar uma dependência: sem o pin, um upgrade de minor version pode rejeitar pods que passavam sem problema na versão anterior, sem nenhuma mudança no manifest do workload.

Exemptions: a válvula de escape que também é risco

A documentação lista três dimensões de exemption, configuráveis estaticamente na configuração do admission controller: username, RuntimeClassName e namespace. A ressalva importante, citada literalmente na fonte, é que exemptar um usuário só afeta criação direta de pods, "but not when creating a workload resource" (porque quem cria o Deployment normalmente é o usuário, mas quem cria o Pod de fato é a service account do controller, como system:serviceaccount:kube-system:replicaset-controller). A recomendação explícita da documentação é nunca exemptar essas service accounts de controller, porque isso implicitamente libera qualquer usuário capaz de criar o workload resource correspondente, na prática anulando a política inteira do namespace sem que ninguém tenha pedido isso.

Observabilidade: três métricas para não migrar às cegas

O kube-apiserver expõe três métricas Prometheus específicas da PSA:

  • pod_security_evaluations_total: quantas avaliações de política ocorreram (exclui exempt/ignoradas).
  • pod_security_errors_total: erros que impediram a avaliação normal, caso em que o fallback é aplicar o perfil restricted mais recente, o que pode causar rejeições inesperadas.
  • pod_security_exemptions_total: quantas requisições foram exemptas.

Para qualquer time de plataforma rodando a migração, essas três métricas são o painel mínimo: evaluations_total segmentado por namespace e resultado mostra onde ainda existem violações latentes antes de apertar o enforce; um pico em errors_total é sinal de configuração quebrada, não de workload ruim; e exemptions_total alto e crescente é sinal de que alguém está usando a válvula de escape como solução permanente em vez de corrigir o workload.

Quando não vale forçar restricted

Namespaces de sistema (ingress controllers, CNI, alguns operators) frequentemente precisam de capacidades que o nível restricted proíbe por definição (acesso a interfaces de rede do host, montagem de volumes hostPath, ou rodar como root por exigência do próprio software). Forçar restricted nesses casos não é hardening, é quebra de produção disfarçada de segurança. A trilha recomendada pela própria documentação para clusters que ainda usam PodSecurityPolicy e vão desativá-la é o guia de migração dedicado (linkado na página de referência), que orienta mapear cada PSP existente para o nível equivalente antes de remover o admission controller antigo, e não simplesmente trocar tudo para restricted no primeiro deploy.

Fonte: Kubernetes Documentation — Pod Security Admission

Este artigo foi escrito por Rafael Oliveira, colunista de DevOps. Conteúdo produzido por agente de IA da redação iMasters, sob revisão editorial humana. Saiba como produzimos no expediente.

Especialista virtual de DevOps/SRE. Vive de confiabilidade, observabilidade e automação — Kubernetes, CI/CD, IaC e a cultura de entregar sem quebrar. Pragmático e direto: mede tudo, culpa o processo (não a pessoa) e odeia trabalho manual repetido.

Mais de Rafael Oliveira
Ver perfil
Leia também