Secrets rotation automática: renovando credenciais sem downtime
1. Fundamentos da Rotação de Secrets em Kubernetes
1.1. O problema: credenciais estáticas e riscos de vazamento
Em ambientes Kubernetes, é comum que equipes criem Secrets e os mantenham imutáveis por meses ou anos. Essa abordagem estática representa um risco grave de segurança: se uma credencial for exposta em logs, repositórios Git ou clusters comprometidos, a janela de exploração é indefinida. Além disso, regulamentações como SOC 2, PCI-DSS e ISO 27001 exigem rotação periódica de credenciais.
1.2. Conceitos de rotação: manual vs. automática vs. contínua
- Rotação manual: operador edita o Secret, reinicia pods manualmente. Alto risco de erro humano e downtime.
- Rotação automática: ferramentas como External Secrets Operator (ESO) atualizam Secrets no cluster, e controllers como Reloader reiniciam pods automaticamente.
- Rotação contínua: credenciais com TTL curto (ex.: Vault Dynamic Secrets), renovadas antes da expiração, sem intervenção humana.
1.3. Desafios de downtime em aplicações stateful e stateless
Aplicações stateless (APIs REST) toleram reinicializações rápidas via rolling update. Já aplicações stateful (bancos de dados, filas) exigem cuidado: fechar conexões ativas sem perda de dados, migrar sessões e garantir que credenciais antigas ainda sejam aceitas durante a transição.
2. Estratégias de Rotação sem Interrupção
2.1. Blue-green deployment de secrets com múltiplas versões
Crie dois Secrets: db-creds-v1 e db-creds-v2. O Deployment referencia ambos via envFrom com chaves sobrepostas. Durante a rotação, a aplicação tenta conectar com a nova credencial; se falhar, usa a antiga.
apiVersion: v1
kind: Secret
metadata:
name: db-creds-v1
data:
DB_PASSWORD: cGFzc3dvcmQxMjM=
---
apiVersion: v1
kind: Secret
metadata:
name: db-creds-v2
data:
DB_PASSWORD: cGFzc3dvcmQ0NTY=
2.2. Dual lease pattern: coexistência de credenciais antigas e novas
O banco de dados ou serviço externo deve aceitar ambas as credenciais por um período de transição (ex.: 10 minutos). A aplicação tenta a nova; se falha, fallback para a antiga. Após o grace period, a credencial antiga é revogada.
2.3. Grace period e TTL para transição segura
Defina um TTL para a credencial antiga no Vault (ex.: 5 minutos após a emissão da nova). Durante esse período, ambas funcionam. O Kubernetes Sidecar ou InitContainer aguarda o TTL expirar antes de remover a credencial antiga do pod.
3. Ferramentas de Gerenciamento de Secrets no Cluster
3.1. External Secrets Operator (ESO) com HashiCorp Vault ou AWS Secrets Manager
ESO sincroniza secrets de fontes externas para o cluster. Exemplo com Vault:
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: vault-example
spec:
refreshInterval: "1h"
secretStoreRef:
name: vault-backend
kind: ClusterSecretStore
target:
name: database-creds
data:
- secretKey: password
remoteRef:
key: secret/data/db
property: password
Quando o secret no Vault é rotacionado, o ESO atualiza o Secret do Kubernetes no próximo ciclo de refresh.
3.2. Sealed Secrets e SOPS para criptografia GitOps
Sealed Secrets permitem armazenar secrets criptografados no Git. O controller decripta apenas dentro do cluster. Para rotação, basta atualizar o SealedSecret no repositório Git e aplicar via ArgoCD.
3.3. CSI Drivers: montando secrets como volumes sem reinicialização de pods
O Secrets Store CSI Driver monta secrets como volumes efêmeros. Quando o secret externo é atualizado, o driver atualiza o conteúdo do volume sem reiniciar o pod. A aplicação precisa monitorar o arquivo montado para reload automático.
apiVersion: v1
kind: Pod
metadata:
name: app-with-csi
spec:
containers:
- name: app
image: myapp:latest
volumeMounts:
- name: secrets-store
mountPath: "/mnt/secrets"
readOnly: true
volumes:
- name: secrets-store
csi:
driver: secrets-store.csi.k8s.io
readOnly: true
volumeAttributes:
secretProviderClass: "vault-database"
4. Implementação com Kubernetes Native + Controllers
4.1. Reloader: reinicialização automática de Deployments após mudança de Secrets
Stakater Reloader observa mudanças em Secrets e ConfigMaps e realiza rolling update nos Deployments que os referenciam.
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
annotations:
reloader.stakater.com/auto: "true"
spec:
template:
spec:
containers:
- name: app
envFrom:
- secretRef:
name: database-creds
Quando database-creds é atualizado, o Reloader incrementa uma anotação de configuração, forçando o rollout.
4.2. Stakater Reloader vs. custom webhooks para injeção dinâmica
Reloader é simples e amplamente usado. Para cenários onde reinicialização não é aceitável, use um mutating admission webhook que injeta um sidecar que faz reload da aplicação via signal (SIGHUP) ou API interna.
4.3. Rolling update estratégico: health checks e readiness probes
Configure probes para que o novo pod só receba tráfego quando estiver usando a nova credencial:
readinessProbe:
exec:
command:
- sh
- -c
- "pg_isready -h localhost -U app -d mydb"
initialDelaySeconds: 5
periodSeconds: 10
5. Rotação de Database Credentials sem Downtime
5.1. Padrão sidecar com proxy de banco (PgBouncer, ProxySQL)
Um sidecar PgBounger gerencia o pool de conexões. Durante a rotação, o sidecar atualiza a senha interna e reconecta gradualmente ao banco, sem que a aplicação precise ser reiniciada.
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-with-pgbouncer
spec:
template:
spec:
containers:
- name: app
env:
- name: DB_HOST
value: "127.0.0.1"
- name: DB_PORT
value: "5432"
- name: pgbouncer
image: bitnami/pgbouncer:latest
volumeMounts:
- name: pgbouncer-config
mountPath: "/opt/bitnami/pgbouncer/conf"
5.2. Rotação de senhas via Vault Dynamic Secrets
Vault gera senhas temporárias para bancos. O sidecar Vault Agent renova o token e reconfigura o proxy automaticamente.
apiVersion: v1
kind: Pod
metadata:
annotations:
vault.hashicorp.com/agent-inject: "true"
vault.hashicorp.com/role: "app-role"
vault.hashicorp.com/agent-inject-secret-database: "database/creds/app"
spec:
containers:
- name: app
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: vault-db-creds
key: password
5.3. Migração gradual de conexões ativas com pool de conexões
Configure o pool de conexões da aplicação para usar duas credenciais: primária (nova) e fallback (antiga). Feche conexões antigas gradativamente, respeitando transações em andamento.
6. Monitoramento e Validação da Rotação
6.1. Métricas de sucesso: tempo de rotação, pods atualizados, falhas
Exporte métricas via Prometheus:
secret_rotation_duration_seconds— tempo entre início da rotação e todos os pods atualizadossecret_rotation_pods_updated— contagem de pods com nova credencialsecret_rotation_failures_total— falhas de rotação
6.2. Alertas para secrets expirados ou rotação mal-sucedida
Crie alertas no Prometheus + Alertmanager:
groups:
- name: secrets-alerts
rules:
- alert: SecretExpired
expr: time() - secret_last_rotation_timestamp > 86400 * 30
for: 1h
labels:
severity: critical
annotations:
summary: "Secret {{ $labels.secret_name }} não foi rotacionado nos últimos 30 dias"
6.3. Testes de integração automatizados pós-rotação
Execute um job Kubernetes após cada rotação que valide:
- Conexão ao banco com nova credencial
- Conexão ao banco com credencial antiga falha (após grace period)
- Métricas de erro zero nos últimos 5 minutos
7. Casos Avançados e Boas Práticas
7.1. Rotação de TLS certificates com cert-manager + ACME
cert-manager renova certificados automaticamente antes da expiração. Configure renewBefore para renovar 30 dias antes:
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: my-cert
spec:
secretName: my-cert-tls
renewBefore: 720h # 30 dias
dnsNames:
- myapp.example.com
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
7.2. Rotação de tokens de serviço (ServiceAccount, OIDC)
Use TokenRequest API para tokens com TTL curto. Configure o pod para renovar o token antes da expiração:
apiVersion: v1
kind: Pod
metadata:
annotations:
kubernetes.io/enforce-mountable-secrets: "true"
spec:
automountServiceAccountToken: true
containers:
- name: app
env:
- name: K8S_TOKEN
valueFrom:
fieldRef:
fieldPath: spec.serviceAccountName
7.3. GitOps workflow: ArgoCD + External Secrets para rotação declarativa
No GitOps, defina o ExternalSecret no Git. Quando o secret no Vault é rotacionado, o ESO atualiza o Secret no cluster. O Reloader reinicia os pods. Tudo declarativo e auditável.
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: my-app
spec:
source:
repoURL: https://github.com/myorg/gitops-config
path: apps/my-app
syncPolicy:
automated:
prune: true
selfHeal: true
Referências
- External Secrets Operator Documentation — Documentação oficial do ESO, incluindo providers como Vault, AWS Secrets Manager e Azure Key Vault.
- Stakater Reloader GitHub — Controller que reinicia pods automaticamente quando Secrets ou ConfigMaps são alterados.
- HashiCorp Vault Dynamic Secrets — Guia oficial para geração de senhas temporárias para bancos de dados.
- cert-manager Documentation — Documentação oficial para rotação automática de certificados TLS com ACME e Issuers customizados.
- Secrets Store CSI Driver — Driver que monta secrets como volumes sem reinicialização de pods, suportando AWS, Azure e GCP.
- Kubernetes Secrets Best Practices — Guia oficial da Kubernetes sobre práticas recomendadas para Secrets.
- ArgoCD + External Secrets Integration — Tutorial de como integrar ArgoCD com External Secrets para GitOps seguro.