A segurança em Kubernetes é um tópico crítico para garantir que ambientes conteinerizados estejam protegidos contra acessos não autorizados, vazamento de dados e execução de cargas maliciosas. Nesta aula, exploraremos quatro pilares essenciais: RBAC (controle de acesso baseado em papéis), Network Policies (políticas de rede), Secrets (segredos) e Pod Security (segurança de pods). Cada um desses componentes desempenha um papel fundamental na defesa em profundidade de um cluster Kubernetes.

Vamos aprender como configurar cada um deles, entender seus conceitos e aplicar boas práticas. Todo o conteúdo é baseado na documentação oficial do Kubernetes e em cenários reais de uso.

RBAC

RBAC (Role-Based Access Control) é o mecanismo padrão do Kubernetes para controlar quem pode acessar quais recursos e quais ações podem realizar. Ele permite definir papéis (Roles) que contêm um conjunto de permissões, e vincular esses papéis a usuários ou grupos através de RoleBindings ou ClusterRoleBindings.

Existem dois tipos de papéis: Role, que é namespace-específico, e ClusterRole, que é global. As permissões são definidas usando verbos como get, list, watch, create, update, delete, entre outros, aplicados a recursos como pods, services, deployments, etc.

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default
  name: pod-reader
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-pods
  namespace: default
subjects:
- kind: User
  name: jane
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

No exemplo acima, um usuário chamado jane recebe permissão para ler pods no namespace default. Para permissões cluster-wide, use ClusterRole e ClusterRoleBinding. Boa prática: sempre seguir o princípio do menor privilégio, concedendo apenas as permissões necessárias.

Network Policies

Network Policies são regras que controlam o tráfego de rede entre pods e entre pods e serviços externos. Por padrão, todos os pods podem se comunicar entre si sem restrições. Ao aplicar uma Network Policy, você isola os pods que correspondem aos seletores especificados, e apenas o tráfego permitido pelas regras é autorizado.

As políticas podem filtrar tráfego de entrada (ingress) e saída (egress) com base em labels de pods, namespaces, endereços IP ou portas. É importante lembrar que o plugin de rede (como Calico, Cilium ou Weave) deve suportar Network Policies para que funcionem.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-frontend
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: frontend
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: backend
    ports:
    - port: 80
  egress:
  - to:
    - ipBlock:
        cidr: 10.0.0.0/24
    ports:
    - port: 443

Neste exemplo, pods com label app=frontend aceitam tráfego apenas de pods com label app=backend na porta 80, e podem enviar tráfego apenas para o range 10.0.0.0/24 na porta 443. Boa prática: por padrão, negue todo o tráfego e depois libere apenas o necessário, seguindo o modelo de defesa em profundidade.

Secrets

Secrets são objetos do Kubernetes usados para armazenar informações sensíveis como senhas, tokens e chaves SSH. Eles são codificados em base64, mas não são criptografados por padrão no etcd. Para maior segurança, é recomendável habilitar a criptografia em repouso e usar ferramentas externas como HashiCorp Vault ou AWS Secrets Manager integradas ao cluster.

Os Secrets podem ser montados como volumes ou expostos como variáveis de ambiente nos pods. É importante evitar armazenar Secrets em arquivos de manifesto versionados em Git; em vez disso, use ferramentas como Sealed Secrets ou External Secrets Operator.

apiVersion: v1
kind: Secret
metadata:
  name: db-secret
type: Opaque
data:
  username: YWRtaW4=
  password: MWYyZDFlMmU2N2Rm
---
apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
  - name: mycontainer
    image: nginx
    env:
    - name: DB_USERNAME
      valueFrom:
        secretKeyRef:
          name: db-secret
          key: username
    - name: DB_PASSWORD
      valueFrom:
        secretKeyRef:
          name: db-secret
          key: password

No exemplo, um Secret contém username e password em base64. O pod injeta esses valores como variáveis de ambiente. Para criar o Secret, use kubectl create secret generic db-secret --from-literal=username=admin --from-literal=password=1f2d1e2e67df. Boa prática: evite Secrets grandes e considere usar Service Accounts com tokens automáticos.

Pod Security

Pod Security é um conjunto de políticas que controlam aspectos de segurança dos pods, como execução como root, uso de capabilities, filesystems read-only, e volumes hostPath. O Kubernetes oferece o Pod Security Admission (PSA) que substituiu o antigo PodSecurityPolicy (PSP) a partir da versão 1.25.

