ConfigMaps e Secrets em Kubernetes: Gerenciando Configuração
Quando você trabalha com Kubernetes em produção, rapidamente percebe que hardcoding configurações dentro de imagens Docker é uma péssima prática. ConfigMaps e Secrets são os mecanismos nativos do Kubernetes para separar dados de configuração da lógica da aplicação. A diferença fundamental é simples: ConfigMaps armazenam dados não-sensíveis em texto plano, enquanto Secrets são projetados para dados sensíveis como senhas e tokens, com suporte a encoding em base64.
Neste artigo, vou guiá-lo através dos conceitos práticos, mostrando como estruturar suas aplicações para aproveitar essas ferramentas corretamente. Você aprenderá não apenas a sintaxe, mas o porquê dessas decisões arquiteturais importam para escalabilidade e manutenção.
Entendendo ConfigMaps: Configuração sem Sensibilidade
O que é um ConfigMap e quando usá-lo
Um ConfigMap é um objeto Kubernetes que permite armazenar dados de configuração em pares chave-valor. Pense nele como um arquivo de properties ou um arquivo .env que vive dentro do cluster e pode ser montado em seus Pods. O uso mais comum é para variáveis de ambiente que mudam entre ambientes (desenvolvimento, staging, produção), como URLs de bancos de dados, timeouts, níveis de log, e parâmetros de aplicação.
A vantagem de usar ConfigMaps é que você pode atualizar configurações sem recriar suas imagens Docker. Você muda o ConfigMap, e na próxima vez que o Pod for criado ou reiniciado, ele recebe a nova configuração. Isso acelera o ciclo de desenvolvimento e reduz significativamente o tamanho e complexidade das imagens.
Criando ConfigMaps: Métodos Práticos
Existem várias formas de criar um ConfigMap. A mais simples é usar argumentos diretos no kubectl:
kubectl create configmap app-config \
--from-literal=DATABASE_URL=postgresql://db:5432/myapp \
--from-literal=LOG_LEVEL=info \
--from-literal=MAX_CONNECTIONS=100
Para configurações mais complexas ou que vêm de arquivos, você pode usar a abordagem declarativa com YAML:
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
namespace: production
data:
DATABASE_URL: postgresql://db:5432/myapp
LOG_LEVEL: info
MAX_CONNECTIONS: "100"
app.properties: |
server.port=8080
server.shutdown=graceful
cache.ttl.seconds=3600
Note que chaves com conteúdo multilinhas (como app.properties) usam o pipe |. Quando você tem arquivos inteiros de configuração, pode referenciá-los diretamente:
kubectl create configmap nginx-config --from-file=nginx.conf --from-file=default.conf
Consumindo ConfigMaps em Pods
Uma vez criado, você pode injetar ConfigMaps em seus Pods de duas formas principais. Como variáveis de ambiente é a mais comum:
apiVersion: v1
kind: Pod
metadata:
name: my-app
spec:
containers:
- name: app
image: myapp:1.0
env:
- name: DATABASE_URL
valueFrom:
configMapKeyRef:
name: app-config
key: DATABASE_URL
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: app-config
key: LOG_LEVEL
Ou você pode expor todas as chaves do ConfigMap de uma só vez usando envFrom:
apiVersion: v1
kind: Pod
metadata:
name: my-app
spec:
containers:
- name: app
image: myapp:1.0
envFrom:
- configMapRef:
name: app-config
A segunda abordagem é montar o ConfigMap como um volume, útil quando você precisa de arquivos completos de configuração:
apiVersion: v1
kind: Pod
metadata:
name: nginx-app
spec:
containers:
- name: nginx
image: nginx:latest
volumeMounts:
- name: config-volume
mountPath: /etc/nginx/conf.d
volumes:
- name: config-volume
configMap:
name: nginx-config
Neste caso, cada chave do ConfigMap vira um arquivo dentro do diretório /etc/nginx/conf.d. Se o ConfigMap tiver uma chave default.conf, você encontrará um arquivo /etc/nginx/conf.d/default.conf dentro do container.
Secrets: Protegendo Dados Sensíveis
Diferenças entre ConfigMap e Secret
Enquanto ConfigMaps são para dados públicos, Secrets são para informações sensíveis: senhas de banco de dados, tokens de API, chaves SSH, certificados TLS. A principal diferença técnica é que Secrets são armazenados em base64 por padrão (etcd) e o Kubernetes oferece opções de criptografia em repouso. Porém, não confunda base64 com encriptação: base64 é apenas encoding, não oferece segurança real.
Se você precisa de segurança real, você deve configurar encriptação em repouso no etcd. Mas mesmo com base64, Secrets têm um propósito importante: separam dados sensíveis de dados públicos, facilitam rotação de credenciais, e permitem controles RBAC (Role-Based Access Control) mais granulares.
Criando Secrets de Forma Segura
Para criar um Secret com dados sensíveis, use kubectl create secret:
kubectl create secret generic db-credentials \
--from-literal=username=admin \
--from-literal=password=mysecurepassword123
Ou de forma declarativa (mas cuidado com o controle de versão!):
apiVersion: v1
kind: Secret
metadata:
name: db-credentials
type: Opaque
data:
username: YWRtaW4= # base64 encoded "admin"
password: bXlzZWN1cmVwYXNzd29yZDEyMw== # base64 encoded "mysecurepassword123"
Para gerar os valores em base64 seguramente (sem colocar senhas em histórico de shell):
echo -n "mysecurepassword123" | base64
Para Secrets de tipo docker-registry (credentials para puxar imagens privadas):
kubectl create secret docker-registry registry-credentials \
--docker-server=docker.io \
--docker-username=myusername \
--docker-password=mypassword \
--docker-email=myemail@example.com
E para certificados TLS:
kubectl create secret tls tls-secret \
--cert=path/to/cert.crt \
--key=path/to/key.key
Consumindo Secrets em Pods
Secrets são consumidos de forma idêntica aos ConfigMaps. Como variáveis de ambiente:
apiVersion: v1
kind: Pod
metadata:
name: app-with-db
spec:
containers:
- name: app
image: myapp:1.0
env:
- name: DB_USER
valueFrom:
secretKeyRef:
name: db-credentials
key: username
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-credentials
key: password
Ou montado como volume (para quando você precisa de arquivos, como certificados):
apiVersion: v1
kind: Pod
metadata:
name: secure-app
spec:
containers:
- name: app
image: myapp:1.0
volumeMounts:
- name: tls-certs
mountPath: /etc/tls
readOnly: true
volumes:
- name: tls-certs
secret:
secretName: tls-secret
Para usar Secrets como credenciais de pull de imagens privadas, configure-o no imagePullSecrets:
apiVersion: v1
kind: Pod
metadata:
name: private-image-app
spec:
imagePullSecrets:
- name: registry-credentials
containers:
- name: app
image: private.docker.io/myapp:1.0
Boas Práticas e Padrões Reais
Organizando ConfigMaps e Secrets por Ambiente
Em um projeto real, você não quer um único ConfigMap gigante. Organize por função e ambiente. Exemplo de estrutura para uma aplicação com múltiplos serviços:
# namespace: production
---
apiVersion: v1
kind: ConfigMap
metadata:
name: api-config
labels:
app: api
env: production
data:
LOG_LEVEL: warn
CACHE_TTL: "3600"
API_TIMEOUT: "30"
---
apiVersion: v1
kind: ConfigMap
metadata:
name: worker-config
labels:
app: worker
env: production
data:
QUEUE_WORKERS: "10"
RETRY_ATTEMPTS: "3"
---
apiVersion: v1
kind: Secret
metadata:
name: api-secrets
labels:
app: api
env: production
type: Opaque
data:
# Encode: echo -n "your-api-key" | base64
API_KEY: eW91ci1hcGkta2V5
JWT_SECRET: eW91ci1qd3Qtc2VjcmV0
Isso facilita a manutenção e permite diferentes configurações para staging, development, etc.
Validação e Versionamento
Sempre valide seu YAML antes de aplicar:
kubectl apply --dry-run=client -f config.yaml
Use controle de versão para seus ConfigMaps e Secrets. Uma prática comum é manter versões numeradas:
kubectl create configmap app-config-v1 --from-file=app.properties
kubectl create configmap app-config-v2 --from-file=app.properties # quando houver mudanças
Depois, você atualiza os Pods para usar a nova versão. O Kubernetes não atualiza Pods automaticamente quando um ConfigMap ou Secret é modificado — você precisa recriar os Pods ou usar ferramentas como Reloader.
Rotação de Secrets em Produção
Nunca comita Secrets em Git. Use uma solução de gerenciamento de secrets como Vault, AWS Secrets Manager, ou Azure Key Vault, e sincronize com Kubernetes usando operadores como External Secrets Operator:
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
name: vault-backend
spec:
provider:
vault:
server: "https://vault.example.com"
path: "secret"
auth:
kubernetes:
mountPath: "kubernetes"
role: "my-app-role"
---
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: db-credentials
spec:
refreshInterval: 1h
secretStoreRef:
name: vault-backend
kind: SecretStore
target:
name: db-credentials
creationPolicy: Owner
data:
- secretKey: username
remoteRef:
key: myapp/db
property: username
- secretKey: password
remoteRef:
key: myapp/db
property: password
Isso sincroniza secrets de forma dinâmica e segura, permitindo rotação centralizada.
Conclusão
Você aprendeu que ConfigMaps e Secrets são ferramentas essenciais para separar configuração de código, permitindo que suas imagens Docker sejam imutáveis e reutilizáveis em diferentes ambientes. A diferença não é apenas técnica — é arquitetural: ConfigMaps para dados públicos e Secrets para sensíveis.
A segunda lição é que encoding em base64 (usado por padrão em Secrets) não é encriptação real. Para produção, você deve configurar encriptação em repouso no etcd e considerar soluções externas de gerenciamento de secrets como HashiCorp Vault, que oferecem rotação automática, auditoria e controle de acesso mais granular.
Por último, organize ConfigMaps e Secrets por função, ambiente e app, valide sempre antes de aplicar, e automize a sincronização quando trabalhar com backends externos. Isso transforma Kubernetes de um orquestrador para um verdadeiro gerenciador de configuração corporativo.