Armazenamento seguro de segredos: variáveis de ambiente vs vault

1. O cenário de risco: por que segredos vazam?

1.1. Exemplos reais de vazamentos por má gestão

Em 2019, um engenheiro da Uber commitou acidentalmente credenciais AWS em um repositório público, expondo dados de 57 milhões de usuários. Casos como esse são recorrentes: segredos vazam em logs de depuração, arquivos de configuração versionados, pipelines de CI/CD mal configurados e até mesmo em capturas de tela compartilhadas em fóruns.

# Exemplo de vazamento clássico em código-fonte
DB_PASSWORD=supersecret123
API_KEY=sk-abc123def456

1.2. O problema do "secret sprawl" em aplicações modernas

Com a adoção de microsserviços, containers e múltiplos ambientes (dev, staging, produção), o número de segredos cresce exponencialmente. Uma aplicação típica pode ter dezenas de chaves de API, senhas de banco, tokens JWT e certificados TLS. Esse espalhamento dificulta o rastreamento, a rotação e a revogação.

1.3. Diferença entre configuração não sensível e segredo crítico

Configurações como PORT=3000 ou LOG_LEVEL=debug não são sensíveis. Já DB_PASSWORD, JWT_SECRET e AWS_ACCESS_KEY são segredos críticos. A confusão entre esses dois tipos leva a práticas inseguras, como versionar arquivos .env ou hardcodear credenciais.

2. Variáveis de ambiente: o padrão-ouro (com ressalvas)

2.1. Como usar variáveis de ambiente corretamente

Variáveis de ambiente são a forma mais básica e amplamente adotada para configurar aplicações. O uso correto envolve:

# .env (NUNCA versionar!)
DATABASE_URL=postgres://user:pass@localhost:5432/mydb
REDIS_PASSWORD=redis123

Para Docker:

# docker-compose.yml
services:
  app:
    environment:
      - DATABASE_URL=${DATABASE_URL}
      - REDIS_PASSWORD=${REDIS_PASSWORD}

2.2. Limitações: persistência em logs, processos filhos e debugging

Variáveis de ambiente vazam facilmente:
- São capturadas em logs de erro (console.log(process.env.DATABASE_URL))
- Herdadas por processos filhos, expondo segredos a subprocessos
- Visíveis em comandos como ps aux e arquivos /proc/[pid]/environ
- Persistem em dumps de memória e core files

2.3. Boas práticas: rotação manual, criptografia em repouso e .gitignore

# .gitignore (obrigatório!)
.env
.env.*
*.env.local

# Rotação manual: alterar senhas periodicamente e reiniciar serviços
# Criptografia em repouso: usar ferramentas como sops ou git-crypt

3. Vaults de segredos: a evolução necessária

3.1. O que é um vault

Um vault é um sistema centralizado para armazenar, acessar e gerenciar segredos. Os principais exemplos são:

  • HashiCorp Vault: open-source, multiplataforma, suporta múltiplos backends
  • AWS Secrets Manager: integrado ao ecossistema AWS, rotação automática
  • Azure Key Vault: para aplicações no Azure, com HSM opcional
  • Google Secret Manager: nativo do GCP

3.2. Ciclo de vida do segredo

Um vault gerencia o ciclo completo:

1. Criação: segredo é armazenado criptografado
2. Acesso: autenticação via token, JWT ou certificado
3. Rotação: substituição automática em intervalos definidos
4. Expiração: TTL (Time-To-Live) para leases temporários
5. Revogação: remoção imediata do acesso

3.3. Vantagens: auditoria, acesso dinâmico e isolamento por ambiente

  • Auditoria: todo acesso é logado (quem, quando, qual segredo)
  • Acesso dinâmico: segredos são gerados sob demanda com permissões mínimas
  • Isolamento: ambientes diferentes usam paths diferentes (secret/dev/db, secret/prod/db)

4. Comparação prática: variáveis de ambiente vs vault

4.1. Cenário 1: Aplicação monolítica em servidor único

Para um app simples rodando em um VPS, variáveis de ambiente com .env criptografado são suficientes. A complexidade de um vault não se justifica.

4.2. Cenário 2: Microsserviços com orquestração (Kubernetes)

Em Kubernetes, variáveis de ambiente via Secrets ainda são comuns, mas vaults oferecem vantagens:

# Kubernetes Secret (limitado)
apiVersion: v1
kind: Secret
metadata:
  name: db-credentials
type: Opaque
data:
  password: c3VwZXJzZWNyZXQxMjM=  # base64 (NÃO é segurança!)

# Vault injector (recomendado)
# Sidecar que injeta segredos diretamente no pod

