Segurança com Docker Secrets

O Desafio de Gerenciar Segredos em Aplicações

O gerenciamento de segredos e configurações sensíveis é um desafio crítico em qualquer aplicação, especialmente em projetos open-source. Desde o início do NotionAiAssistant, consideramos a segurança como uma prioridade, e o gerenciamento adequado de credenciais e tokens de API era essencial.

graph LR
    subgraph "Fluxo de Docker Secrets"
        S1["Arquivos de Secrets<br>Local/CI/Produção"] --> S2["Docker Compose<br>Referencia Secrets"]
        S2 --> S3["Montados em<br>/run/secrets/"]
        S3 --> S4["Aplicação<br>Lê do Filesystem"]
    end
    
    subgraph "Benefícios de Segurança"
        S4 --> V1["Não Aparecem<br>em Logs"]
        S4 --> V2["Não Expostos<br>em Variáveis"]
        S4 --> V3["Não Incluídos<br>em Imagens"]
    end
    
    classDef source fill:#f9f,stroke:#333,stroke-width:2px
    classDef flow fill:#bbf,stroke:#333,stroke-width:2px
    classDef benefit fill:#bfb,stroke:#333,stroke-width:2px
    
    class S1 source
    class S2,S3,S4 flow
    class V1,V2,V3 benefit

Por Que Docker Secrets?

Existem diversas soluções para gerenciamento de segredos disponíveis no mercado, como:

  • HashiCorp Vault
  • AWS Secrets Manager
  • Google Secret Manager
  • Kubernetes Secrets
  • Variáveis de ambiente criptografadas
  • Arquivos .env com ferramentas como dotenv

No entanto, escolhemos Docker Secrets pelos seguintes motivos:

1. Integração Nativa com Nosso Stack

Como já estávamos utilizando Docker e Docker Compose para nosso ambiente de desenvolvimento e produção, o Docker Secrets oferecia uma integração perfeita sem necessidade de ferramentas adicionais.

2. Simplicidade e Baixa Curva de Aprendizado

O Docker Secrets apresenta uma abordagem direta e intuitiva:

# Exemplo de uso no docker-compose.yml
services:
  app:
    image: notionaiassistant:latest
    secrets:
      - notion_api_key
      - database_password
      - openai_api_key

secrets:
  notion_api_key:
    file: ./secrets/notion_api_key.txt
  database_password:
    file: ./secrets/database_password.txt
  openai_api_key:
    file: ./secrets/openai_api_key.txt

3. Segurança em Diferentes Ambientes

O Docker Secrets nos permitiu implementar uma estratégia consistente para diferentes ambientes:

  • Desenvolvimento: Secrets armazenados localmente em arquivos
  • CI/CD: Secrets injetados a partir de variáveis de ambiente
  • Produção: Secrets gerenciados pelo Docker Swarm

4. Evita Exposição Acidental

O Docker Secrets reduz significativamente o risco de exposição acidental de credenciais:

  • Não aparecem em logs ou saídas de comandos
  • Não são expostos através de variáveis de ambiente
  • Não são incluídos em imagens ou containers
  • São montados como arquivos temporários em /run/secrets/

Implementação no NotionAiAssistant

Nossa implementação de Docker Secrets segue um padrão consistente em todo o projeto:

1. Estrutura de Diretórios

NotionAiAssistant/
├── secrets/
│   ├── .gitignore        # Ignora todos os arquivos exceto templates
│   ├── notion_api_key.txt.template
│   ├── database_password.txt.template
│   └── ...

2. Acesso aos Secrets no Código

Implementamos uma função auxiliar para acessar secrets de forma consistente:

def get_secret(secret_name: str) -> str:
    """
    Obtém um secret do Docker Secrets ou fallback para variável de ambiente.
    
    Args:
        secret_name: Nome do secret a ser obtido
        
    Returns:
        Conteúdo do secret como string
    """
    # Caminho padrão do Docker Secrets
    secret_path = f"/run/secrets/{secret_name}"
    
    # Verifica se o secret existe como arquivo
    if os.path.exists(secret_path):
        with open(secret_path, "r") as f:
            return f.read().strip()
    
    # Fallback para variável de ambiente (desenvolvimento local ou CI)
    env_var = os.environ.get(secret_name.upper())
    if env_var:
        return env_var
        
    raise ValueError(f"Secret {secret_name} não encontrado")

3. Configuração para Novos Contribuidores

Criamos um script de setup que facilita a configuração inicial:

#!/bin/bash
# setup-secrets.sh

echo "Configurando secrets para ambiente de desenvolvimento..."

mkdir -p secrets

for template in secrets/*.template; do
    secret_file="${template%.template}"
    
    if [ ! -f "$secret_file" ]; then
        echo "Criando $secret_file"
        echo "development_value" > "$secret_file"
        echo "⚠️  Lembre-se de substituir o valor padrão em $secret_file com suas credenciais reais"
    fi
done

echo "✅ Setup concluído!"

Benefícios Práticos Observados

A adoção do Docker Secrets trouxe benefícios tangíveis ao projeto:

  1. Zero exposição acidental de credenciais em commits ou logs
  2. Processo de onboarding simplificado para novos contribuidores
  3. Consistência entre ambientes de desenvolvimento e produção
  4. Rotação de credenciais facilitada sem necessidade de reconstruir imagens
  5. Auditabilidade melhorada de acesso a informações sensíveis

Comparação com Alternativas

SoluçãoComplexidadeIntegração com DockerCurva de AprendizadoCusto
Docker SecretsBaixaNativaBaixaGratuito
HashiCorp VaultAltaRequer configuraçãoAltaGratuito/Pago
Cloud ProvidersMédiaRequer SDK/APIMédiaPago
.env FilesBaixaManualBaixaGratuito

Lições Aprendidas

Nossa experiência com Docker Secrets nos ensinou importantes lições:

  1. A solução mais simples muitas vezes é a melhor: não precisamos de ferramentas complexas para resolver problemas básicos
  2. Soluções nativas trazem menos atrito: usar o que já está disponível no ecossistema reduz pontos de falha
  3. Documentação clara é essencial: especialmente para aspectos relacionados à segurança
  4. Padrões consistentes aumentam a segurança: uma abordagem uniforme facilita auditoria e manutenção

Conclusão

A escolha do Docker Secrets demonstrou que, em muitos casos, as ferramentas nativas do ecossistema que você já utiliza podem oferecer soluções elegantes para problemas complexos. Em vez de adicionar mais complexidade com ferramentas especializadas, primeiro avalie o que já está disponível em seu stack atual.

Esta abordagem alinha-se perfeitamente com nossa filosofia de projeto: utilizar tecnologias open-source simples e eficazes para criar soluções robustas e acessíveis.


"A simplicidade é o último grau da sofisticação." - Leonardo da Vinci