ConfigMaps e Secrets

1. Introdução aos Conceitos de Configuração no Kubernetes

Em qualquer aplicação moderna, a separação entre código e configuração é um pilar essencial de boas práticas de DevOps. No Kubernetes, essa separação é materializada através de dois recursos fundamentais: ConfigMaps e Secrets. Ambos existem para externalizar dados de configuração dos contêineres, permitindo que o mesmo código seja executado em diferentes ambientes (desenvolvimento, homologação, produção) sem modificações.

A diferença crucial entre eles está na sensibilidade dos dados:
- ConfigMaps: armazenam dados não confidenciais em formato texto, como variáveis de ambiente, arquivos de configuração (ex: nginx.conf, application.properties) e parâmetros de runtime.
- Secrets: armazenam dados sensíveis como senhas, tokens de API, chaves SSH e certificados TLS. Embora sejam codificados em base64, isso não é criptografia — é apenas uma codificação para transporte.

Casos de uso típicos incluem injetar URLs de bancos de dados via ConfigMap e credenciais de acesso via Secret, ou fornecer certificados TLS para um ingress controller.

2. Criando e Gerenciando ConfigMaps

Criação Imperativa

O kubectl oferece comandos diretos para criar ConfigMaps:

# A partir de literais (pares chave=valor)
kubectl create configmap app-config --from-literal=LOG_LEVEL=debug --from-literal=DB_HOST=localhost

# A partir de um arquivo (o nome do arquivo vira a chave)
kubectl create configmap nginx-config --from-file=nginx.conf

# A partir de um diretório inteiro (cada arquivo vira uma chave)
kubectl create configmap app-properties --from-dir=./config/

Criação Declarativa (Manifesto YAML)

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  LOG_LEVEL: "debug"
  DB_HOST: "localhost"
  app.properties: |
    database.url=jdbc:postgresql://localhost:5432/mydb
    database.user=admin

ConfigMaps também suportam binaryData para dados binários (ex: imagens pequenas), embora o limite de tamanho total seja 1 MB.

Boas Práticas

  • Nomeie ConfigMaps de forma descritiva (ex: app-config-v2).
  • Versionamente em Git, pois não contêm dados sensíveis.
  • Evite armazenar mais de 1 MB de dados.

3. Criando e Gerenciando Secrets

Criação Imperativa

# A partir de literais
kubectl create secret generic db-secret --from-literal=DB_PASSWORD=S3nh@Sup3r

# A partir de arquivos
kubectl create secret generic tls-secret --from-file=tls.crt --from-file=tls.key

# A partir de um arquivo .env
kubectl create secret generic env-secret --from-env-file=.env

Codificação base64

Quando você inspeciona um Secret com kubectl get secret db-secret -o yaml, os valores aparecem codificados:

apiVersion: v1
kind: Secret
metadata:
  name: db-secret
data:
  DB_PASSWORD: UzNuQEBTdXAzcg==  # base64 de "S3nh@Sup3r"

Importante: base64 não é criptografia. Qualquer pessoa com acesso ao cluster pode decodificar facilmente. Para segurança real, use criptografia em repouso (EncryptionConfiguration) ou ferramentas como Sealed Secrets.

Criação Declarativa com stringData

O campo stringData permite escrever valores em texto puro no manifesto, que o Kubernetes codifica automaticamente:

apiVersion: v1
kind: Secret
metadata:
  name: db-secret
stringData:
  DB_PASSWORD: "S3nh@Sup3r"  # Texto puro
  DB_USER: "admin"

Tipos de Secrets

  • Opaque (padrão): dados arbitrários.
  • kubernetes.io/tls: usado para certificados TLS (exige chaves tls.crt e tls.key).
  • kubernetes.io/dockerconfigjson: credenciais para registro de contêineres Docker.

4. Injetando ConfigMaps e Secrets em Pods: Variáveis de Ambiente

Uso de env com valueFrom

apiVersion: v1
kind: Pod
metadata:
  name: app-pod
spec:
  containers:
  - name: app
    image: myapp:1.0
    env:
    - name: LOG_LEVEL
      valueFrom:
        configMapKeyRef:
          name: app-config
          key: LOG_LEVEL
    - name: DB_PASSWORD
      valueFrom:
        secretKeyRef:
          name: db-secret
          key: DB_PASSWORD

Uso de envFrom para injeção em massa

spec:
  containers:
  - name: app
    image: myapp:1.0
    envFrom:
    - configMapRef:
        name: app-config
    - secretRef:
        name: db-secret

