Secrets em produção: Doppler e HashiCorp Vault

    Hardcoded secrets em código e .env no servidor são os vetores de vazamento mais comuns. Gerenciadores de secrets como Doppler e HashiCorp Vault centralizam o controle, criptografam em repouso, auditam cada acesso e permitem rotação sem downtime — eliminando a dependência de arquivos .env espalhados por servidores.

    Doppler: secrets como variáveis de ambiente

    Injetar secrets automaticamente sem arquivos .env:

    bash
    # Instalar Doppler CLI no VPS:
    (curl -Ls --tlsv1.2 --proto "=https" -o install.sh   https://cli.doppler.com/install.sh) && sudo sh install.sh
    
    # Autenticar (em desenvolvimento, usa browser; em CI/CD, usa service token):
    doppler login
    
    # Configurar projeto no VPS:
    doppler setup --project minha-api --config prd
    
    # Executar aplicação com secrets injetados como env vars:
    doppler run -- node server.js
    # ou:
    doppler run -- npm start
    
    # Verificar quais secrets serão injetados:
    doppler secrets --only-names
    
    # Configurar como serviço systemd que injeta secrets:
    sudo tee /etc/systemd/system/minha-api.service << 'EOF'
    [Unit]
    Description=Minha API Node.js
    After=network.target
    
    [Service]
    User=nodejs
    WorkingDirectory=/app
    ExecStart=/usr/local/bin/doppler run -- node server.js
    Restart=always
    RestartSec=5
    
    # Token do Doppler para autenticação no servidor:
    Environment=DOPPLER_TOKEN=dp.st.prd.xxxxxxxxxxxxxxxxxxxx
    
    [Install]
    WantedBy=multi-user.target
    EOF
    sudo systemctl daemon-reload && sudo systemctl enable minha-api

    HashiCorp Vault: gerenciamento enterprise de secrets

    Instalar e configurar Vault para gerenciamento avançado:

    bash
    # Instalar HashiCorp Vault no Ubuntu:
    wget -O- https://apt.releases.hashicorp.com/gpg |   sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
    echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg]   https://apt.releases.hashicorp.com $(lsb_release -cs) main" |   sudo tee /etc/apt/sources.list.d/hashicorp.list
    sudo apt update && sudo apt install vault
    
    # Configuração básica do Vault:
    sudo tee /etc/vault.d/vault.hcl << 'EOF'
    ui = true
    
    storage "file" {
      path = "/opt/vault/data"
    }
    
    listener "tcp" {
      address     = "127.0.0.1:8200"
      tls_disable = "true"   # Em produção: usar TLS
    }
    
    api_addr = "http://127.0.0.1:8200"
    EOF
    
    sudo systemctl enable vault && sudo systemctl start vault
    
    # Inicializar o Vault (primeira vez):
    export VAULT_ADDR='http://127.0.0.1:8200'
    vault operator init -key-shares=3 -key-threshold=2
    # Salva as 3 unseal keys e o root token em local SEGURO
    
    # Desselar (necessário após cada restart):
    vault operator unseal UNSEAL_KEY_1
    vault operator unseal UNSEAL_KEY_2

    Armazenar e ler secrets no Vault

    Usar o KV secrets engine para armazenar credenciais:

    bash
    export VAULT_ADDR='http://127.0.0.1:8200'
    export VAULT_TOKEN='s.xxxxxxxxxxxxxxxxxxxxxxxx'  # root token
    
    # Habilitar KV secrets engine versão 2:
    vault secrets enable -path=minha-api kv-v2
    
    # Armazenar secrets:
    vault kv put minha-api/producao   DATABASE_URL="postgresql://user:senha@localhost/db"   JWT_SECRET="$(openssl rand -base64 32)"   REDIS_URL="redis://localhost:6379"   STRIPE_SECRET_KEY="sk_live_xxxxxxxxx"
    
    # Ler secrets:
    vault kv get minha-api/producao
    vault kv get -field=DATABASE_URL minha-api/producao
    
    # Versionar secrets (KV v2 mantém histórico):
    vault kv put minha-api/producao JWT_SECRET="novo-secret"
    vault kv get -version=1 minha-api/producao   # versão anterior
    
    # Criar AppRole para autenticação da aplicação (sem root token):
    vault auth enable approle
    
    vault policy write minha-api-policy - << 'EOF'
    path "minha-api/data/producao" {
      capabilities = ["read"]
    }
    EOF
    
    vault write auth/approle/role/minha-api   token_policies="minha-api-policy"   token_ttl=1h   token_max_ttl=4h
    
    # Obter credentials da aplicação:
    vault read auth/approle/role/minha-api/role-id
    vault write -f auth/approle/role/minha-api/secret-id

    Ler secrets do Vault na aplicação Node.js

    Integrar Vault com aplicação Node.js para injetar secrets em startup:

    typescript
    // npm install node-vault
    
    import vault from 'node-vault'
    
    async function carregarSecrets(): Promise<Record<string, string>> {
      const client = vault({
        apiVersion: 'v1',
        endpoint: process.env.VAULT_ADDR || 'http://127.0.0.1:8200',
      })
    
      // Autenticar via AppRole:
      const auth = await client.approleLogin({
        role_id: process.env.VAULT_ROLE_ID!,
        secret_id: process.env.VAULT_SECRET_ID!,
      })
      client.token = auth.auth.client_token
    
      // Ler secrets:
      const { data } = await client.read('minha-api/data/producao')
      return data.data
    }
    
    // Inicialização da aplicação:
    async function main() {
      const secrets = await carregarSecrets()
    
      process.env.DATABASE_URL = secrets.DATABASE_URL
      process.env.JWT_SECRET = secrets.JWT_SECRET
      process.env.REDIS_URL = secrets.REDIS_URL
    
      // Iniciar a aplicação após injetar os secrets:
      const app = await criarApp()
      app.listen(3000)
    }
    
    // Rotação de secrets sem restart (Vault lease renew):
    // O token tem TTL de 1h — renovar antes de expirar:
    setInterval(async () => {
      try {
        await client.tokenRenewSelf()
      } catch {
        // Reutenticar se o token não puder ser renovado:
        const secrets = await carregarSecrets()
        atualizarSecrets(secrets)
      }
    }, 30 * 60 * 1000)  // renovar a cada 30 minutos

    Boas práticas de segurança para .env em produção

    Alternativas simples quando Vault/Doppler são excesso para o projeto:

    bash
    # Prática mínima se .env for necessário:
    
    # 1. Nunca commitar .env no git:
    echo ".env" >> .gitignore
    echo ".env.*" >> .gitignore
    echo "*.env" >> .gitignore
    
    # 2. Permissões restritas no arquivo:
    chmod 600 /app/.env           # apenas o dono pode ler/escrever
    chown nodejs:nodejs /app/.env # dono = usuário da aplicação
    
    # 3. .env fora do diretório da aplicação:
    # /etc/minha-api/env  (não dentro de /app que pode ter outros arquivos)
    chmod 640 /etc/minha-api/env
    chown root:nodejs /etc/minha-api/env
    
    # 4. Usar systemd EnvironmentFile para carregar sem .env no diretório da app:
    # /etc/systemd/system/minha-api.service:
    # [Service]
    # EnvironmentFile=/etc/minha-api/env
    # ExecStart=/usr/bin/node /app/server.js
    
    # 5. Verificar se secrets não estão em processo ou logs:
    ps aux | grep node  # não deve mostrar DATABASE_URL=... como argumento
    # Logs não devem logar objetos req (que podem conter Authorization headers)
    
    # 6. Rotação: quando rotacionar uma credencial:
    # Atualizar .env → reload da aplicação sem downtime:
    sudo systemctl reload minha-api  # envia SIGHUP, mais suave que restart

    $ runstack deploy --plan starter

    Não quer configurar manualmente?

    Não quer configurar manualmente? Implante o VPS Linux em menos de 3 minutos com a Runstack. Infraestrutura da OPEN DATACENTER, com servidores no Brasil.

    Perguntas frequentes