PSA define três níveis de segurança: privileged, baseline e restricted. O nível privileged permite tudo (sem restrições), baseline aplica restrições mínimas (como proibir containers privileged), e restricted é o mais restritivo (exige read-only root filesystem, não root, etc.). Você pode aplicar esses níveis a namespaces usando labels.

apiVersion: v1
kind: Namespace
metadata:
  name: my-namespace
  labels:
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/audit: baseline
    pod-security.kubernetes.io/warn: baseline

Com essa configuração, pods no namespace my-namespace que violarem o nível restricted serão rejeitados (enforce), enquanto violações de baseline geram logs de auditoria e avisos (audit e warn). Para verificar se um pod atende a um nível, use kubectl label --dry-run=server pod my-pod pod-security.kubernetes.io/enforce=restricted. Boa prática: use o nível restricted sempre que possível, e apenas exceções justificadas devem usar baseline ou privileged.

Boas Práticas e Observações Finais

Além dos quatro pilares, considere: manter o Kubernetes atualizado, usar namespaces para isolar ambientes, monitorar logs de auditoria, implementar políticas de segurança com ferramentas como OPA/Gatekeeper ou Kyverno, e realizar scans de vulnerabilidades nas imagens dos containers. A segurança é um processo contínuo e deve ser integrada ao ciclo de vida das aplicações.

Referências

Exercícios

  1. Crie um ClusterRole chamado pod-admin que permita todas as operações (get, list, watch, create, update, delete) em pods, e um ClusterRoleBinding que associe esse papel a um usuário chamado dev-user.

    ✓ Resposta:
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRole
    metadata:
      name: pod-admin
    rules:
    - apiGroups: [""]
      resources: ["pods"]
      verbs: ["get", "list", "watch", "create", "update", "delete"]
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      name: dev-user-pod-admin
    subjects:
    - kind: User
      name: dev-user
      apiGroup: rbac.authorization.k8s.io
    roleRef:
      kind: ClusterRole
      name: pod-admin
      apiGroup: rbac.authorization.k8s.io
  2. Crie uma Network Policy que permita tráfego de entrada apenas na porta 8080 vindo de pods com label app=web, e bloqueie todo o tráfego de saída.

    ✓ Resposta:
    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
      name: allow-web-only
    spec:
      podSelector: {}
      policyTypes:
      - Ingress
      - Egress
      ingress:
      - from:
        - podSelector:
            matchLabels:
              app: web
        ports:
        - port: 8080
      egress: []
  3. Crie um Secret chamado api-key com a chave key=abc123 e monte-o como volume em um pod nginx no caminho /etc/secret.

    ✓ Resposta:
    # Primeiro, crie o Secret (use kubectl ou manifesto)
    kubectl create secret generic api-key --from-literal=key=abc123
    # Ou via manifesto:
    apiVersion: v1
    kind: Secret
    metadata:
      name: api-key
    type: Opaque
    data:
      key: YWJjMTIz
    ---
    apiVersion: v1
    kind: Pod
    metadata:
      name: nginx-secret
    spec:
      containers:
      - name: nginx
        image: nginx
        volumeMounts:
        - name: secret-volume
          mountPath: /etc/secret
      volumes:
      - name: secret-volume
        secret:
          secretName: api-key
  4. Configure um namespace chamado secure-ns para rejeitar pods que não atendam ao nível restricted do Pod Security Admission.

    ✓ Resposta:
    apiVersion: v1
    kind: Namespace
    metadata:
      name: secure-ns
      labels:
        pod-security.kubernetes.io/enforce: restricted
        pod-security.kubernetes.io/enforce-version: latest
  5. Explique a diferença entre Role e ClusterRole e dê um exemplo de quando usar cada um.

    ✓ Resposta:Role é namespace-específico, ou seja, concede permissões apenas dentro de um namespace específico. ClusterRole é global, concedendo permissões em todo o cluster (incluindo recursos não-namespaced como nodes). Use Role para conceder acesso a recursos dentro de um namespace (ex: ler pods no namespace default). Use ClusterRole para conceder acesso a recursos cluster-wide (ex: gerenciar nodes) ou para reutilizar em múltiplos namespaces via RoleBinding (ex: leitura de pods em qualquer namespace).