Diferenças práticas:
- envFrom injeta todas as chaves como variáveis de ambiente.
- Com env você pode mapear chaves seletivamente e renomeá-las.
- Chaves ausentes em envFrom são ignoradas; em env com optional: false (padrão) o pod não inicia.

5. Injetando ConfigMaps e Secrets em Pods: Volumes e Arquivos

Montagem como Volume

apiVersion: v1
kind: Pod
metadata:
  name: config-pod
spec:
  volumes:
  - name: config-volume
    configMap:
      name: app-config
  - name: secret-volume
    secret:
      secretName: db-secret
  containers:
  - name: app
    image: myapp:1.0
    volumeMounts:
    - name: config-volume
      mountPath: /etc/config
    - name: secret-volume
      mountPath: /etc/secrets
      readOnly: true

Comportamento de Atualização Automática

Quando um ConfigMap ou Secret é atualizado, os volumes montados são sincronizados automaticamente (com um atraso de ~60 segundos). No entanto, a aplicação precisa recarregar os arquivos — o Kubernetes não reinicia o pod.

SubPath e Permissões

Para montar arquivos individuais (em vez de diretórios):

volumeMounts:
- name: config-volume
  mountPath: /etc/nginx/nginx.conf
  subPath: nginx.conf

Secrets são montados com permissão 0400 (apenas leitura para o owner). Você pode alterar com defaultMode:

volumes:
- name: secret-volume
  secret:
    secretName: db-secret
    defaultMode: 0400

6. Boas Práticas de Segurança e Operação

Criptografia em Repouso

Por padrão, Secrets são armazenados em texto plano no etcd. Para criptografar:

# Criar chave de criptografia
kubectl create secret generic encryption-key \
  --from-literal=key=$(openssl rand -base64 32)

# Configurar EncryptionConfiguration (exemplo simplificado)
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
  - resources:
    - secrets
    providers:
    - aescbc:
        keys:
        - name: key1
          secret: $(base64 da chave)
    - identity: {}

RBAC (Controle de Acesso)

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: production
  name: secret-reader
rules:
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["get", "list"]

Ferramentas Externas

  • Sealed Secrets: criptografa Secrets com chave assimétrica, permitindo versionamento seguro no Git.
  • External Secrets Operator: sincroniza Secrets de sistemas externos (AWS Secrets Manager, HashiCorp Vault, Azure Key Vault).
  • HashiCorp Vault: solução completa de gerenciamento de segredos com integração nativa ao Kubernetes via CSI.

Imutabilidade e Rollout Restart

ConfigMaps e Secrets são imutáveis em Deployments — alterações não reiniciam pods automaticamente. Use:

kubectl rollout restart deployment/myapp

Ou configure anotações para forçar reinicialização:

spec:
  template:
    metadata:
      annotations:
        checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}

7. Comparação e Cenários Práticos

Tabela Comparativa

Característica ConfigMap Secret
Visibilidade Dados em texto plano Dados codificados em base64
Tamanho máximo 1 MB 1 MB
Segurança Baixa (dados não sensíveis) Média (requer criptografia adicional)
Casos de uso Configs, variáveis de ambiente Senhas, tokens, certificados
Atualização automática Sim (volumes) Sim (volumes)

Exemplo Combinado

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  DB_HOST: "postgres-service"
  DB_PORT: "5432"
---
apiVersion: v1
kind: Secret
metadata:
  name: app-secret
stringData:
  DB_PASSWORD: "S3nh@Sup3r"
---
apiVersion: v1
kind: Pod
metadata:
  name: app-pod
spec:
  containers:
  - name: app
    image: myapp:1.0
    env:
    - name: DB_HOST
      valueFrom:
        configMapKeyRef:
          name: app-config
          key: DB_HOST
    - name: DB_PORT
      valueFrom:
        configMapKeyRef:
          name: app-config
          key: DB_PORT
    - name: DB_PASSWORD
      valueFrom:
        secretKeyRef:
          name: app-secret
          key: DB_PASSWORD

Debugging

# Listar ConfigMaps
kubectl get configmaps

# Ver detalhes (dados aparecem descriptografados para ConfigMaps)
kubectl describe configmap app-config

# Ver dados de Secret (codificados)
kubectl get secret db-secret -o yaml

# Ver dados de Secret (decodificados)
kubectl get secret db-secret -o jsonpath='{.data.DB_PASSWORD}' | base64 --decode

# Verificar arquivos montados dentro do pod
kubectl exec app-pod -- cat /etc/config/LOG_LEVEL

Referências