Os 10 riscos de segurança mais críticos em ambientes Kubernetes e como mitigá-los.
O OWASP Kubernetes Top 10 identifica os riscos de segurança mais significativos em ambientes Kubernetes. O Kubernetes se tornou o padrão de fato para orquestração de contêineres, mas sua flexibilidade e complexidade introduzem numerosos desafios de segurança. Este guia abrange configurações incorretas de cargas de trabalho, problemas de RBAC, gerenciamento de secrets, segmentação de rede e muito mais.
Configurações inseguras de cargas de trabalho são o problema de segurança mais comum do Kubernetes. Contêineres executando como root, com privilégios excessivos, sistemas de arquivos graváveis ou sem limites de recursos criam superfícies de ataque significativas. Configurações padrão são frequentemente inseguras e devem ser explicitamente endurecidas.
Um contêiner comprometido com privilégios root e acesso ao host pode escapar da sandbox do contêiner, acessar o sistema de arquivos do host e pivotar para outras cargas de trabalho. Escalação de privilégios a partir de um pod mal configurado pode levar ao comprometimento completo do cluster.
apiVersion: v1 kind: Pod metadata: name: insecure-app spec: containers: - name: app image: myapp:latest # Mutable tag! securityContext: privileged: true # Full host access! runAsUser: 0 # Running as root! volumeMounts: - mountPath: /host name: host-fs volumes: - name: host-fs hostPath: path: / # Entire host filesystem!
apiVersion: v1 kind: Pod metadata: name: secure-app spec: securityContext: runAsNonRoot: true seccompProfile: type: RuntimeDefault containers: - name: app image: myapp@sha256:abc123... # Immutable digest securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true runAsUser: 1000 capabilities: drop: ["ALL"] resources: limits: cpu: "500m" memory: "256Mi" requests: cpu: "100m" memory: "128Mi"
O RBAC (Role-Based Access Control) do Kubernetes é poderoso, mas complexo. Funções excessivamente permissivas Eespecialmente bindings de cluster-admin, permissões curinga e privilégios excessivos de service account Epermitem acesso não autorizado a recursos do cluster, secrets e cargas de trabalho.
Um atacante que obtém acesso a uma service account super privilegiada pode listar secrets, criar pods privilegiados, modificar deployments e escalar para cluster-admin. Regras RBAC curinga são o equivalente Kubernetes de conceder acesso root.
# ClusterRoleBinding granting cluster-admin to a service account apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: app-admin-binding subjects: - kind: ServiceAccount name: my-app # App SA with cluster-admin! namespace: default roleRef: kind: ClusterRole name: cluster-admin # Full cluster control! apiGroup: rbac.authorization.k8s.io
# Scoped Role with minimum required permissions apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: app-role namespace: my-app-ns rules: - apiGroups: [""] resources: ["configmaps"] verbs: ["get", "list"] # Read-only, specific resources resourceNames: ["app-config"] # Named resource only --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: app-role-binding namespace: my-app-ns subjects: - kind: ServiceAccount name: my-app namespace: my-app-ns roleRef: kind: Role name: app-role apiGroup: rbac.authorization.k8s.io
Secrets do Kubernetes são apenas codificados em base64 por padrão, não criptografados. Armazenar dados sensíveis (chaves de API, senhas de banco de dados, certificados TLS) em ConfigMaps simples, variáveis de ambiente ou Secrets não criptografados os expõe a qualquer pessoa com acesso à API. Secrets também são visíveis no etcd se a criptografia em repouso não estiver habilitada.
Secrets expostos permitem que atacantes acessem bancos de dados, contas cloud e serviços externos. Secrets armazenados no etcd sem criptografia podem ser lidos por qualquer pessoa com acesso ao etcd. Secrets em variáveis de ambiente são visíveis nas specs de pods e listagens de processos.
# Secret in plain ConfigMap Evisible to anyone apiVersion: v1 kind: ConfigMap metadata: name: app-config data: DB_PASSWORD: "SuperSecret123!" # Plaintext password! API_KEY: "sk-live-abc123xyz" # API key in ConfigMap! --- apiVersion: v1 kind: Pod metadata: name: app spec: containers: - name: app image: myapp:latest envFrom: - configMapRef: name: app-config # All values as env vars!
# Use External Secrets Operator with a vault backend apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: app-secrets spec: refreshInterval: 1h secretStoreRef: name: vault-backend kind: ClusterSecretStore target: name: app-secrets data: - secretKey: db-password remoteRef: key: secret/myapp/db property: password --- apiVersion: v1 kind: Pod metadata: name: app spec: containers: - name: app image: myapp@sha256:abc123... volumeMounts: - name: secrets mountPath: /etc/secrets readOnly: true # Mount as read-only files volumes: - name: secrets secret: secretName: app-secrets
Sem políticas em nível de cluster, não há barreiras de proteção prevenindo o deployment de cargas de trabalho inseguras. Pod Security Standards (PSS), admission controllers e motores de políticas como OPA Gatekeeper ou Kyverno são essenciais para aplicar baselines de segurança em todos os namespaces.
Sem aplicação de políticas, qualquer desenvolvedor pode fazer deploy de contêineres privilegiados, usar volumes hostPath ou desabilitar controles de segurança. Uma única carga de trabalho mal configurada pode comprometer todo o cluster. Revisão manual não escala para detectar todas as violações.
#!/bin/bash # No admission control Eany pod spec is accepted # No Pod Security Standards configured # Anyone can deploy a privileged container kubectl run hacker-pod --image=alpine \ --overrides='{"spec":{"containers":[{ "name":"hack", "image":"alpine", "securityContext":{"privileged":true}, "command":["nsenter","--target","1","--mount","--uts","--ipc","--net","--pid","--","bash"] }]}}' # No policy blocks this Enow has host root access!
# Enforce Pod Security Standards with Kyverno apiVersion: kyverno.io/v1 kind: ClusterPolicy metadata: name: disallow-privileged spec: validationFailureAction: Enforce background: true rules: - name: deny-privileged match: any: - resources: kinds: ["Pod"] validate: message: "Privileged containers are not allowed." pattern: spec: containers: - securityContext: privileged: "false" - name: require-run-as-non-root match: any: - resources: kinds: ["Pod"] validate: message: "Containers must run as non-root." pattern: spec: securityContext: runAsNonRoot: true
Por padrão, todos os pods em um cluster Kubernetes podem se comunicar entre si sem qualquer restrição. Esta arquitetura de rede plana significa que um pod comprometido pode alcançar qualquer outro pod, serviço ou até mesmo o servidor de API do Kubernetes. Network Policies são essenciais para implementar microssegmentação.
Sem segmentação de rede, movimento lateral é trivial. Um pod frontend comprometido pode acessar diretamente bancos de dados backend, serviços internos e a API de metadados (169.254.169.254). Isso viola o princípio do menor privilégio na camada de rede.
# No NetworkPolicy Eall pods can communicate freely apiVersion: v1 kind: Namespace metadata: name: production # No default deny policy # No network policies at all # Any pod can reach: # - Other pods in any namespace # - Kubernetes API server # - Cloud metadata API (169.254.169.254) # - External internet
# Default deny all ingress and egress apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny-all namespace: production spec: podSelector: {} policyTypes: ["Ingress", "Egress"] --- # Allow only frontend to backend communication apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-frontend-to-backend namespace: production spec: podSelector: matchLabels: app: backend policyTypes: ["Ingress"] ingress: - from: - podSelector: matchLabels: app: frontend ports: - port: 8080 protocol: TCP
Componentes do control plane do Kubernetes (API server, etcd, kubelet, dashboard) e serviços de aplicação podem ser inadvertidamente expostos à internet ou redes não confiáveis. Dashboards expostos, kubelets não autenticados e API servers publicamente acessíveis são vetores de ataque comuns.
Componentes Kubernetes expostos fornecem acesso direto ao gerenciamento do cluster. Uma API kubelet não autenticada permite execução de contêineres. Um dashboard exposto com credenciais padrão concede acesso cluster-admin. Acesso público ao etcd expõe todos os dados do cluster incluindo secrets.
# Kubernetes Dashboard exposed via LoadBalancer apiVersion: v1 kind: Service metadata: name: kubernetes-dashboard namespace: kubernetes-dashboard spec: type: LoadBalancer # Public internet access! ports: - port: 443 targetPort: 8443 selector: k8s-app: kubernetes-dashboard # Dashboard bound to cluster-admin service account # No authentication required Efull cluster access!
# Dashboard accessible only via kubectl proxy apiVersion: v1 kind: Service metadata: name: kubernetes-dashboard namespace: kubernetes-dashboard spec: type: ClusterIP # Internal only ports: - port: 443 targetPort: 8443 selector: k8s-app: kubernetes-dashboard --- # Access via: kubectl proxy, then browse to: # http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/ # Or use kubectl port-forward for secure access
Clusters Kubernetes consistem em muitos componentes: API server, etcd, kubelet, kube-proxy, CoreDNS e add-ons de terceiros (Ingress controllers, service meshes, monitoramento). Componentes mal configurados ou sem patches introduzem vulnerabilidades. Configurações padrão frequentemente não são endurecidas.
Componentes vulneráveis do cluster podem ser explorados para execução remota de código, escalação de privilégios ou negação de serviço. CVEs no kubelet, Ingress controllers ou plugins CNI podem levar a escapes de contêiner e takeover do cluster. Componentes desatualizados acumulam vulnerabilidades conhecidas.
# kubelet with insecure configuration # /var/lib/kubelet/config.yaml apiVersion: kubelet.config.k8s.io/v1beta1 kind: KubeletConfiguration authentication: anonymous: enabled: true # Anyone can access kubelet API! webhook: enabled: false # No authorization! authorization: mode: AlwaysAllow # All requests permitted! readOnlyPort: 10255 # Unauthenticated read port open!
# Hardened kubelet configuration apiVersion: kubelet.config.k8s.io/v1beta1 kind: KubeletConfiguration authentication: anonymous: enabled: false # Deny anonymous access webhook: enabled: true # Use API server for auth x509: clientCAFile: /etc/kubernetes/pki/ca.crt authorization: mode: Webhook # API server authorizes requests readOnlyPort: 0 # Disable read-only port protectKernelDefaults: true eventRecordQPS: 5
Clusters Kubernetes executando em ambientes cloud (AWS, GCP, Azure) podem acessar APIs de metadados cloud e funções IAM anexadas aos nós. Atacantes que comprometem um pod podem usar estes para escalar privilégios do cluster para a conta cloud, acessando buckets S3, bancos de dados e outros serviços cloud.
Funções IAM em nível de nó são herdadas por todos os pods naquele nó. Um pod comprometido pode consultar a API de metadados (169.254.169.254) para obter credenciais cloud, e então acessar qualquer recurso cloud que a função do nó permitir. Isso habilita movimento lateral do Kubernetes para o ambiente cloud mais amplo.
# Node IAM role with excessive permissions resource "aws_iam_role_policy_attachment" "node_admin" { role = aws_iam_role.node_role.name policy_arn = "arn:aws:iam::aws:policy/AdministratorAccess" # All pods on this node inherit admin access! } # No IMDS restrictions Eany pod can get node credentials # curl http://169.254.169.254/latest/meta-data/iam/security-credentials/
# Use IAM Roles for Service Accounts (IRSA) resource "aws_iam_role" "app_role" { name = "my-app-role" assume_role_policy = jsonencode({ Version = "2012-10-17" Statement = [{ Effect = "Allow" Principal = { Federated = aws_iam_openid_connect_provider.eks.arn } Action = "sts:AssumeRoleWithWebIdentity" Condition = { StringEquals = { "${aws_iam_openid_connect_provider.eks.url}:sub" = "system:serviceaccount:my-ns:my-app" } } }] }) } # Pod-level scoped IAM via service account annotation # Only this specific pod gets these specific permissions
Kubernetes suporta múltiplos mecanismos de autenticação: certificados, tokens, OIDC e autenticação webhook. Autenticação quebrada inclui uso de tokens estáticos, compartilhamento de arquivos kubeconfig, não rotacionar certificados e falha ao integrar com provedores de identidade. Montagem automática de tokens de service account cria superfície de ataque desnecessária.
Arquivos kubeconfig e tokens de service account roubados ou vazados fornecem acesso direto ao cluster. Tokens estáticos que nunca expiram dão acesso persistente. Sem gerenciamento centralizado de identidade, revogar acesso para membros da equipe que saíram é difícil e propenso a erros.
# Static token file for API server authentication # /etc/kubernetes/token-auth-file.csv # token,user,uid,"groups" # abc123,admin,1,"system:masters" # Static token, never expires! # Pod with auto-mounted service account token apiVersion: v1 kind: Pod metadata: name: app spec: # automountServiceAccountToken defaults to true! # Token mounted at /var/run/secrets/kubernetes.io/serviceaccount/token containers: - name: app image: myapp:latest # App doesn't need K8s API access but has a token anyway
# Disable auto-mounted token for pods that don't need API access apiVersion: v1 kind: ServiceAccount metadata: name: my-app namespace: my-app-ns automountServiceAccountToken: false # No auto-mount --- # For pods that need API access, use bound tokens with expiry apiVersion: v1 kind: Pod metadata: name: api-consumer spec: serviceAccountName: api-consumer-sa automountServiceAccountToken: false containers: - name: app image: myapp@sha256:abc123... volumeMounts: - name: token mountPath: /var/run/secrets/tokens readOnly: true volumes: - name: token projected: sources: - serviceAccountToken: expirationSeconds: 3600 # 1-hour expiry audience: api-server
Kubernetes gera eventos de auditoria para requisições ao API server, mas audit logging frequentemente está desabilitado ou mal configurado. Sem logging e monitoramento adequados, atividades maliciosas Ecomo acesso não autorizado a secrets, mudanças RBAC e escapes de contêiner Epassam despercebidas. Monitoramento de segurança em runtime no nível de contêiner e nó é essencial.
Sem audit logging, atacantes operam sem serem detectados. Eles podem criar service accounts backdoor, extrair secrets e modificar cargas de trabalho sem qualquer registro. Resposta a incidentes é severamente prejudicada quando não há trilha de auditoria para determinar o que aconteceu, quando e por quem.
# API server with no audit logging configured # kube-apiserver flags: # --audit-log-path="" # No audit log! # --audit-policy-file="" # No audit policy! # No runtime security monitoring # No alerting on suspicious activities # Container logs not collected centrally # Default log retention Elogs lost on pod restart
# Comprehensive audit policy apiVersion: audit.k8s.io/v1 kind: Policy rules: # Log all secret access at Metadata level - level: Metadata resources: - group: "" resources: ["secrets"] # Log RBAC changes at RequestResponse level - level: RequestResponse resources: - group: rbac.authorization.k8s.io resources: ["clusterroles", "clusterrolebindings", "roles", "rolebindings"] # Log pod exec/attach (potential attacks) - level: Request resources: - group: "" resources: ["pods/exec", "pods/attach", "pods/portforward"] # Default: log at Metadata level - level: Metadata
| ID | Vulnerabilidade | Severidade | Mitigação Chave |
|---|---|---|---|
| K01 | Configurações Inseguras de Cargas de Trabalho | Critical | Não-root, FS somente leitura, remover capabilities, limites de recursos |
| K02 | Autorização Excessivamente Permissiva | Critical | RBAC com escopo de namespace, sem curingas, auditar bindings |
| K03 | Falhas no Gerenciamento de Secrets | Critical | Secrets externos, criptografia em repouso, montagem de arquivos |
| K04 | Falta de Aplicação de Políticas | High | Pod Security Standards, Kyverno/OPA Gatekeeper |
| K05 | Segmentação de Rede Ausente | High | NetworkPolicies default-deny, microssegmentação |
| K06 | Componentes Excessivamente Expostos | High | Serviços ClusterIP, kubectl proxy, regras de firewall |
| K07 | Componentes de Cluster Mal Configurados | High | CIS Benchmark, desabilitar auth anônima, gerenciamento de patches |
| K08 | Movimento Lateral de Cluster para Cloud | Critical | IRSA/Workload Identity, bloquear API de metadados, IMDSv2 |
| K09 | Mecanismos de Autenticação Quebrados | Critical | Integração OIDC, tokens vinculados, desabilitar auto-mount |
| K10 | Logging e Monitoramento Inadequados | Medium | Audit logging, Falco/Tetragon, integração SIEM |