Pod Security Standards no Kubernetes: Proteção em Camadas
Pod Security Standards (PSS) é um mecanismo nativo do Kubernetes que define três níveis de restrição de segurança para Pods. Diferente de políticas antigas como Pod Security Policy (descontinuada desde a v1.25), o PSS utiliza admission controllers e labels nos namespaces para regular o que cada Pod pode fazer. Essa abordagem elimina complexidades anteriores e oferece uma solução simples mas robusta.
O Kubernetes, por padrão, permite que containers rodem com privilégios elevados, acessem filesystems do host, e façam operações perigosas. O PSS resolve esse problema estabelecendo três perfis: Restricted (máxima segurança), Baseline (segurança mínima compatível com padrões), e Privileged (sem restrições). Cada um deles é aplicado no nível do namespace, não requerendo instalação de recursos externos.
Os Três Níveis de Segurança
Restricted: Máxima Segurança
O nível Restricted implementa as melhores práticas de segurança conforme recomendações da indústria. Um Pod sob este padrão não pode rodar como root, não pode acessar o filesystem do host, não pode escalar privilégios, e deve declarar limites de recursos. É ideal para ambientes críticos e produção.
As principais restrições do Restricted incluem:
- Containers devem rodar com
runAsNonRoot: true - Linux capabilities devem ser removidas (exceto NET_BIND_SERVICE)
- Filesystem raiz deve ser somente-leitura (
readOnlyRootFilesystem: true) - Não é permitido
privileged: trueouallowPrivilegeEscalation: true seccompdeve ser configurado comRuntimeDefaultou um perfil customizado- SELinux deve usar
restrictedcomo tipo
Aqui está um exemplo de um Deployment que está em conformidade com o Restricted:
apiVersion: apps/v1
kind: Deployment
metadata:
name: secure-app
namespace: production
spec:
replicas: 2
selector:
matchLabels:
app: secure-app
template:
metadata:
labels:
app: secure-app
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 2000
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: nginx:1.21-alpine
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
runAsNonRoot: true
runAsUser: 1000
capabilities:
drop:
- ALL
ports:
- containerPort: 8080
resources:
requests:
memory: "64Mi"
cpu: "100m"
limits:
memory: "128Mi"
cpu: "500m"
volumeMounts:
- name: cache
mountPath: /tmp
- name: var-cache
mountPath: /var/cache/nginx
volumes:
- name: cache
emptyDir: {}
- name: var-cache
emptyDir: {}
Baseline: Segurança Mínima Viável
O Baseline representa o nível mínimo de segurança sem restringir aplicações legadas comuns. Ele permite muitas operações que o Restricted proíbe, mas ainda bloqueia os riscos mais óbvios como containers com ALL capabilities ou hosts que usam privilégios inseguros do host. É apropriado para aplicações que você conhece e confia, mas que não podem cumprir os requisitos do Restricted.
As principais características do Baseline:
- Permite
runAsRoot(usuário 0), mas bloqueia alguns casos privilegiados - Permite a maioria das Linux capabilities, exceto SYS_ADMIN, SYS_RAWIO, etc.
- Não requer
readOnlyRootFilesystem - Permite
allowPrivilegeEscalation: true - Não força seccomp ou SELinux
Um exemplo típico de aplicação Baseline:
apiVersion: v1
kind: Pod
metadata:
name: legacy-app
namespace: development
spec:
containers:
- name: web-server
image: apache:2.4
securityContext:
runAsUser: 0
allowPrivilegeEscalation: true
ports:
- containerPort: 80
volumeMounts:
- name: www
mountPath: /var/www/html
volumes:
- name: www
hostPath:
path: /data/www
type: Directory
Este Pod funcionará sob o Baseline, mas falhará no Restricted porque executa como root e permite escalação de privilégios.
Privileged: Sem Restrições
O nível Privileged desabilita completamente as verificações de segurança do PSS. É necessário apenas em casos muito específicos: container runtimes, CNI plugins, ou ferramentas de monitoramento do host que genuinamente precisam de acesso privilegiado. Você deve evitar este nível para aplicações normais.
Um exemplo de uso legítimo do Privileged seria um daemonset que monitora o host:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: host-monitor
namespace: kube-system
spec:
selector:
matchLabels:
app: host-monitor
template:
metadata:
labels:
app: host-monitor
spec:
hostNetwork: true
hostPID: true
containers:
- name: monitor
image: prometheus-node-exporter:latest
securityContext:
privileged: true
volumeMounts:
- name: proc
mountPath: /host/proc
readOnly: true
- name: sys
mountPath: /host/sys
readOnly: true
volumes:
- name: proc
hostPath:
path: /proc
- name: sys
hostPath:
path: /sys
Aplicando Pod Security Standards aos Namespaces
Para ativar o Pod Security Standards em um namespace, você usa labels. Existem três tipos de labels que controlam o comportamento do enforcement:
pod-security.kubernetes.io/enforce: bloqueia Pods que violam o padrão (modo enforcement)pod-security.kubernetes.io/audit: registra Pods que violam, mas permite (modo auditoria)pod-security.kubernetes.io/warn: avisa o usuário mas permite (modo warning)
Cada um desses labels recebe um valor: baseline, restricted ou privileged.
Configurando um Namespace com Restricted
Para forçar que todos os Pods em um namespace sigam o padrão Restricted:
apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/warn: restricted
Depois de aplicar este namespace, qualquer tentativa de criar um Pod que não esteja em conformidade com Restricted resultará em um erro. Por exemplo, tentar criar um Pod que roda como root será rejeitado:
$ kubectl apply -f pod-root.yaml -n production
Error from server (Forbidden): error when creating "pod-root.yaml": pods "test-pod" is forbidden:
violates PodSecurityPolicy: runAsNonRoot
Modo Auditoria e Warning
Se você quer migrar gradualmente para padrões mais restritos, use auditoria e warnings primeiro:
apiVersion: v1
kind: Namespace
metadata:
name: staging
labels:
pod-security.kubernetes.io/enforce: baseline
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/warn: restricted
Nesta configuração, Pods podem violar o Restricted, mas:
- Serão registrados nos logs de auditoria
- Exibirão um aviso ao usuário
- Mas ainda serão criados com sucesso
Isso permite identificar quais aplicações precisam de ajustes antes de enforçar Restricted completamente.
Exceções com Versões de API
O PSS evolui com novas versões do Kubernetes. Use labels de versão para aceitar comportamentos antigos:
apiVersion: v1
kind: Namespace
metadata:
name: legacy-support
labels:
pod-security.kubernetes.io/enforce: baseline
pod-security.kubernetes.io/enforce-version: v1.24
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/audit-version: latest
Migração Prática: Do Privileged para Restricted
Uma estratégia real de migração segue passos claros. Começamos examinando Pods existentes, aplicamos labels de auditoria, identificamos violações, corrigimos manifests, e finalmente ativamos enforcement.
Passo 1: Auditar Aplicações Existentes
Aplique auditoria sem enforcement em namespaces importantes:
kubectl label namespace my-app \
pod-security.kubernetes.io/audit=restricted \
--overwrite
Passo 2: Identificar Violações
Verifique os logs de auditoria para encontrar quais Pods violam o padrão:
kubectl get events -n my-app --sort-by='.lastTimestamp' | grep "PodSecurity"
Passo 3: Corrigir Manifests
Para cada aplicação que viola, atualize o manifest. Exemplo de correção de uma aplicação que roda como root:
Antes (violação):
containers:
- name: app
image: myapp:latest
Depois (correto):
securityContext:
runAsNonRoot: true
runAsUser: 1001
fsGroup: 2001
containers:
- name: app
image: myapp:latest
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
Passo 4: Ativar Enforcement
Apenas depois que todas as aplicações foram testadas e corrigidas:
kubectl label namespace my-app \
pod-security.kubernetes.io/enforce=restricted \
--overwrite
Conclusão
Aprendemos que Pod Security Standards oferece três níveis distintos — Restricted para máxima segurança, Baseline para compatibilidade, e Privileged para casos raros — sem complexidades de gerenciamento de políticas externas. A aplicação é simples: use labels no namespace e o admission controller nativo do Kubernetes garante conformidade. A migração é gradual e segura: implemente auditoria primeiro, identifique problemas, corrija Pods, então enforce — permitindo transições sem downtime.