Contêineres que não declaram perfil seccomp rodam, na maior parte dos clusters em produção, sem qualquer restrição às chamadas de sistema que podem fazer ao kernel. Isso importa porque, após comprometer um processo dentro do Pod por uma falha de dependência, o atacante opera com a superfície completa de syscalls disponível no nó — incluídas aí primitivas que técnicas de escalonamento de privilégio costumam explorar. A ação prioritária para equipes que operam Kubernetes em Linux tem três partes: adotar o perfil RuntimeDefault como padrão do kubelet, impedir na admissão que workloads declarem Unconfined e evoluir para perfis por workload quando o padrão do runtime não bastar. Este guia percorre as camadas nessa ordem de adoção.
Por que restringir syscalls
Seccomp, ou secure computing mode, é um recurso do kernel Linux, presente desde a versão 2.6.12, que limita as chamadas que um processo em userspace pode fazer ao kernel. No Kubernetes, esse suporte é estável desde a v1.19 e o perfil é declarado no campo seccompProfile do securityContext, no nível do Pod ou de cada contêiner. Init containers e ephemeral containers têm campo próprio; o valor definido no contêiner tem prioridade sobre o herdado do Pod, e contêineres que não declaram nada herdam o perfil do nível superior.
Dois detalhes operacionais evitam surpresas no primeiro rollout. Primeiro: não é possível aplicar perfil seccomp a contêiner configurado com privileged: true — contêineres privilegiados sempre rodam como Unconfined, então o endurecimento de syscalls começa por eliminar privileged dos manifests. Segundo: perfis do tipo Localhost são arquivos JSON que precisam existir no disco do nó, sob /var/lib/kubelet/seccomp; se o arquivo não estiver lá, a criação do contêiner falha com CreateContainerError. Distribuição de perfil por nó é, por isso, um problema de automação, não de sintaxe.
RuntimeDefault como padrão
Sem configuração adicional, o kubelet não aplica seccomp algum: Pods sem perfil explícito rodam Unconfined. A configuração seccompDefault do kubelet muda isso. Quando habilitada — pela flag --seccomp-default ou pelo arquivo de configuração do kubelet — todo Pod que não declara perfil recebe o RuntimeDefault, o perfil padrão definido pelo container runtime em uso, construído com um defaultAction que nega chamadas fora da lista permitida. Como cada runtime mantém sua própria lista, e ela pode variar entre containerd e CRI-O e entre versões, o resultado concreto deve entrar no cálculo dos testes de compatibilidade.
A documentação do Kubernetes recomenda habilitar o recurso primeiro em um subconjunto de nós e observar a execução dos workloads antes de estender ao cluster inteiro. A mudança não altera o campo securityContext.seccompProfile nem adiciona anotações ao manifest, o que permite reverter a qualquer momento sem tocar na configuração dos workloads. Para verificar qual perfil um contêiner efetivamente recebeu, o crictl inspect expõe o seccomp aplicado pelo runtime naquele nó.
Bloqueio na admissão
O padrão do nó protege o que não foi declarado; a admissão protege o que foi mal declarado. Os Pod Security Standards definem três políticas cumulativas — Privileged, Baseline e Restricted — e o Pod Security Admission pode exigir, avisar ou auditar cada rótulo por namespace, o que permite uma transição gradual por equipe. Na política Baseline, voltada a prevenir escalonamentos conhecidos mantendo compatibilidade com workloads comuns, o padrão proíbe que o perfil seccomp seja definido explicitamente como Unconfined; os valores aceitos são indefinido, RuntimeDefault e Localhost. A política Restricted é descrita como fortemente restritiva, alinhada às práticas recomendadas de hardening de Pods, e serve de meta para namespaces de cargas críticas.
Transformar isso em rotina de entrega segue a mesma lógica de converter requisitos em critério de aceite no pipeline, como no ASVS no pipeline: manifest que pede Unconfined deve falhar no CI antes de chegar ao cluster, e namespaces novos já nascem com rótulo Baseline, no mínimo em modo enforce.
Perfis por workload
| Tipo | O que faz | Quando usar |
|---|---|---|
| Unconfined | Roda sem restrição de syscalls | Nunca como escolha; só como exceção documentada e bloqueada na admissão |
| RuntimeDefault | Aplica o perfil padrão do container runtime do nó | Ponto de partida para praticamente todo workload |
| Localhost | Aplica um JSON de allowlist presente no nó | Cargas conhecidas que precisam de menos syscalls que o padrão |
Um perfil Localhost é um JSON no formato da especificação de runtime da OCI: um defaultAction com SCMP_ACT_ERRNO negando por padrão e uma lista de chamadas com ação de permissão. O erro comum é escrever a allowlist na mão, adivinhando o que a aplicação precisa. O caminho sustentável é gravar o perfil a partir do comportamento real da aplicação em execução e só então aplicar em modo restritivo, mantendo o perfil versionado junto ao código do workload — um perfil que ninguém sabe reproduzir é dívida, não controle.
O período após a ativação merece monitoração dedicada: chamadas bloqueadas aparecem como erro de syscall no processo, com sintomas que vão de recurso que não inicia a funcionalidade que falha em silêncio. Trate todo bloqueio inesperado como sinal de perfil incompleto, não como falha da aplicação, e ajuste a lista com base no que foi observado.
Gravação com Security Profiles Operator
É aqui que entra o Security Profiles Operator (SPO), projeto da organização kubernetes-sigs que facilita criar e usar perfis seccomp, SELinux e AppArmor em clusters. O SPO roda como um deployment que gerencia pods daemon em cada nó, responsáveis pela instalação, gravação e aplicação dos perfis. A gravação de perfis seccomp pode acontecer por avaliação dos logs de auditoria do nó ou por um gravador embutido em eBPF, e o resultado vira um recurso gerenciado do cluster em vez de um arquivo copiado à mão para cada máquina — o que resolve justamente o problema de distribuição descrito acima. O operador também enriquece os registros de auditoria, o que conecta essa camada ao trabalho de normalização de logs no SIEM descrito no guia sobre OCSF no SIEM: chamadas bloqueadas por seccomp são eventos de detecção, não apenas falha de workload.
Roteiro de adoção
- P1 — inventário: listar Pods com privileged, com Unconfined explícito e sem perfil algum; priorizar os que rodam código de terceiros ou recebem entrada externa.
- P1 — padrão do nó: habilitar seccompDefault em um grupo de nós de staging, validar workloads, estender ao restante; manter o rollback documentado.
- P1 — admissão: aplicar rótulo Baseline em enforce nos namespaces de aplicação e bloquear Unconfined no CI.
- P2 — perfis dedicados: gravar perfis com o SPO para cargas críticas, aplicar como Localhost e monitorar bloqueios antes de endurecer ainda mais.
- P2 — detecção: rotear eventos de auditoria enriquecidos ao pipeline de logs e criar alerta para picos de chamadas bloqueadas.