O Kubernetes fechou em 2026 a maturação de um dos controles de isolamento mais esperados da plataforma: user namespaces são agora um recurso estável desde o Kubernetes 1.36, com a feature gate UserNamespacesSupport travada — não existe mais opção de desligar o comportamento. A decisão que resta à equipe defensiva não é avaliar se o mecanismo amadureceu, e sim definir quais cargas migram para o novo modo sem quebrar volumes, runtimes e políticas de agendamento. A ação prioritária é inventariar pods que rodam como root sem necessidade técnica e convertê-los de forma gradual nos nós que já cumprem os requisitos de runtime e kernel.

O problema resolvido é estrutural. No contêiner Linux convencional, o UID 0 dentro do pod corresponde ao mesmo UID 0 do nó. Qualquer fuga de namespace — por defeito no runtime, falha do kernel ou volume montado de forma generosa — converte root de contêiner em root de host. User namespaces quebram essa equivalência: o processo continua root dentro do contêiner, mas o kubelet o mapeia para UIDs e GIDs altos e sem privilégio no nó. A documentação de conceitos do Kubernetes resume o efeito com exatidão: privilégios plenos para operações dentro do namespace, nenhum privilégio fora dele.

Como o isolamento funciona

A ativação é deliberada, por pod, e cabe ao dono da carga. Definindo o campo hostUsers como false na especificação do pod, o kubelet cria um user namespace dedicado e escolhe sozinho o intervalo de UIDs/GIDs do host para onde o pod será mapeado, garantindo que dois pods no mesmo nó nunca compartilhem a mesma faixa. Esse desenho elimina a configuração manual de mappings, que é a fonte mais comum de erro em implantações caseiras de userns via OCI puro.

O efeito sobre capabilities é o ganho defensivo central. Conceder CAP_SYS_ADMIN a um pod com user namespace deixa de significar poder sobre o nó: a capability vale apenas dentro do namespace e é inválida fora dele. CAP_SYS_MODULE perde o efeito por completo, porque o pod não consegue carregar módulos de kernel. Um workload legado que exige root para funcionar pode manter a compatibilidade interna sem que um comprometimento se traduza em controle do host — o argumento técnico mais forte para a migração.

Os campos runAsUser, runAsGroup e fsGroup continuam se referindo ao usuário dentro do contêiner, e os inodes criados em volumes montados pelo pod ficam idênticos aos de um pod sem user namespace. Isso permite ativar e desativar o modo sem alterar a propriedade de arquivos já gravados, um detalhe que evita migrações doloridas de storage e compartilhamento de volumes entre pods com e sem isolamento.

Requisitos de nó e runtime

O suporte exige containerd 2.0 ou CRI-O 1.25 como runtime de contêiner no nó, além de kernel Linux e sistemas de arquivos capazes de idmap mounts, a primitiva que remapeia donos de arquivos montados. Sem idmap, o runtime rejeita a criação do contêiner com erro explícito de MOUNT_ATTR_IDMAP, e o pod nunca sai de Creating. Esse é o primeiro ponto de verificação em qualquer plano de adoção: checar a versão do runtime e o filesystem dos volumes antes de tocar nas especificações dos pods.

Por padrão, o kubelet mapeia os pods para UIDs/GIDs acima da faixa 0–65535, assumindo que processos e arquivos do host vivem dentro dessa faixa, o que é padrão na maioria das distribuições. Para ajustar a faixa, o nó precisa do usuário kubelet no sistema, do binário getsubids do pacote shadow-utils e de uma única linha em /etc/subuid e /etc/subgid. Há regras rígidas: o ID inicial precisa ser múltiplo de 65536 e no mínimo 65536, a contagem precisa ser múltiplo de 65536 e suficiente para o número máximo de pods do nó, e as faixas de usuário e grupo precisam ser iguais. Reconfigurar um nó que já roda pods com user namespace exige drain antes — o kubelet se recusa a iniciar se não puder honrar os pods existentes, e DaemonSets com tolerações não são despejados sozinhos.

Limitações que travam a adoção

O modo é incompatível com o compartilhamento dos demais namespaces do host: um pod com hostUsers false não pode usar hostNetwork, hostIPC nem hostPID. Isso coloca fora do escopo DaemonSets de observabilidade, agentes de rede e qualquer carga que dependa da visão direta do nó — para essas, o caminho continua sendo um sandbox de runtime com micro-VM ou políticas equivalentes.

No storage, volumes NFS não podem ser montados em pods com user namespace, porque o cliente NFS do Linux ainda não suporta idmap mounts. Outros filesystems sem suporte a idmap geram o mesmo bloqueio. O levantamento de volumes deve preceder qualquer mudança em produção: um pod que monta um volume incompatível falha na criação, sem modo degradado.

Plano de adoção priorizado

O roteiro abaixo ordena o trabalho por risco e esforço, com critério objetivo de conclusão em cada etapa:

Prioridade Ação Critério de conclusão
P1 Inventariar pods com runAsUser 0 e sem necessidade real de privilégio Lista de candidatos aprovada pelo dono de cada aplicação
P1 Validar runtime, kernel e filesystem dos nós-alvo Runtime compatível e teste de idmap executado com sucesso em cada pool
P1 Excluir cargas com hostNetwork, hostIPC, hostPID ou volumes NFS Exceções documentadas com justificativa técnica
P2 Migrar cargas elegíveis em pool de staging com drain controlado Pods estáveis e verificação de namespace por readlink em /proc/self/ns/user
P2 Estender a política de admissão para exigir hostUsers false em novos deployments elegíveis Regra ativa no pipeline, com isenções auditáveis

A verificação prática de que o isolamento está ativo é simples: executar readlink /proc/self/ns/user dentro do contêiner e no host e comparar os identificadores — precisam ser diferentes. É também o sinal que o time de resposta deve registrar ao investigar um comprometimento de pod, porque define quais privilégios o invasor realmente tinha no nó. O controle complementa, não substitui, a higiene do pipeline: dependências maliciosas continuam entrando por imagens e pacotes, e travá-las antes do deploy com OSV-Scanner no CI/CD permanece obrigatório.

Sinais a monitorar

Três sinais indicam atrito na adoção. Primeiro, eventos Warning com falha em MOUNT_ATTR_IDIK na criação do sandbox apontam para filesystem sem idmap — corrija o pool ou exclua o volume. Segundo, pods presos em Creating em nós específicos sugerem runtime antigo nesse pool, verificação que deve entrar no runbook de upgrade. Terceiro, kubelet que não inicia após mudança de faixa subuid indica que a reconfiguração foi feita sem drain; a recuperação exige voltar à faixa anterior ou despejar os pods remanescentes. Nenhum desses sinais representa risco de segurança — são falhas de configuração que impedem o isolamento de existir, o que em si já é um achado digno de métrica.

A trajetória da funcionalidade ajuda a calibrar expectativa de longo prazo no hardening de plataforma: proposta em 2016 no KEP-127, alfa em 1.25, beta em 1.30, beta reforçada em 1.33 e estável em 1.36. Dez anos de iteração até o padrão ser considerado pronto para produção — e a recomendação operacional é não esperar outro ciclo para começar a usar.

Fontes