4.3. Matriz de decisão: custo, complexidade e segurança

Critério Variáveis de ambiente Vault
Custo Gratuito Custo de infraestrutura
Complexidade Baixa Média a alta
Segurança Média Alta
Rotação automática Manual Automática
Auditoria Inexistente Completa
Ideal para Protótipos, apps pequenos Produção, compliance

5. Implementando vault na prática (exemplo com HashiCorp Vault)

5.1. Setup mínimo: iniciar servidor Vault em dev mode

# Terminal 1: Iniciar Vault em modo desenvolvimento (NUNCA em produção!)
$ vault server -dev

# Terminal 2: Configurar ambiente
$ export VAULT_ADDR='http://127.0.0.1:8200'
$ export VAULT_TOKEN='root-token'

# Criar um segredo
$ vault kv put secret/dev/db password=supersecret123

5.2. Injetando segredos via API: exemplo em Python

# app.py
import requests
import os

VAULT_ADDR = os.getenv('VAULT_ADDR', 'http://127.0.0.1:8200')
VAULT_TOKEN = os.getenv('VAULT_TOKEN')

def get_secret(path):
    headers = {'X-Vault-Token': VAULT_TOKEN}
    response = requests.get(f'{VAULT_ADDR}/v1/{path}', headers=headers)
    response.raise_for_status()
    return response.json()['data']['data']

# Uso
secrets = get_secret('secret/dev/db')
db_password = secrets['password']
print(f'Conectando ao banco com senha: {db_password}')

5.3. Integração com CI/CD: evitando segredos hardcoded em pipelines

# .github/workflows/deploy.yml
jobs:
  deploy:
    steps:
      - name: Autenticar no Vault
        run: |
          vault login -method=token token=${{ secrets.VAULT_TOKEN }}

      - name: Obter segredos
        run: |
          vault kv get -field=password secret/prod/db > /tmp/db_pass
          echo "DB_PASSWORD=$(cat /tmp/db_pass)" >> $GITHUB_ENV

6. Armadilhas comuns e como evitá-las

6.1. Cache indevido de segredos na memória da aplicação

Nunca armazene segredos em variáveis globais ou caches de longa duração. Sempre busque sob demanda ou use TTL curto.

# ERRADO
secrets_cache = {}

def get_secret(name):
    if name in secrets_cache:
        return secrets_cache[name]  # Nunca expire!
    ...

# CORRETO
def get_secret(name):
    # Buscar do vault a cada requisição ou usar cache com TTL
    return vault_client.read_secret(name, ttl=60)  # Expira em 60s

6.2. Vault como ponto único de falha (HA e disaster recovery)

Configure Vault em cluster com alta disponibilidade e backups regulares. Sempre tenha um plano de disaster recovery.

# Configuração mínima de HA no Vault
storage "raft" {
  path = "/vault/data"
  node_id = "node1"
}

cluster_addr = "https://vault-1.example.com:8201"
api_addr = "https://vault-1.example.com:8200"

6.3. Combinação perigosa: vault + variáveis de ambiente sem criptografia

Nunca exporte segredos do vault para variáveis de ambiente sem antes criptografar o arquivo de configuração.

# PERIGOSO
export $(vault kv get -format=json secret/prod/db | jq -r '.data.data | to_entries[] | .key + "=" + .value')

# SEGURO
# Usar injector que injeta diretamente no processo, sem expor via env

7. Conclusão e recomendações finais

7.1. Quando ficar com variáveis de ambiente

  • Projetos pessoais ou protótipos
  • Aplicações monolíticas com até 3-5 segredos
  • Times pequenos sem requisitos de compliance
  • Ambientes de desenvolvimento local

7.2. Quando migrar para um vault

  • Mais de 10 segredos gerenciados manualmente
  • Múltiplos ambientes e times
  • Requisitos de auditoria (SOC2, PCI-DSS, HIPAA)
  • Microsserviços com rotação frequente de credenciais
  • Integração com Kubernetes ou Docker Swarm

7.3. Checklist de segurança: o mínimo que todo dev deve implementar hoje

[ ] NUNCA versionar segredos (use .gitignore)
[ ] Usar variáveis de ambiente com criptografia em repouso
[ ] Implementar rotação periódica de senhas e chaves
[ ] Auditoria básica: quem acessou o quê e quando
[ ] Isolar segredos por ambiente (dev/staging/prod)
[ ] Evitar cache de longa duração de segredos
[ ] Documentar o processo de revogação de emergência

A segurança de segredos não é opcional — é uma responsabilidade fundamental de todo desenvolvedor. Comece pequeno, mas comece hoje.

Referências