>_ josetilabs.com
← blog

25 out 2026 · linux, seguranca · 4 min

Como guardar segredo em variável de ambiente sem vazar?

Um segredo em código ou em log já é segredo perdido. O .env resolve o armazenamento, mas só se a permissão do arquivo e o .gitignore estiverem corretos. O script abaixo cria o arquivo com modo 600, gera o .gitignore e testa se o valor aparece em um log. Veja também cron do jeito certo para como o cron herda (ou não) variáveis de ambiente, e container sem root para rodar o serviço sem privilégio.

O que vaza e por quê

Três caminhos costumam vazar um segredo: o arquivo .env entra no git porque ninguém adicionou a regra de ignore; o log da aplicação imprime a variável inteira durante o debug; e o segredo fica em uma variável de shell exportada em um script que roda como root e é lido por outro usuário. O primeiro é o mais comum e o mais barato de evitar.

A regra do Twelve-Factor ajuda a pensar: configuração varia entre ambientes, código não. Segredo é configuração, então não pertence ao repositório. Um .env fora do git com permissão 600 cobre o caso de um único host. Para vários hosts ou rotação frequente, um gerenciador de segredos (Vault, SOPS, o cofre do provedor) passa a valer o custo.

O artefato

```bash

!/usr/bin/env bash

set -euo pipefail

DEMO=$(mktemp -d) cd “$DEMO”

1. arquivo de segredos com permissão restrita

umask 077 cat > .env <<’ENV’ APP_SECRET=sk_live_9f8e7d6c5b4a3210 DB_PASSWORD=hunter2-nao-use-isso ENV chmod 600 .env

echo “=== permissão do .env ===” stat -c ‘%a %U:%G %n’ .env

2. .gitignore precisa cobrir .env

if [ ! -f .gitignore ] || ! grep -qxF ‘.env’ .gitignore; then printf ‘%s\n’ ‘.env’ ‘.env.*’ ‘!.env.example’ >> .gitignore fi echo “=== .gitignore ===” cat .gitignore

3. leitura mascarada: nunca imprime o segredo inteiro

mask() { local v=”$1” if [ “${#v}” -le 4 ]; then printf ‘****’ else printf ‘%s…%s’ “${v:0:2}” “${v: -2}” fi }

set -a

shellcheck disable=SC1091

. ./.env set +a

echo “=== variáveis carregadas (mascaradas) ===” printf ‘APP_SECRET=%s\n’ “$(mask “$APP_SECRET”)” printf ‘DB_PASSWORD=%s\n’ “$(mask “$DB_PASSWORD”)”

4. teste de vazamento em log: o log nunca pode conter o valor bruto

LOG=”$DEMO/run.log” { printf ‘inicio %s\n’ “$(date -Is)” printf ‘APP_SECRET=%s\n’ “$(mask “$APP_SECRET”)” printf ‘fim\n’ } > “$LOG”

echo “=== teste de vazamento ===” if grep -Fq “$APP_SECRET” “$LOG” || grep -Fq “$DB_PASSWORD” “$LOG”; then echo “FALHA: segredo encontrado no log” exit 1 else echo “ok: nenhum segredo bruto no log” fi

5. exemplo de unit systemd (não executa aqui; é o que o leitor cola)

echo “=== unit de exemplo (EnvironmentFile) ===” cat <<’UNIT’ [Service] EnvironmentFile=/etc/meu-app/.env ExecStart=/usr/local/bin/meu-app UNIT

echo “=== pronto ===”```

O script usa umask 077 antes de criar o .env, então o arquivo nasce com modo 600 mesmo se o umask do shell estiver relaxado. A leitura é mascarada: a função mask mostra apenas os dois primeiros e os dois últimos caracteres. O teste final procura o valor bruto no log e falha se encontrar.

Como verificar

Rode bash env.sh. A saída esperada inclui a linha 600 no stat e ok: nenhum segredo bruto no log. Em um repositório real, confirme também com git status --porcelain --ignored, que deve listar !! .env.

Terminal mostrando chmod 600 no .env, stat com modo 600 e teste de vazamento com ok
Permissão 600 no .env e o teste de vazamento passando.

Se der errado

.env, shell ou cofre

Abordagem Quando usar Limite
Arquivo .env com modo 600 Um host, um serviço, segredo estável Rotação manual, sem auditoria
Variável no shell ou no crontab Comando único e efêmero Fica no histórico e no ps
Gerenciador de segredos Vários hosts ou rotação automática Mais uma dependência para operar

FAQ

Posso commitar um .env.example? Sim, desde que contenha apenas nomes de variáveis e valores de exemplo sem segredo. O script adiciona !.env.example para isso.

systemd lê .env diretamente? Sim, com EnvironmentFile=/etc/meu-app/.env. A linha de exemplo no script mostra a unit. O systemd ignora linhas que começam com # e exige KEY=VALUE sem export.

chmod 600 basta? Para um host com um único usuário de serviço, sim. Se vários usuários precisam ler, use grupo dedicado com modo 640 e um grupo de serviço, não 644.

Como rotacionar sem parar o serviço? Atualize o .env e recarregue o serviço (systemctl reload ou o mecanismo do app). Se o app lê o arquivo só no boot, será preciso reiniciar.

Vale a pena criptografar o .env no git? Para um time pequeno, não. Se precisar versionar segredo, use SOPS ou git-crypt, não o arquivo puro.

Fontes

Leia também

// Por e-mail

Os textos publicados aqui também vão por e-mail. O envio ainda não começou: quem deixar o endereço agora entra na primeira lista.

Guardo só o seu e-mail, a data e o registro desta autorização. Sem cookies, sem rastreador e nada compartilhado com terceiros. Detalhes na política de privacidade.