Da Construção de Imagens Seguras à Blindagem de Clusters e Microsserviços
A consolidação dos contêineres como padrão dominante para empacotamento e execução de microsserviços transformou a arquitetura de sistemas operacionais e redes corporativas. Contudo, essa ampla adoção gerou uma das falhas conceituais mais perigosas da engenharia de infraestrutura: a crença de que contêineres funcionam como máquinas virtuais isoladas.
Em uma máquina virtual tradicional, a barreira de isolamento é sustentada por um hipervisor de hardware, com cada sistema operacional executando seu próprio kernel autônomo, sua própria tabela de páginas de memória e seus próprios drivers. Em contrapartida, um contêiner é apenas um processo comum do espaço de usuário, executado diretamente sobre o kernel compartilhado do hospedeiro, contido por um conjunto de primitivas lógicas do sistema operacional Linux.
O confinamento de processos em ambientes OCI (Open Container Initiative), padronizado por runtimes como Docker, containerd e CRI-O, depende fundamentalmente de três mecanismos providos pelo kernel Linux:
/proc e /sys, mesmo que o processo em questão esteja executando com privilégios de superusuário.A configuração padrão da maioria dos runtimes de contêiner não cria uma fronteira de segurança impenetrável. Um processo rodando como UID 0 (root) dentro de um contêiner sem mapeamento de user namespaces é, diante das chamadas de sistema (syscalls) do kernel, o próprio superusuário do hospedeiro. Se o processo encontrar uma brecha em drivers, no sistema de arquivos compartilhado ou em capabilities desnecessárias, o escape para o nó físico é imediato.
O endurecimento operacional (hardening) de infraestruturas baseadas em contêineres exige uma abordagem em múltiplas camadas independentes. A violação de uma única camada não pode expor os dados da organização nem conceder acesso irrestrito ao restante da infraestrutura corporativa.
A engenharia defensiva para contêineres e clusters orquestrados é estruturada em quatro domínios de controle rigorosos, ilustrados a seguir:
Toda vulnerabilidade presente na imagem de contêiner é transferida diretamente para o ambiente de produção. O hábito comum de basear imagens corporativas em distribuições completas de uso geral, como Ubuntu ou Debian padrão, injeta centenas de megabytes de código supérfluo e utilitários que jamais serão executados pela aplicação, mas que servem perfeitamente a um invasor em caso de comprometimento.
Se uma aplicação web sofrer uma vulnerabilidade de injeção remota de comandos (RCE, Remote Code Execution), o sucesso da exploração depende criticamente dos binários disponíveis no sistema de arquivos local. A presença de utilitários como curl, wget, nc (netcat), python, apt, bash ou interpretadores Perl fornece as ferramentas exatas que o atacante necessita para baixar artefatos adicionais, estabelecer uma conexão reversa (reverse shell) e iniciar a varredura da rede interna.
A prática recomendada consiste no uso de imagens mínimas especializadas, conhecidas como imagens distroless ou imagens baseadas em scratch e Alpine reduzida. Imagens distroless contêm exclusivamente o binário da aplicação compilada e suas dependências de tempo de execução (como bibliotecas C dinâmicas e certificados de AC raiz), eliminando completamente gerenciadores de pacotes, interpretadores e shells interativos.
A metodologia de compilação em múltiplos estágios separa rigorosamente as ferramentas necessárias para compilar o código-fonte (como compiladores Go, SDKs Java, Node.js completo e cabeçalhos de compilação) do ambiente que recebe o artefato final para execução. O código-fonte bruto e os compiladores permanecem isolados nas camadas intermediárias de build, descartadas ao término do processo.
O exemplo técnico a seguir ilustra a construção segura de um microsserviço com compilação multi-stage, criação de usuário não privilegiado com identificador estático e descarte total de ferramentas de desenvolvimento:
# -----------------------------------------------------------------------------
# Estágio 1: Ambiente de compilação temporário (Build Stage)
# -----------------------------------------------------------------------------
FROM golang:1.24-bookworm AS builder
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
# Compilação estática: desativa dependência de bibliotecas C dinâmicas (CGO)
RUN CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-w -s" -o /bin/app ./cmd/server
# -----------------------------------------------------------------------------
# Estágio 2: Imagem final mínima para execução em produção
# -----------------------------------------------------------------------------
FROM gcr.io/distroless/static-debian12:nonroot
WORKDIR /app
# Copia exclusivamente o binário compilado a partir do estágio anterior
COPY --from=builder /bin/app /app/server
# Execução obrigatória sob o UID não privilegiado (65532:nonroot no distroless)
USER 65532:65532
EXPOSE 8080
ENTRYPOINT ["/app/server"]
A tabela a seguir compara o impacto das diferentes abordagens de construção de imagens de contêiner em relação à área de exposição a vulnerabilidades conhecidas (CVEs, Common Vulnerabilities and Exposures):
| Tipo de Imagem Base | Tamanho Médio | Presença de Shell | Gerenciador de Pacotes | CVEs Médias em Repouso |
|---|---|---|---|---|
| Distribuição Completa (ex: Ubuntu 22.04) | 78 MB a 150 MB | Sim (bash, sh) | Sim (apt, dpkg) | Alta (25 a 80 vulnerabilidades) |
| Distribuição Mínima (ex: Alpine Linux) | 7 MB a 12 MB | Sim (/bin/sh via busybox) | Sim (apk) | Baixa (geralmente 0 a 5) |
| Distroless Estático (ex: Distroless Nonroot) | 2 MB a 18 MB | Não (ausente) | Não (ausente) | Mínima (geralmente zero) |
| Imagem Vazia (scratch) | Apenas o binário | Não (ausente) | Não (ausente) | Zero vulnerabilidades de SO |
Tags mutáveis como latest, alpine:3.20 ou bookworm podem ser sobrescritas nos registros públicos de contêineres, introduzindo quebras de compatibilidade ou componentes adulterados. Em ambientes produtivos regulados, declare as imagens base referenciando o digest SHA-256 imutável: FROM golang@sha256:726354.... Essa prática garante a reprodutibilidade absoluta do processo de compilação.
Executar contêineres como superusuário (UID 0) é a causa direta da severidade crítica da maioria das vulnerabilidades de escape documentadas nos últimos anos. Se a aplicação não define explicitamente um usuário de menor privilégio na diretiva USER do Dockerfile ou na especificação do Pod, o runtime adota o root como padrão de execução.
O escape de contêiner ocorre quando um invasor, tendo obtido execução de código no espaço do contêiner, explora privilégios mal configurados para interagir diretamente com o sistema operacional hospedeiro. Vetores clássicos de escape incluem:
/var/run/docker.sock): Prática perigosa frequentemente empregada em pipelines de CI/CD para compilar imagens dentro de contêineres (Docker-in-Docker). Quem possui escrita no soquete do Docker possui controle irrestrito sobre a API do daemon, podendo iniciar um novo contêiner com --privileged, montar o sistema de arquivos raiz do hospedeiro (/) em /host e obter controle completo da máquina física.--privileged: Desativa completamente as proteções de isolamento. O contêiner recebe acesso direto a todos os nós de dispositivos em /dev, recupera todas as Linux capabilities do kernel e desativa os filtros Seccomp e AppArmor. A partir de um contêiner privilegiado, comandos como mknod ou a montagem direta de partições de disco do host em um diretório temporário concedem acesso total ao hospedeiro em poucos segundos./proc e /sys: A escrita em arquivos como /proc/sys/kernel/core_pattern permite que um processo root dentro do contêiner instrua o kernel do hospedeiro a executar um script malicioso no contexto do host quando ocorrer uma falha de segmentação forçada.O isolamento provido pelo namespace de usuários (User Namespaces) permite mapear uma faixa de UIDs e GIDs virtuais de dentro do contêiner para uma faixa completamente desprovida de privilégios no sistema operacional hospedeiro. Dessa forma, mesmo que a aplicação execute internamente como UID 0 (root virtual), para o kernel do host esse processo é reconhecido como um identificador arbitrário inofensivo, como o UID 100000.
Caso o processo consiga burlar as restrições do sistema de arquivos e alcançar o hospedeiro, ele não possuirá permissões para ler arquivos confidenciais em /etc/shadow, nem para enviar sinais de término a outros processos do sistema.
Por padrão, executáveis com bits SUID ativados (como sudo ou passwd) podem elevar os privilégios do chamador durante a execução. O runtime de contêiner deve ser configurado com o parâmetro de segurança --security-opt=no-new-privileges:true (no Docker/Podman) ou allowPrivilegeEscalation: false (no Kubernetes). Essa restrição impede que qualquer processo filho ganhe privilégios adicionais por meio de binários setuid/setgid ou transições de capabilities.
O modelo de permissões clássico do Unix era binário: um processo executava com privilégios de superusuário (UID 0) e podia realizar qualquer operação, ou operava como usuário comum e sofria bloqueios universais. Para mitigar esse risco estrutural, o kernel Linux fracionou o poder absoluto do superusuário em unidades atômicas granulares conhecidas como Linux Capabilities.
A configuração padrão dos runtimes OCI concede cerca de 14 capabilities automáticas para cada novo contêiner (incluindo CAP_NET_RAW, CAP_CHOWN, CAP_DAC_OVERRIDE e CAP_FOWNER). A ampla maioria dos serviços de microsserviços modernos, como servidores web e APIs REST, necessita de zero privilégios especiais de kernel.
A postura defensiva obrigatória consiste em descartar compulsória e universalmente todas as capabilities através da instrução drop: ["ALL"], reintroduzindo exclusivamente aquelas cuja ausência comprovadamente inviabilize o funcionamento do serviço:
# Exemplo de especificação de segurança em Pod do Kubernetes
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
runAsNonRoot: true
runAsUser: 10001
runAsGroup: 10001
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE # Permite escutar em portas abaixo de 1024, se indispensável
| Linux Capability | Operação Habilitada | Risco de Segurança em Caso de Comprometimento |
|---|---|---|
CAP_SYS_ADMIN |
Montagem de sistemas de arquivos, manipulação de namespaces, debug | Equivalente a root total; vetor direto para escape de contêiner. |
CAP_SYS_PTRACE |
Rastreamento de processos via syscall ptrace |
Permite ler a memória de processos vizinhos e extrair segredos/tokens. |
CAP_NET_ADMIN |
Configuração de interfaces de rede, tabelas de roteamento e firewall | Permite desativar regras defensivas e capturar tráfego de outros pods. |
CAP_NET_RAW |
Criação de pacotes RAW e pacotes ICMP personalizados | Permite forjar cabeçalhos IP (IP Spoofing) e ataques ARP spoofing. |
CAP_SYS_MODULE |
Carregamento e descarregamento de módulos de kernel (LKM) | Permite injetar rootkits diretamente no núcleo do sistema hospedeiro. |
CAP_DAC_OVERRIDE |
Ignora restrições de permissões de leitura, escrita e execução em arquivos | Anula o controle de acesso discricionário tradicional do sistema. |
O kernel Linux implementa mais de 450 chamadas de sistema (syscalls). Um microsserviço típico em Go, Rust ou Node.js raramente precisa de mais de 50 syscalls ativas para cumprir sua função de negócios. Syscalls arcaicas, experimentais ou destinadas à depuração e gerenciamento de hardware representam superfícies de ataque que facilitam a exploração de vulnerabilidades de corrupção de memória no próprio kernel.
O Seccomp (Secure Computing Mode) intercepta as chamadas de sistema efetuadas pelas threads do contêiner antes que alcancem o núcleo do sistema operacional. Caso uma instrução proibida seja disparada, o Seccomp pode abortar a chamada com erro (EPERM) ou terminar o processo infrator imediatamente (SIGKILL).
O Kubernetes introduziu o perfil padrão RuntimeDefault, que deve ser habilitado compulsória e globalmente em todos os pods do cluster através da configuração:
securityContext:
seccompProfile:
type: RuntimeDefault
A técnica de forçar o sistema de arquivos do contêiner para o modo somente leitura (readOnlyRootFilesystem: true) neutraliza classes inteiras de ataques pós-exploração. Se um invasor obtiver execução remota de código, ele não conseguirá gravar binários maliciosos, modificar scripts de inicialização, alterar arquivos de configuração em /etc nem baixar ferramentas em /tmp.
Se a aplicação necessitar de diretórios temporários transitórios para cache de escrita ou processamento de arquivos em trânsito, esses caminhos específicos devem ser montados isoladamente como volumes emptyDir baseados em memória RAM (medium: Memory) com limites estritos de tamanho, mantendo o restante da árvore de arquivos imutável.
Proteger o ambiente de execução em tempo real é ineficaz se o código ou as dependências que compõem a imagem forem adulterados antes da implantação. Incidentes cibernéticos contemporâneos atingem prioritariamente a cadeia de suprimentos de software (Software Supply Chain), inserindo cavalos de Troia em bibliotecas de código aberto populares ou comprometendo chaves de esteiras de integração contínua (CI/CD, Continuous Integration and Continuous Delivery).
Um SBOM (Software Bill of Materials) é a relação formal, estruturada e legível por máquina de todos os pacotes, dependências transitivas, bibliotecas e metadados que integram um artefato de software. Os padrões internacionais consolidados para geração de SBOMs são o SPDX (Software Package Data Exchange) e o CycloneDX.
A geração contínua do SBOM durante o processo de build do contêiner permite que a organização responda com agilidade a alertas emergenciais de vulnerabilidades críticas recém-descobertas (Zero-Day). Em vez de varrer servidores e clusters em produção buscando manualmente a presença de uma biblioteca vulnerável, a equipe de segurança consulta o repositório central de SBOMs e identifica em segundos todos os contêineres e versões afetadas.
O ecossistema Sigstore fornece o utilitário cosign, padronizando a assinatura digital de artefatos OCI e o armazenamento das assinaturas diretamente no registro de contêineres corporativo, sem a necessidade de manter infraestruturas proprietárias complexas.
A garantia de autenticidade da imagem baseia-se em uma regra inegociável: o orquestrador Kubernetes deve recusar terminantemente a inicialização de qualquer contêiner cuja imagem não apresente uma assinatura criptográfica válida, emitida pela chave privada oficial da esteira institucional de CI/CD.
# Geração do par de chaves assimétricas para a esteira
cosign generate-key-pair
# Assinatura digital do artefato recém-compilado no registro seguro
cosign sign --key cosign.key ciberlab-registry.local/apps/payment-service:v2.1.0
# Anexação do arquivo de SBOM formal (formato SPDX ou CycloneDX) à imagem
cosign attach sbom --sbom ./sbom.spdx.json ciberlab-registry.local/apps/payment-service:v2.1.0
# Assinatura criptográfica do atestado de proveniência e do SBOM anexado
cosign sign --key cosign.key ciberlab-registry.local/apps/payment-service:v2.1.0
Integre analisadores de vulnerabilidades estáticas de código e contêineres (como Trivy ou Grype) diretamente na esteira de integração. Estabeleça uma política rígida que interrompa automaticamente a compilação (retornando exit code 1) diante da detecção de falhas classificadas com severidade CRITICAL ou HIGH que já possuam correções disponíveis (--ignore-unfixed desativado).
O Kubernetes é um sistema distribuído de alta complexidade projetado primariamente para elasticidade e orquestração em escala. Quando implantado com configurações padrão de fábrica, o cluster apresenta uma superfície de ataque exposta em múltiplos componentes do plano de controle (Control Plane) e dos nós de processamento (Worker Nodes).
O Control Plane hospeda o cérebro da infraestrutura. A violação de qualquer um de seus componentes concede controle irrestrito sobre todas as cargas de trabalho da organização:
kubectl, automações e nós do cluster). Se exposto à Internet pública sem autenticação estrita, sem certificados mTLS ou permitindo requisições anônimas, torna-se a rota primária para tomada de controle do cluster.Em cada nó de trabalho, o agente kubelet opera com privilégios de superusuário no sistema operacional, gerenciando o ciclo de vida dos contêineres e comunicando-se com o runtime através da CRI (Container Runtime Interface):
169.254.169.254. Acesso ao IMDS (Instance Metadata Service) v1 permite que um pod comprometido roube as credenciais e papéis IAM (Identity and Access Management) do nó físico hospedeiro, escalando o ataque para o ambiente de nuvem da empresa.O mecanismo de RBAC (Role-Based Access Control) do Kubernetes é responsável por regular o acesso à API do cluster, definindo com precisão quem pode executar quais verbos operacionais sobre quais recursos em cada namespace.
O erro de modelagem mais comum em operações de Kubernetes é a concessão negligente de cluster-admin a usuários e contas de serviço, ou o uso excessivo de coringas (verbs: ["*"], resources: ["*"]) em manifestos de configuração para contornar problemas de permissão durante o desenvolvimento.
Diretrizes compulsórias para desenho de papéis de segurança:
RoleBinding confina a validade das permissões a um único namespace específico. O uso de ClusterRoleBinding estende o privilégio por todos os namespaces do cluster, expondo recursos sensíveis e pods administrativos de outros sistemas.["get", "list", "watch"]) e os recursos exatos (["pods", "services"]). Jamais use o asterisco para facilitar a implantação.pods, deployments ou daemonsets permite que um usuário crie um pod com montagem do sistema de arquivos raiz do host, escalando privilégios até root da máquina física. De forma similar, o verbo bind ou escalate sobre roles não pode ser concedido a usuários não administradores.Por padrão, todo namespace cria automaticamente uma conta de serviço chamada default. Em versões históricas do Kubernetes, o token JWT (JSON Web Token) associado a essa conta era injetado silenciosa e automaticamente em cada pod criado no diretório /var/run/secrets/kubernetes.io/serviceaccount/token.
Se a aplicação for comprometida, o invasor extrai esse token e ganha acesso imediato à API do Kubernetes com as permissões daquela ServiceAccount. A prática mandatória para aplicações de negócios que não realizam gestão programática do cluster consiste em desativar explicitamente o automount do token:
apiVersion: v1
kind: ServiceAccount
metadata:
name: payment-processor-sa
namespace: finance
# Desativa a injeção compulsória do token JWT nos contêineres do Pod
automountServiceAccountToken: false
O CIS (Center for Internet Security) publica o CIS Kubernetes Benchmark, referência internacional consagrada que define mais de 100 controles técnicos para auditoria e endurecimento operacional de clusters corporativos.
O arquivo de manifesto do kube-apiserver (comumente localizado em /etc/kubernetes/manifests/kube-apiserver.yaml em instalações baseadas em nós autônomos) deve ser parametrizado com as seguintes diretivas obrigatórias:
--anonymous-auth=false: Desativa integralmente qualquer requisição não autenticada à API do cluster. Toda solicitação deve comprovar identidade por certificado TLS ou token emitido por provedor OIDC (OpenID Connect).--profiling=false: Desativa a exposição de dados de profiling de depuração do processo, prevenindo o vazamento de ponteiros de memória e métricas internas que auxiliam ataques dirigidos.--authorization-mode=Node,RBAC: Restringe a autorização ao modo Node (que limita a atuação de kubelets aos pods alocados especificamente ao seu próprio nó) e ao RBAC formal. Modos legados e perigosos como AlwaysAllow devem ser terminantemente expurgados.--audit-log-path=/var/log/k8s/audit.log e --audit-policy-file=...: Ativa a trilha de auditoria estruturada, gravando em disco todas as operações solicitadas à API com registro de usuário, IP de origem, verbo, recurso e timestamp.Por padrão, o etcd persiste todos os recursos em formato de texto claro desprotegido. A obtenção de um backup desprotegido do etcd ou o acesso físico aos discos do servidor expõe imediatamente todos os segredos corporativos, certificados e chaves de API da instituição.
A blindagem exige a criação de uma EncryptionConfiguration, associada ao kube-apiserver através da flag --encryption-provider-config. O provedor recomendado para ambientes de alta segurança é a integração com um KMS (Key Management Service) externo via plugin gRPC, garantindo que as chaves de criptografia sejam rotacionadas periodicamente fora do ambiente do cluster:
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
- configmaps
providers:
- kms:
apiVersion: v2
name: corporate-kms-provider
endpoint: unix:///run/kms/kms.sock
- aescbc:
keys:
- name: primary-key
secret: dGVzdGUtc2VncmVkby1mb3J0ZS1jaWJlcmxhYi0yNTY=
- identity: {} # Permite a leitura de dados legados durante a migração
No arquivo de configuração /var/lib/kubelet/config.yaml presente em cada nó de trabalho, os seguintes parâmetros do CIS Benchmark devem ser confirmados:
authentication:
anonymous:
enabled: false # Proíbe acesso sem credenciais na porta 10250
webhook:
enabled: true
authorization:
mode: Webhook # Força validação das permissões de quem chama contra o API Server
protectKernelDefaults: true # Aborta a inicialização se os parâmetros de sysctl divergirem
readOnlyPort: 0 # Desativa a porta legada não autenticada 10255
A barreira mais eficaz para impedir que manifestos perigosos sejam aceitos pelo cluster é o controle de admissão (Admission Control). Os controladores de admissão interceptam requisições já autenticadas e autorizadas no kube-apiserver antes que qualquer modificação seja persistida no etcd.
Com a depreciação e remoção do antigo mecanismo de PodSecurityPolicies (PSP), o Kubernetes padronizou os Pod Security Standards (PSS), implementados nativamente pelo controlador Pod Security Admission (PSA). O PSS define três perfis de conformidade:
hostNetwork, hostPID, hostIPC e a montagem direta de volumes hostPath desprotegidos.Para aplicar o perfil restrito de forma compulsória em um namespace corporativo, utilizam-se labels de controle no próprio manifesto do namespace:
apiVersion: v1
kind: Namespace
metadata:
name: billing
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
Embora o PSS nativo seja indispensável, organizações corporativas demandam regras de governança customizadas que vão além da especificação básica de pods. O Kyverno é um mecanismo nativo do Kubernetes que executa políticas como código utilizando YAML declarativo tradicional, sem exigir o aprendizado de linguagens complexas adicionais.
O manifesto abaixo ilustra uma política do Kyverno que bloqueia a inicialização de qualquer contêiner cuja imagem provenha de repositórios públicos não autorizados ou que utilize tags genéricas mutáveis como latest:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: enforce-trusted-registry-and-tags
spec:
validationFailureAction: Enforce
rules:
- name: validate-registry-source
match:
any:
- resources:
kinds:
- Pod
validate:
message: "Imagens devem ser originadas exclusivamente do registro seguro corporativo ciberlab-registry.local."
pattern:
spec:
containers:
- image: "ciberlab-registry.local/*"
- name: disallow-latest-tag
match:
any:
- resources:
kinds:
- Pod
validate:
message: "O uso da tag mutável :latest é terminantemente proibido em produção."
pattern:
spec:
containers:
- image: "!*:latest"
Por especificação de design original, o modelo de rede do Kubernetes adota a premissa de conectividade total irrestrita (Flat Network): qualquer pod em qualquer namespace pode comunicar-se diretamente com qualquer outro pod em qualquer outro namespace por padrão.
Em uma rede plana desprotegida, caso um atacante obtenha sucesso explorando uma vulnerabilidade em um serviço web exposto ao público (tráfego norte-sul), ele pode iniciar imediatamente o reconhecimento interno e movimentação lateral (tráfego leste-oeste). Sem barreiras de isolamento, o servidor web comprometido conecta-se livremente a bancos de dados privados, filas de mensagens e APIs internas de outros departamentos.
A engenharia defensiva exige a aplicação do princípio do Default Deny (bloqueio padrão). Cada namespace deve possuir uma política inicial que feche integralmente todo o tráfego de entrada (Ingress) e todo o tráfego de saída (Egress):
# Política mandatória de isolamento total inicial do namespace
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all-traffic
namespace: finance
spec:
podSelector: {} # Aplica-se a 100% dos pods no namespace finance
policyTypes:
- Ingress
- Egress
Após a imposição do bloqueio universal, a equipe de engenharia cria manifestos adicionais de NetworkPolicy liberando cirurgicamente apenas os fluxos de rede indispensáveis para o serviço. Uma API de pagamentos, por exemplo, deve aceitar conexões exclusivamente na porta TCP 8443 a partir de pods rotulados como role: api-gateway, e emitir tráfego externo exclusivamente para o banco de dados institucional na porta TCP 5432 e para o serviço de DNS do cluster:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-ingress-gateway-and-egress-db
namespace: finance
spec:
podSelector:
matchLabels:
app: payment-service
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: ingress-system
podSelector:
matchLabels:
role: api-gateway
ports:
- protocol: TCP
port: 8443
egress:
- to:
- podSelector:
matchLabels:
app: postgres-database
ports:
- protocol: TCP
port: 5432
- to: # Liberação obrigatória de resolução DNS interna
- namespaceSelector: {}
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
O Kubernetes API Server aceita e armazena manifestos de NetworkPolicy independentemente da infraestrutura subjacente. Contudo, o componente responsável por fiscalizar e aplicar efetivamente as regras de bloqueio é o plugin de rede CNI (Container Network Interface). Plugins legados básicos (como Flannel sem canalização de extensão) ignoram silenciosamente as políticas sem emitir mensagens de erro. Utilize sempre CNIs corporativas com suporte nativo a eBPF e filtragem estrita, como Cilium ou Calico.
O recurso nativo Secret do Kubernetes é frequentemente incompreendido. Seus campos de dados não são protegidos por criptografia intrínseca na especificação do manifesto; são apenas codificados em Base64 simples (um método de representação reversível em fração de segundo sem qualquer chave secreta).
Práticas frágeis comumente observadas que devem ser prontamente eliminadas:
envFrom para expor segredos diretamente como variáveis de ambiente nos contêineres. Se a aplicação sofrer uma exceção de depuração não tratada (crash dump), sofrer um ataque de SSRF (Server-Side Request Forgery) ou expor rotas de status como /phpinfo ou /actuator/env, todas as credenciais são vazadas instantaneamente.A arquitetura recomendada pela indústria para microsserviços modernos consiste na dissociação total dos segredos da base de dados do Kubernetes, integrando os nós a um cofre de chaves corporativo externo (como HashiCorp Vault, AWS Secrets Manager ou Azure Key Vault) através do Secrets Store CSI Driver.
Por meio desse padrão, os segredos são buscados no cofre em tempo real e montados como um volume de memória volátil (tmpfs) exclusivamente no momento da inicialização do Pod, sem que nenhum segredo permanente seja gravado no etcd do cluster:
apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
name: vault-db-credentials
namespace: finance
spec:
provider: vault
parameters:
roleName: "finance-payment-role"
vaultAddress: "https://vault.internal.ciberlab:8200"
objects: |
- objectName: "db-password"
secretPath: "database/creds/payment-app"
secretKey: "password"
---
# Montagem do segredo como arquivo no Pod da aplicação
apiVersion: v1
kind: Pod
metadata:
name: payment-engine
namespace: finance
spec:
serviceAccountName: payment-processor-sa
containers:
- name: server
image: ciberlab-registry.local/apps/payment-service:v2.1.0
volumeMounts:
- name: secrets-store-inline
mountPath: "/mnt/secrets/database"
readOnly: true
volumes:
- name: secrets-store-inline
csi:
driver: secrets-store.csi.k8s.io
readOnly: true
volumeAttributes:
secretProviderClass: "vault-db-credentials"
Essa abordagem viabiliza a rotação automatizada e transparente de credenciais sem reinicialização forçada do pod, reduzindo a validade temporal de tokens vazados.
O endurecimento operacional de contêineres e orquestração Kubernetes não constitui um evento pontual de configuração estática, mas um ciclo disciplinado e contínuo de engenharia defensiva, governança de políticas e observabilidade em tempo real.
Enquanto mecanismos estáticos como Seccomp e Pod Security Standards bloqueiam violações preventivas de configurações conhecidas, a detecção de ameaças sofisticadas em tempo de execução exige instrumentação comportamental contínua. O uso da tecnologia eBPF (Extended Berkeley Packet Filter) permite que motores de detecção como o Falco capturem todas as chamadas de sistema no núcleo do hospedeiro com sobrecarga de processamento desprezível.
O monitoramento contínuo deve gerar alertas imediatos para incidentes como:
bash, sh) dentro de contêineres em produção./bin, /sbin, /usr).A blindagem da infraestrutura de contêineres consolida-se através da implementação harmoniosa de três pilares estruturais:
1. Higiene na Origem
Construção de imagens com bases distroless mínimas, descarte absoluto de compiladores via multi-stage builds, geração compulsória de SBOM e assinatura criptográfica com Cosign na esteira de CI/CD.
2. Barreira no Ponto de Admissão
Aplicação compulsória de Pod Security Standards no nível Restricted, governança declarativa com Kyverno e bloqueio inegociável de contêineres root, privileged ou sem limites de recursos.
3. Blindagem de Rede e Runtime
Microssegmentação leste-oeste com políticas de default-deny, mTLS entre microsserviços, segredos fornecidos sob demanda via cofre externo e telemetria de detecção baseada em eBPF.
Engenharia, disciplina de configuração e automação de conformidade constituem as únicas salvaguardas reais para sustentar sistemas digitais seguros, resilientes e escaláveis.
Este checklist resume os controles essenciais de conformidade técnica abordados nesta cartilha. Ele deve ser utilizado por administradores de infraestrutura, arquitetos de nuvem e auditores de segurança para validar a prontidão operacional de novos contêineres e clusters antes da sua liberação para produção.
| Domínio de Controle | Requisito Técnico | Critério de Conformidade | Status |
|---|---|---|---|
| Construção de Imagens | Uso de Imagens Mínimas | Imagens baseadas em Distroless ou scratch; ausência total de gerenciadores de pacotes e interpretadores. | [ ] |
| Construção de Imagens | Compilação Multi-Stage | Ferramentas de build e código-fonte descartados no primeiro estágio; somente artefatos binários na imagem final. | [ ] |
| Cadeia de Suprimentos | Geração e Verificação de SBOM | Arquivo SBOM gerado em formato SPDX/CycloneDX e armazenado junto ao artefato no registro OCI corporativo. | [ ] |
| Cadeia de Suprimentos | Assinatura Digital com Cosign | Imagens assinadas criptograficamente na esteira de CI/CD; controle de admissão bloqueia imagens sem assinatura. | [ ] |
| Runtime de Contêiner | Execução como Non-Root | Diretiva runAsNonRoot: true declarada e UID fixado explicitamente acima de 10000; root desativado. |
[ ] |
| Runtime de Contêiner | Bloqueio de Elevação de Privilégio | Flag allowPrivilegeEscalation: false aplicada compulsória em todos os contêineres de todos os pods. |
[ ] |
| Isolamento de Kernel | Descarte de Linux Capabilities | Diretiva drop: ["ALL"] declarada; reintrodução apenas cirúrgica e justificada tecnicamente. |
[ ] |
| Isolamento de Kernel | Filtragem com Seccomp | Perfil RuntimeDefault ativado nativamente em 100% dos pods do ambiente. |
[ ] |
| Isolamento de Kernel | Sistema de Arquivos Read-Only | Parâmetro readOnlyRootFilesystem: true ativo; escrita restrita a volumes voláteis emptyDir. |
[ ] |
| Orquestração K8s | Pod Security Standards | Namespaces corporativos rotulados com modo enforce: restricted. |
[ ] |
| Orquestração K8s | Governança com Kyverno | Políticas de cluster aplicadas para banir tags mutáveis (latest) e registros públicos não homologados. |
[ ] |
| Controle de Acesso | Privilégio Mínimo em RBAC | Uso de RoleBinding no lugar de ClusterRoleBinding; ausência total de coringas de permissão (*). |
[ ] |
| Controle de Acesso | Restrição de ServiceAccounts | Diretiva automountServiceAccountToken: false ativada em pods que não dialogam com a API do cluster. |
[ ] |
| Blindagem do Nó | Segurança da API do Kubelet | Acesso anônimo desativado na porta 10250; autorização em modo Webhook; porta somente leitura desativada. | [ ] |
| Control Plane | Criptografia de Dados no etcd | Provedor de criptografia em repouso ativo no kube-apiserver para objetos secrets e configmaps. |
[ ] |
| Rede e Firewall | Políticas de Default-Deny | NetworkPolicy padrão de bloqueio total de Ingress e Egress aplicada em cada namespace corporativo. | [ ] |
| Rede e Firewall | Liberação Granular de Tráfego | Comunicação leste-oeste liberada exclusivamente entre pods homologados com restrição estrita de portas TCP/UDP. | [ ] |
| Gestão de Segredos | Isolamento com Cofre Externo | Utilização do Secrets Store CSI Driver integrado ao HashiCorp Vault; eliminação de senhas em variáveis de ambiente. | [ ] |
| Observabilidade | Detecção de Anomalias com eBPF | Instrumentação com Falco em tempo de execução para alertar spawn de shells interativos e acessos não conformes. | [ ] |
Cartilha CiberLab · Ciência Embarcada · Lucas Rayan Guerra