Secret management no Bash: evitando hardcoding
1. Por que evitar hardcoding de segredos?
Hardcoding de senhas, chaves de API e tokens em scripts Bash é uma das práticas mais perigosas na automação. Quando um segredo é escrito literalmente no código, ele se torna parte do histórico do Git, acessível a qualquer pessoa com acesso ao repositório. Um simples git log -p pode expor credenciais que deveriam permanecer confidenciais.
Além do vazamento em repositórios, segredos hardcoded aparecem em logs de execução, dumps de processo e até em mensagens de erro. A manutenção também se torna um pesadelo: quando uma senha precisa ser rotacionada, é necessário buscar em dezenas de scripts, muitas vezes esquecendo de atualizar algum arquivo.
A falta de auditabilidade é outro problema grave. Sem um sistema centralizado, não é possível saber quem acessou qual segredo, quando foi rotacionado ou se há cópias espalhadas em backups.
2. Variáveis de ambiente como primeira camada
A abordagem mais simples e imediata é usar variáveis de ambiente. Em vez de escrever a senha no script, você a define fora dele:
# No terminal ou ~/.bashrc
export DB_PASSWORD="minha_senha_secreta"
export API_KEY="abc123def456"
No script, basta referenciar a variável:
#!/bin/bash
echo "Conectando ao banco com senha: $DB_PASSWORD"
mysql -u root -p"$DB_PASSWORD" -e "SHOW DATABASES;"
Boas práticas:
- Use nomes padronizados com prefixo do projeto: MEUAPP_DB_PASSWORD
- Nunca coloque export com segredos dentro do script versionado
- Para ambientes isolados, crie um arquivo .env (não versionado) e faça source:
set -a
source .env
set +a
O set -a automaticamente exporta todas as variáveis lidas do arquivo.
Armadilhas comuns:
- Subshells não herdam variáveis exportadas após o export (a menos que use set -a)
- Com sudo, as variáveis de ambiente não são passadas por padrão. Use sudo -E para preservá-las
- Scripts executados via cron ou systemd precisam de configuração explícita de ambiente
3. Lendo segredos de arquivos externos
Para maior controle, armazene segredos em arquivos com permissões restritas:
# Criar arquivo com permissão 600 (apenas dono pode ler)
echo "minha_senha" > /etc/secrets/db_password.txt
chmod 600 /etc/secrets/db_password.txt
No script:
#!/bin/bash
DB_PASSWORD=$(cat /etc/secrets/db_password.txt)
Ou com read para evitar problemas com espaços e caracteres especiais:
read -r DB_PASSWORD < /etc/secrets/db_password.txt
Para arquivos no formato .env, um parser manual mais seguro que source direto:
#!/bin/bash
while IFS='=' read -r key value; do
[[ -z "$key" || "$key" =~ ^# ]] && continue
key=$(echo "$key" | xargs)
value=$(echo "$value" | xargs)
export "$key=$value"
done < /etc/secrets/producao.env
Isso evita injeção de código malicioso que poderia ocorrer com source em arquivos não confiáveis.
4. Integração com cofres de segredos
Para ambientes profissionais, use cofres de segredos como HashiCorp Vault ou AWS Secrets Manager.
Exemplo com Vault:
#!/bin/bash
VAULT_ADDR="https://vault.exemplo.com"
VAULT_TOKEN=$(cat /tmp/vault-token)
# Obter segredo
DB_PASSWORD=$(curl -s --header "X-Vault-Token: $VAULT_TOKEN" \
"$VAULT_ADDR/v1/secret/data/myapp" | jq -r '.data.data.db_password')
echo "$DB_PASSWORD" | mysql -u root -p
Cache local com limpeza automática:
#!/bin/bash
TEMP_DIR=$(mktemp -d)
trap "rm -rf $TEMP_DIR" EXIT
# Cache do token por 30 minutos
TOKEN_FILE="$TEMP_DIR/vault_token"
if [ ! -f "$TOKEN_FILE" ] || [ $(find "$TOKEN_FILE" -mmin +30) ]; then
vault login -method=ldap username="$USER" -format=json | jq -r '.auth.client_token' > "$TOKEN_FILE"
fi
VAULT_TOKEN=$(cat "$TOKEN_FILE")
DB_PASSWORD=$(vault kv get -field=password secret/myapp)
O trap garante que o diretório temporário seja removido mesmo se o script falhar.
5. Criptografia simétrica com GPG e OpenSSL
Quando não há um cofre disponível, criptografe os arquivos de segredo:
Criptografar com GPG:
# Criptografar (pede senha)
gpg --symmetric --cipher-algo AES256 secrets.txt
# Descriptografar sob demanda no script
DB_PASSWORD=$(gpg --decrypt secrets.txt.gpg 2>/dev/null)
Com OpenSSL:
# Criptografar
openssl enc -aes-256-cbc -salt -in secrets.txt -out secrets.enc -pass pass:"senha_mestre"
# Descriptografar
DB_PASSWORD=$(openssl enc -d -aes-256-cbc -in secrets.enc -pass pass:"senha_mestre")
Gerenciamento com pass:
# Inicializar (uma vez)
pass init "minha-chave-gpg"
# Adicionar segredo
pass insert servidor/db_password
# Usar no script
DB_PASSWORD=$(pass show servidor/db_password)
O pass armazena cada segredo em arquivo GPG individual e oferece integração com Git para backup criptografado.
6. Ferramentas especializadas para Bash
Mozilla SOPS (Secrets OPerationS):
# Criptografar arquivo .env
sops --encrypt --aws-kms arn:aws:kms:us-east-1:123456:key/abc .env > .env.enc
# Descriptografar no script
eval $(sops --decrypt .env.enc)
Bitwarden CLI:
# Login (token de sessão expira em 1 hora)
BW_SESSION=$(bw login --apikey --raw)
# Obter segredo
DB_PASSWORD=$(bw get password "minha-senha" --session "$BW_SESSION")
1Password CLI (op):
# Obter segredo (requer token de acesso)
DB_PASSWORD=$(op read "op://Vault/Item/db_password")
7. Boas práticas em scripts de deploy e CI/CD
Em pipelines CI/CD, segredos devem ser configurados como variáveis de ambiente do pipeline, nunca no código:
GitHub Actions:
jobs:
deploy:
steps:
- name: Deploy
env:
DB_PASSWORD: ${{ secrets.DB_PASSWORD }}
run: ./deploy.sh
Proteção contra vazamentos em logs:
#!/bin/bash
set -o pipefail
# Sanitizar logs
exec 2> >(sed 's/'"$DB_PASSWORD"'/***REDACTED***/g' >&2)
# Comando que pode vazar segredo
mysql -u root -p"$DB_PASSWORD" -e "SELECT 1" 2>&1 | \
sed 's/'"$DB_PASSWORD"'/***REDACTED***/g'
Validação de segredos antes do uso:
#!/bin/bash
if [ -z "$DB_PASSWORD" ]; then
echo "ERRO: DB_PASSWORD não definida" >&2
exit 1
fi
# Verificar se parece uma senha válida (exemplo)
if [ ${#DB_PASSWORD} -lt 8 ]; then
echo "ERRO: DB_PASSWORD muito curta" >&2
exit 1
fi
Nunca faça echo "Senha: $DB_PASSWORD" mesmo em debug. Use echo "Senha: [REDACTED]".
Referências
- HashiCorp Vault - Getting Started — Tutorial oficial de introdução ao Vault, incluindo autenticação e leitura de segredos via CLI
- Mozilla SOPS - GitHub Repository — Repositório oficial do SOPS com documentação completa de criptografia de arquivos para Bash
- passwordstore.org - pass: the standard Unix password manager — Site oficial do pass com exemplos de uso em scripts e integração com Git
- Bitwarden CLI - Official Documentation — Documentação oficial do Bitwarden CLI para gerenciamento programático de segredos
- GitHub Actions - Using secrets in workflows — Guia oficial da GitHub sobre uso seguro de segredos em pipelines CI/CD
- OWASP - Secrets Management Cheat Sheet — Guia de boas práticas da OWASP para gerenciamento de segredos em aplicações