
Curso Kubernetes 25 — Segurança: RBAC, PSA, NetworkPolicy e secrets
Segurança em Kubernetes não é uma ferramenta. É um conjunto de padrões que impedem o próximo incidente — quase sempre causado por um cluster-admin esquecido ou um namespace sem rede isolada.
Este capítulo monta o mínimo que todo cluster de produção deveria ter.
Selo do curso: testado em Kubernetes 1.35 com PSA e Calico/Cilium.
Modelo de ameaça prático
Perguntas que valem mais que um checklist genérico:
- Se um pod for comprometido, o que ele alcança? (rede, API, secrets)
- Quem pode criar pod? Pod cria acesso ao nó.
- Onde estão os segredos e quem lê?
- O que roda com
privileged: truee por quê?
RBAC sem cluster-admin
Nunca dê cluster-admin a aplicação. Crie uma Role no namespace:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: portal-backend
namespace: portal
rules:
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: portal-backend
namespace: portal
subjects:
- kind: ServiceAccount
name: portal-backend
namespace: portal
roleRef:
kind: Role
name: portal-backend
apiGroup: rbac.authorization.k8s.io
No Deployment:
spec:
template:
spec:
serviceAccountName: portal-backend
automountServiceAccountToken: false
automountServiceAccountToken: false quando a app não fala com a API é o ganho mais barato do capítulo: sem token montado, credencial vazada no container não serve para nada.
Audite:
kubectl auth can-i --list --as=system:serviceaccount:portal:portal-backend -n portal
kubectl get clusterrolebindings -o json | jq -r '.items[] | select(.roleRef.name=="cluster-admin") | .metadata.name'
Pessoas: cada um com o próprio usuário (OIDC), não um kubeconfig compartilhado.
Pod Security Admission
PSA substituiu o PSP. Três níveis:
| Nível | O que exige |
|---|---|
| privileged | nada |
| baseline | bloqueia o pior (privileged, hostNetwork, hostPath) |
| restricted | roda como non-root, sem privilege escalation, seccomp, capabilities dropadas |
No namespace:
apiVersion: v1
kind: Namespace
metadata:
name: portal
labels:
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/enforce-version: latest
pod-security.kubernetes.io/warn: restricted
pod-security.kubernetes.io/audit: restricted
Comece com warn + audit, corrija as cargas, depois enforce.
Pod compatível com restricted:
spec:
securityContext:
runAsNonRoot: true
runAsUser: 10001
seccompProfile:
type: RuntimeDefault
containers:
- name: app
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
readOnlyRootFilesystem quebra app que escreve em /tmp. Monte emptyDir em /tmp — e descubra quantas apps escrevem onde não deviam.
NetworkPolicy: default-deny
Sem política, todo pod fala com todo pod. Comece negando:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny
namespace: portal
spec:
podSelector: {}
policyTypes: ["Ingress", "Egress"]
Depois libere o necessário:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: backend-allow
namespace: portal
spec:
podSelector:
matchLabels:
app: portal-backend
policyTypes: ["Ingress", "Egress"]
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: ingress-nginx
ports:
- protocol: TCP
port: 8080
egress:
- to:
- podSelector:
matchLabels:
app: portal-postgres
ports:
- protocol: TCP
port: 5432
- to:
- namespaceSelector: {}
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
Dois erros clássicos:
- Esquecer DNS no egress: tudo vira timeout.
- Confiar em IP: pod muda de IP; use selectors.
Teste:
kubectl -n portal run tmp --rm -it --image=busybox -- sh
# dentro: nc -zv portal-postgres 5432 (deve falhar se não liberado)
Segredos
O que não fazer:
- Secret em
values.yamlou no Git. - Secret em variável de ambiente impressa em log.
- Mesmo segredo em todos os ambientes.
Opções:
- External Secrets Operator + Vault/AWS SM.
- Sealed Secrets (criptografado no Git).
- SOPS + age.
Independente da escolha:
- rotacione credenciais;
- limite leitura de Secret por Role (Secret é namespaced, mas leitura é poder);
- habilite
encryption at restno etcd; - evite
kubectl get secret -o yamlem pipeline.
E o alerta que já apareceu neste curso: minioadmin, changeme, admin/admin em manifest é incidente esperando data.
Runtime e imagens
- Imagens de registry confiável, por digest.
imagePullPolicy: IfNotPresentcom tag imutável.- Admission policy (Kyverno) barrando
:latest,privilegede hostPath. - Scanner de vulnerabilidade no pipeline (capítulo 24).
- Runtime security (Falco) para detectar shell em container.
Laboratório
- Aplique
default-denyno namespace e observe o que quebra. - Libere DNS e as dependências reais; valide com
nc/curl. - Ative PSA em
warne liste os pods não conformes. - Corrija
securityContextde um Deployment e passe paraenforce. - Crie ServiceAccount + Role mínima e teste com
kubectl auth can-i. - Tente
kubectl execcomo non-root e escrever em/(deve falhar).
Erros comuns
| Sintoma | Causa |
|---|---|
| Timeout após NetworkPolicy | DNS não liberado no egress |
| Pod rejeitado pelo PSA | falta runAsNonRoot/seccomp |
| App quebra com readOnlyRoot | escrita em /tmp sem emptyDir |
| Cluster-admin em todo lugar | RBAC copiado de tutorial |
| Secret legível por qualquer pod | falta RBAC + namespace isolado |
| Token da API montado sem uso | automountServiceAccountToken padrão |
| Policy não aplica | CNI sem suporte a NetworkPolicy |
Checklist
- [ ] ServiceAccount por aplicação, token desmontado quando possível.
- [ ] Roles mínimas e auditoria de
cluster-admin. - [ ] PSA
restricted(oubaselinejustificado) por namespace. - [ ]
securityContextcom non-root, seccomp e capabilities dropadas. - [ ] NetworkPolicy default-deny + liberações explícitas.
- [ ] DNS liberado no egress.
- [ ] Segredos fora do Git e rotação definida.
- [ ] etcd com encryption at rest.
- [ ] Admission policy para imagens e privilégios.
- [ ] Runtime detection (Falco) avaliada.
Glossário
- RBAC: controle de acesso por papel.
- ServiceAccount: identidade do pod.
- PSA: Pod Security Admission.
- NetworkPolicy: firewall entre pods.
- default-deny: nega tudo e libera o necessário.
- seccomp: filtro de syscalls.
- External Secrets: operador que sincroniza segredos externos.
Próximo
Cluster endurecido. Agora a pergunta que derruba ambiente: quanta carga ele aguenta? Capacidade, k6, rate limit e o que acontece quando o banco vira o gargalo.
Próximo: Curso Kubernetes 26 — Capacidade e carga: HPA, k6 e rate limit
Continuar a ler
Leia também
KubernetesKubernetes de Verdade — do zero ao cluster em produção
Uma trilha prática para entender, montar e operar um cluster Kubernetes — do primeiro pod ao failover do Postgres.
4 min de leitura
KubernetesCurso Kubernetes 28 — DR e capstone: provar que o cluster volta
RPO, RTO e drills reais: cenários de desastre, runbook, restore medido e o capstone que fecha o curso com um cluster que se recupera.
5 min de leitura
KubernetesCurso Kubernetes 27 — SLO/SLI, on-call e postmortem blameless
O que prometer, como medir e o que fazer quando o erro estoura: SLI, SLO, error budget, alertas que acordam alguém e postmortem sem caça às bruxas.
4 min de leitura
Comentários
Ainda sem comentários
Seja o primeiro a compartilhar sua opinião sobre este artigo.
Deixe um comentário