Guia completo de Docker Secrets: práticas recomendadas para proteger senhas e chaves de API em contêineres

O celular não parava de vibrar: eram 24 mensagens, todas alertas de anomalia no banco de dados. Conectei ao servidor por SSH e vi que o número de conexões havia disparado. Alguém estava fazendo uma varredura por força bruta.
Ao verificar os logs, descobri que o invasor tinha usado a senha correta — a senha do MySQL que havia sido colocada no docker-compose.yml três meses antes. No mês anterior, um estagiário tinha feito fork do projeto para um repositório público pessoal, e foi assim que a senha vazou.
Mesmo sem vazamento do código, qualquer pessoa capaz de executar docker inspect consegue ver todas as variáveis de ambiente em texto simples. Neste artigo, vamos conversar sobre o gerenciamento de senhas em contêineres: quais práticas perigosas evitar e quais ferramentas realmente protegem informações sensíveis.
Por que variáveis de ambiente não são seguras?
Três práticas inseguras muito comuns
Vou começar pelos erros que eu mesmo já cometi. Veja se você também fez algo parecido.
Primeira: colocar a senha diretamente no Dockerfile
FROM node:18
ENV DATABASE_PASSWORD=MyS3cr3tP@ssw0rd
ENV API_KEY=sk-1234567890abcdef
Essa é a pior opção. Cada instrução do Dockerfile cria uma camada da imagem. Mesmo que depois você use ENV DATABASE_PASSWORD="" para substituir o valor, a senha continuará escondida nas camadas antigas. Qualquer pessoa que tenha acesso à imagem poderá encontrá-la com docker history <nome_da_imagem>.
Não acredita? Eu também não acreditava, até um colega me mostrar. Ele baixou uma imagem interna da empresa e, com poucos comandos, extraiu uma Access Key da AWS. A chave tinha sido deixada três anos antes por um funcionário que já havia saído, e ninguém se lembrara de removê-la.
Segunda: colocar a senha no docker-compose.yml
version: '3.8'
services:
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: SuperSecretPassword123
MYSQL_DATABASE: myapp
Usei essa opção por muito tempo. O motivo era simples: conveniência. Bastava executar docker-compose up -d para colocar tudo no ar, o que agiliza bastante o desenvolvimento e a depuração.
Qual é o problema? Esse arquivo precisa ser enviado ao Git. Mesmo que o repositório seja privado, basta uma permissão mal configurada ou alguém fazer fork para um repositório público, como aconteceu comigo, para todas as senhas vazarem.
Terceira: usar um arquivo .env, mas incluí-lo no controle de versão
# arquivo .env
DB_PASSWORD=password123
API_SECRET=abcdef123456
À primeira vista, parece uma solução mais inteligente: você separa as informações sensíveis em um arquivo .env e usa ${DB_PASSWORD} no docker-compose.
O problema é que muita gente — inclusive eu, no passado — também envia o .env ao Git, pensando que “o restante da equipe precisa conseguir executar o projeto”. Na prática, o resultado não é diferente de gravar a senha diretamente no docker-compose.
O correto é adicionar .env ao .gitignore e fornecer um modelo .env.example. Mas, sinceramente, quantas pessoas pensam nisso logo no início?
Três grandes riscos das variáveis de ambiente
Mesmo que o .env esteja no .gitignore e o código nunca vaze, variáveis de ambiente continuam trazendo riscos. Por quê?
Risco 1: docker inspect mostra tudo
Experimente este comando:
docker inspect <ID_do_contêiner> | grep -A 20 "Env"
Todas as variáveis de ambiente, inclusive as senhas, aparecem em texto simples.
O que isso significa? Qualquer pessoa com acesso ao daemon do Docker — equipe de operações, DevOps ou desenvolvedores com acesso ao servidor — consegue ver suas senhas. Não é preciso quebrar criptografia nem dominar uma técnica avançada: basta executar um comando.
Trabalhei em uma startup em que todos tinham acesso SSH ao servidor de produção, por conveniência. Certo dia, um desenvolvedor frontend recém-contratado ficou curioso para saber “o que havia dentro do contêiner” e executou docker inspect. A senha do banco de dados apareceu na tela. Por sorte, era alguém da própria equipe. E se fosse uma pessoa mal-intencionada?
Risco 2: processos dentro do contêiner podem ler os valores
Não é só o Docker que enxerga as variáveis de ambiente: todos os processos dentro do contêiner também podem lê-las. No Linux, as variáveis de ambiente de um processo ficam no arquivo /proc/<PID>/environ.
Isso significa que, se qualquer dependência da aplicação tiver uma vulnerabilidade que permita injeção de código, o invasor poderá ler as variáveis de ambiente e obter as senhas diretamente.
No ano passado, descobriram um backdoor em uma biblioteca Node.js que lia credenciais da AWS presentes nas variáveis de ambiente e as enviava para um servidor externo. Dezenas de milhares de projetos foram afetados.
Risco 3: os logs podem expor segredos
Esse risco é ainda mais discreto.
Muitas aplicações imprimem as configurações durante a inicialização ou despejam variáveis de ambiente nos logs quando ocorre um erro. Em geral, os arquivos de log têm controles de acesso mais permissivos e podem ser enviados a sistemas centralizados, como o ELK.
Já vi uma equipe centralizar todos os logs de contêineres em um cluster Elasticsearch e, durante uma auditoria de segurança, descobrir centenas de senhas de banco de dados nos registros. Os desenvolvedores tinham o hábito de usar console.log(process.env) durante a depuração e depois se esqueciam de apagar essa linha.
O pior é que, depois que uma senha entra nos logs, fica difícil removê-la por completo: backups, arquivos históricos e outros sistemas passam a guardar cópias.
Casos reais
Esse tipo de incidente é bastante comum, embora muitas empresas não o divulguem. Vou contar alguns casos que conheço.
Caso 1: vazamento em repositório público do GitHub
Uma análise de 2023 mostrou que havia mais de 1 milhão de repositórios públicos no GitHub com chaves de API, senhas de banco de dados e outras informações sensíveis. Não é que todos esses desenvolvedores fossem irresponsáveis. Muitas vezes, trata-se de um descuido momentâneo: uma configuração de teste que não foi removida ou um .env enviado sem querer.
Um amigo que trabalha com machine learning contou que a equipe dele publicou o código de treinamento no GitHub e, junto com ele, enviou as credenciais da AWS. Em menos de 24 horas, alguém usou essas credenciais para criar mais de dez instâncias com GPU e minerar criptomoedas. A conta passou de 20 mil dólares.
Caso 2: vazamento no histórico do pipeline de CI/CD
Ferramentas de CI/CD, como Jenkins e GitLab CI, normalmente preservam logs de variáveis de ambiente no histórico de builds. Sem um mascaramento adequado, esses logs viram verdadeiros cofres de senhas.
Participei de um projeto com implantação automática pelo GitLab CI. Antes de sair da empresa, um colega deu acesso ao repositório a uma equipe terceirizada. Uma pessoa dessa equipe examinou os logs de builds antigos e encontrou os dados de conexão do banco de produção. Por sorte, eles estavam tentando ajudar na otimização e nos avisaram. E se a intenção fosse outra?
Caso 3: varredura de imagens no Docker Hub
Um relatório de segurança da Alibaba Cloud mostrou que, entre as imagens públicas do Docker analisadas, 76% tinham vulnerabilidades, e várias continham credenciais gravadas diretamente.
Algumas empresas publicam imagens internas no Docker Hub por conveniência, pensando que “ninguém vai perder tempo vasculhando a imagem de uma empresa pequena”. Hoje, porém, há muitos crawlers e scanners automatizados dedicados exatamente a isso. Poucos minutos depois do envio, sua imagem já pode ter sido examinada.
Não estou dizendo isso para assustar você. Esses problemas realmente acontecem e são mais comuns do que parecem. A boa notícia é que existem maneiras de evitá-los.
O que é Docker Secrets e como usá-lo?
Como Docker Secrets funciona
Agora vamos à solução.
Docker Secrets é o mecanismo oficial do Docker para gerenciar segredos. Em termos simples, a ideia central é: o segredo deixa de ser uma string em texto simples e passa a ser um arquivo criptografado.
O fluxo funciona assim:
- Você cria um secret, e o Docker o armazena criptografado no log Raft do cluster
- Quando um contêiner precisa desse secret, o Docker o transfere por uma conexão TLS criptografada
- O secret é montado como arquivo no diretório
/run/secrets/dentro do contêiner - Esse diretório usa
tmpfs, um sistema de arquivos em memória que não grava os dados em disco - Quando o contêiner para, o secret é removido automaticamente da memória
O ponto principal é: o secret não aparece nas variáveis de ambiente, na saída de docker inspect nem em imagens criadas com docker commit.
Parece abstrato? Tudo bem. Na primeira vez que li a documentação do Docker, também fiquei confuso. Depois que você testa, o conceito fica bem mais claro.
Há uma limitação importante: Docker Secrets só funciona nativamente no modo Swarm. No começo, isso me incomodou bastante. Se eu estava desenvolvendo localmente, em uma única máquina, por que não poderia usar secrets?
Mais tarde, descobri que o docker-compose também oferece file secrets. Os recursos são mais limitados, mas pelo menos funciona. Em um cluster de produção, você pode usar diretamente o modo Swarm ou o Kubernetes.
Tutorial prático: MySQL + WordPress
Vamos montar um exemplo completo. Suponha que você precise implantar um blog WordPress e proteger a senha de root e a senha de usuário do MySQL.
Etapa 1: crie os arquivos de secret
Primeiro, grave as senhas em arquivos locais. Atenção: não envie esses arquivos ao Git.
echo "MyRootPassword123" > db_root_password.txt
echo "MyUserPassword456" > db_password.txt
Etapa 2: inicialize o Swarm, caso ainda não esteja ativo
docker swarm init
Sim, é só esse comando. Se o modo Swarm ainda não estiver ativo, execute-o. Você também pode usar Swarm em uma única máquina; não é obrigatório ter um cluster com vários servidores.
Etapa 3: crie os Docker secrets
docker secret create mysql_root_password db_root_password.txt
docker secret create mysql_password db_password.txt
Depois da criação, exclua imediatamente os arquivos locais com as senhas:
rm db_root_password.txt db_password.txt
Essa etapa é importante. Assim que o Docker lê os arquivos e armazena os valores de forma criptografada, os arquivos locais em texto simples devem ser destruídos.
Verifique se os secrets foram criados:
docker secret ls
Você verá uma saída parecida com esta:
ID NAME CREATED UPDATED
abc123... mysql_root_password 5 seconds ago 5 seconds ago
def456... mysql_password 3 seconds ago 3 seconds ago
Observe que você não consegue ver o conteúdo do secret, apenas o nome e os metadados. Esse é justamente o objetivo: depois da criação, nem mesmo um administrador consegue recuperar o texto simples.
Etapa 4: crie o docker-compose.yml
version: '3.8'
secrets:
mysql_root_password:
external: true
mysql_password:
external: true
services:
db:
image: mysql:8.0
secrets:
- mysql_root_password
- mysql_password
environment:
MYSQL_ROOT_PASSWORD_FILE: /run/secrets/mysql_root_password
MYSQL_PASSWORD_FILE: /run/secrets/mysql_password
MYSQL_USER: wordpress
MYSQL_DATABASE: wordpress
volumes:
- db_data:/var/lib/mysql
wordpress:
image: wordpress:latest
depends_on:
- db
ports:
- "8080:80"
secrets:
- mysql_password
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD_FILE: /run/secrets/mysql_password
WORDPRESS_DB_NAME: wordpress
volumes:
db_data:
Preste atenção a alguns pontos:
- Configuração
secretsno nível superior: declara quais secrets serão usados.external: trueindica que o secret já existe e não será criado pelo compose services.db.secrets: define quais secrets o serviço poderá usarMYSQL_ROOT_PASSWORD_FILE: a imagem oficial do MySQL aceita variáveis de ambiente com o sufixo_FILEe lê a senha de um arquivo em vez de recebê-la diretamente na variável
Esse sufixo _FILE é importante, mas nem todas as imagens oferecem suporte a ele. Se a imagem não oferecer, você precisará ler o arquivo no script de inicialização:
# exemplo de entrypoint.sh
export DB_PASSWORD=$(cat /run/secrets/db_password)
# depois, inicialize sua aplicação
Etapa 5: faça a implantação
docker stack deploy -c docker-compose.yml myapp
Observe que usamos docker stack deploy, e não docker-compose up. No modo Swarm, é preciso usar o comando stack.
Etapa 6: verifique o resultado
Entre no contêiner do MySQL para confirmar que o secret foi montado corretamente:
docker exec -it <ID_do_contêiner> sh
ls -la /run/secrets/
Você verá algo parecido:
total 8
-r--r--r-- 1 root root 18 Dec 18 10:00 mysql_password
-r--r--r-- 1 root root 18 Dec 18 10:00 mysql_root_password
Tente ler o arquivo:
cat /run/secrets/mysql_root_password
A senha será exibida. O ponto principal é que essa senha existe apenas na memória, não é gravada em disco nem aparece nas variáveis de ambiente.
Confirme que docker inspect não mostra a senha:
docker inspect <ID_do_contêiner> | grep -i password
A saída terá apenas um caminho como MYSQL_ROOT_PASSWORD_FILE=/run/secrets/mysql_root_password. O valor da senha não aparece.
Esse é o poder do Docker Secrets: a aplicação dentro do contêiner consegue ler a senha, mas o valor em texto simples não fica exposto externamente.
Limitações do Docker Secrets e alternativas
Para ser sincero, Docker Secrets não é perfeito. Estas são as principais limitações:
Limitação 1: exige o modo Swarm
Essa é a mais incômoda. Se você só executa contêineres localmente em uma única máquina, precisa usar docker swarm init para trabalhar com secrets. Embora o Swarm funcione em um único nó, isso pode parecer exagerado para um ambiente simples.
Além disso, depois de habilitar o Swarm, você passa a usar docker stack deploy em vez do conhecido docker-compose up. É preciso mudar alguns hábitos de linha de comando.
Limitação 2: o conteúdo não pode ser alterado depois da criação
Depois que um Docker Secret é criado, seu conteúdo fica somente leitura. Para mudar uma senha, você precisa remover o secret e criá-lo novamente:
docker secret rm mysql_password
echo "NewPassword789" | docker secret create mysql_password -
Depois disso, ainda é necessário atualizar todos os serviços que usam esse secret:
docker service update --secret-rm mysql_password --secret-add mysql_password myapp_db
É um processo um pouco trabalhoso. Com variáveis de ambiente, bastaria alterar o valor e reiniciar o contêiner.
Limitação 3: não funciona com contêineres independentes
Se você inicia o contêiner diretamente com docker run, não pode usar Docker Secrets. O recurso exige um serviço implantado com docker service create ou docker stack.
Isso não é muito prático em testes rápidos. Às vezes, você só quer subir temporariamente um contêiner de banco de dados e descobre que precisa configurar todo o fluxo do Swarm.
Alternativa para desenvolvimento em uma máquina: file secrets do docker-compose
Felizmente, o docker-compose oferece uma alternativa: file secrets. Ela não exige o modo Swarm e monta diretamente um arquivo local como secret.
A configuração é parecida com esta:
version: '3.8'
secrets:
db_password:
file: ./secrets/db_password.txt
services:
db:
image: mysql:8.0
secrets:
- db_password
environment:
MYSQL_ROOT_PASSWORD_FILE: /run/secrets/db_password
Depois, crie o arquivo local com a senha:
mkdir secrets
echo "MyPassword123" > secrets/db_password.txt
Atenção: adicione o diretório secrets/ ao .gitignore!
Essa opção é mais segura que variáveis de ambiente: a senha não aparece em docker inspect nem é incluída na imagem. Ainda assim, ela não é tão segura quanto o Docker Secrets de verdade, porque:
- O arquivo com a senha continua em texto simples no disco local
- Não há transmissão criptografada
- Não há gerenciamento centralizado
Para um ambiente de desenvolvimento local, costuma ser suficiente. Em produção, o mais seguro é usar Swarm ou Kubernetes.
Técnicas avançadas
Depois de dominar as operações básicas, vale conhecer algumas técnicas úteis.
Técnica 1: personalizar o caminho de montagem do secret
Por padrão, o secret é montado em /run/secrets/<secret_name>, mas você pode personalizar o caminho e o nome do arquivo:
services:
myapp:
image: myapp:latest
secrets:
- source: db_password
target: /app/config/database.pwd
mode: 0400
Nesse exemplo, mode: 0400 define a permissão do arquivo para que apenas o proprietário possa lê-lo, aumentando a segurança.
Técnica 2: gerenciar vários ambientes
Use senhas diferentes em desenvolvimento, teste e produção, mas mantenha o mesmo nome para o secret:
# ambiente de produção
docker secret create db_password prod_password.txt
# ambiente de teste (em outro cluster Swarm)
docker secret create db_password test_password.txt
O código da aplicação só precisa ler /run/secrets/db_password, sem saber qual é o valor. Assim, o código permanece idêntico; apenas o cluster de destino muda.
Técnica 3: fazer a rotação do secret
Trocar senhas periodicamente é uma boa prática. A rotação de um Docker secret exige algumas etapas, mas não é difícil:
# 1. Crie a nova senha
echo "NewPassword" | docker secret create db_password_v2 -
# 2. Atualize o serviço: adicione o novo secret e remova o antigo
docker service update \
--secret-rm db_password \
--secret-add source=db_password_v2,target=/run/secrets/db_password \
myapp_db
# 3. Depois de confirmar que o serviço funciona, remova o secret antigo
docker secret rm db_password
Observe o detalhe: o novo secret se chama db_password_v2, mas, por meio do parâmetro target, o caminho de montagem continua sendo /run/secrets/db_password. Assim, não é preciso alterar o código da aplicação.
Técnica 4: criar o secret a partir de stdin
Não quer deixar rastros no disco? Crie o secret diretamente pela entrada padrão:
echo "MySecretPassword" | docker secret create db_password -
O - no final indica que o valor será lido de stdin. Assim, nem sequer é necessário criar um arquivo temporário.
Uma opção ainda mais segura é digitar ou colar o valor manualmente, sem deixá-lo no histórico do shell:
docker secret create db_password -
# cole a senha e pressione Ctrl+D para concluir
Comparação com outras ferramentas de gerenciamento de segredos
Matriz comparativa de quatro ferramentas
Docker Secrets não é a única opção. Dependendo do tamanho do projeto e da infraestrutura, talvez você precise de outra ferramenta. Esta tabela resume as diferenças:
| Ferramenta | Cenário indicado | Principal vantagem | Principal desvantagem | Dificuldade inicial |
|---|---|---|---|---|
| Docker Secrets | Cluster Docker Swarm | Suporte nativo, sem custo adicional e configuração simples | Funciona apenas com Swarm, tem recursos básicos e não é multiplataforma | ⭐ Baixa |
| Kubernetes Secrets | Ambiente K8s de produção | Suporte nativo no ecossistema K8s e integração com o ciclo de vida dos Pods | O etcd não é criptografado por padrão; exige configuração adicional para ficar seguro | ⭐⭐ Média |
| HashiCorp Vault | Empresas, ambientes multicloud e requisitos rigorosos de conformidade | Conjunto completo de recursos, credenciais dinâmicas, permissões granulares, logs de auditoria e vários backends | Arquitetura complexa, implantação e manutenção próprias e curva de aprendizado acentuada | ⭐⭐⭐ Alta |
| AWS Secrets Manager | Ambiente totalmente baseado na AWS, com serviços como RDS e Lambda | Integração profunda com a AWS, rotação automática de senhas do RDS e serviço gerenciado | Dependência da AWS, dificuldade em ambientes multicloud e custo de uso | ⭐⭐ Média |
Em resumo:
- Projeto pequeno com Docker Swarm → Docker Secrets é suficiente, simples e gratuito
- Kubernetes em produção → Comece com K8s Secrets e use External Secrets Operator para integrar um Vault externo
- Empresa grande, multicloud e com requisitos elevados de segurança → Use Vault; o investimento inicial compensa no longo prazo
- Infraestrutura totalmente na AWS → Secrets Manager é a opção mais prática e funciona muito bem com RDS e Lambda
Não existe uma ferramenta universalmente melhor, apenas a mais adequada ao seu cenário. Minha própria trajetória foi começar com file secrets do docker-compose em projetos pequenos, migrar para Docker Swarm + Docker Secrets quando a equipe cresceu e, agora que a empresa migrou para K8s, avaliar a adoção do Vault.
Cada migração tem um custo, mas a segurança também melhorou gradualmente.
Recomendações para escolher
Como escolher na prática? Veja algumas referências para a decisão.
Se você é…
Desenvolvedor independente ou projeto pequeno:
- Desenvolvimento local: file secrets do docker-compose é suficiente
- Alguns serviços implantados em uma VPS: Docker Swarm + Docker Secrets
- Orçamento limitado e pouca disposição para manter infraestrutura: evite o Vault, pois ele é pesado demais
Startup com 10 a 50 pessoas:
- Usa Docker: Docker Secrets
- Usa K8s: K8s Secrets + External Secrets Operator, em uma adoção gradual que permite migrar para Vault depois
- Está totalmente na AWS: Secrets Manager é a opção mais prática
Empresa grande:
- Ambiente multicloud: Vault é praticamente a única opção
- Necessidade de auditoria e conformidade: Vault
- Equipe de segurança dedicada: Vault
- Orçamento suficiente e tolerância à curva de aprendizado: Vault
Versão simplificada da árvore de decisão:
Você usa K8s?
└─ Sim → Use K8s Secrets; para recursos avançados, use Vault
└─ Não → Usa Docker Swarm?
└─ Sim → Docker Secrets
└─ Não → Está na AWS?
└─ Sim → AWS Secrets Manager
└─ Não → file secrets do docker-compose (desenvolvimento) / Vault (produção)
Casos práticos
Vou contar duas trajetórias reais de escolha que conheço.
Caso 1: a evolução de uma startup
A empresa SaaS de um amigo começou com cinco pessoas e todos os serviços Docker em uma única VPS. No início, eles usavam docker-compose + file secrets, com arquivos de senha armazenados no servidor e gerenciados manualmente.
Seis meses depois, a empresa recebeu investimento-anjo, a equipe cresceu para 15 pessoas e os serviços foram divididos em uma arquitetura de microsserviços. Nesse momento, adotaram Docker Swarm e migraram para Docker Secrets. O principal benefício foi a praticidade: eles deixaram de distribuir arquivos de senha manualmente entre servidores e passaram a gerenciar os secrets de forma centralizada no cluster Swarm.
Um ano depois, após a rodada Série A, migraram para K8s quando contrataram profissionais de DevOps. Começaram a usar K8s Secrets, mas também adotaram AWS RDS, S3 e outros serviços. As credenciais relacionadas à AWS passaram a ser gerenciadas pelo Secrets Manager, e o External Secrets Operator sincronizava esses valores com os secrets do K8s.
Agora, eles avaliam uma migração completa para Vault. A empresa está adotando uma estratégia multicloud e considera usar GCP para backups, o que torna a dependência do Secrets Manager da AWS menos adequada.
Percebeu? A arquitetura de segurança evolui junto com o negócio; não é preciso começar pela solução mais complexa.
Caso 2: uma empresa tradicional começa pela solução completa
Outro amigo trabalha com tecnologia em um banco. No ano passado, a empresa iniciou uma modernização baseada em contêineres. Como o setor financeiro tem requisitos rigorosos de conformidade, eles adotaram o Vault desde o início.
Embora a curva de aprendizado tenha sido alta, os benefícios foram claros:
- Logs de auditoria completos, com registro de cada acesso a um segredo
- Suporte a credenciais dinâmicas, como acessos temporários ao banco que expiram automaticamente
- Integração com o LDAP existente para controle de permissões
Foram necessários dois meses-pessoa para implantação e treinamento, mas a equipe resolveu de uma vez os principais problemas de gerenciamento de segredos. Depois disso, o custo de manutenção ficou baixo.
Cenários diferentes exigem escolhas diferentes. Para uma empresa pequena, adotar Vault pode custar mais do que entrega; para uma empresa grande, Docker Secrets talvez seja limitado demais.
Checklist de práticas recomendadas para produção
Medidas de segurança para aplicar agora
Mesmo que você não use Docker Secrets, estas medidas devem ser tomadas imediatamente:
✅ Verifique se há informações sensíveis no histórico do Git
# procure palavras-chave que podem indicar senhas
git log -p -S 'password' -S 'secret' -S 'api_key'
# verifique se um arquivo .env já foi enviado ao repositório
git log --all --full-history -- .env
Se encontrar algo, use git filter-repo ou BFG Repo-Cleaner para remover completamente os dados do histórico. Depois, troque imediatamente todas as senhas expostas.
✅ Configure o .gitignore
# .gitignore
.env
*.env
secrets/
db_password.txt
*_password.txt
*_secret.txt
*.pem
*.key
Não conte com a sorte: inclua essas regras.
✅ Ative o GitHub Secret Scanning
Se você usa GitHub, abra as configurações do repositório e ative Security → Secret scanning alerts. Se uma chave for enviada por engano, o GitHub emitirá um alerta automático.
O plano gratuito oferece esse recurso apenas para repositórios públicos; repositórios privados exigem uma conta Pro, Team ou Enterprise. Como repositórios públicos precisam ainda mais dessa proteção, ative-a o quanto antes.
✅ Troque todas as credenciais que podem ter vazado
Faça um inventário de:
- Senhas de bancos de dados
- Chaves de API, como AWS, OpenAI e Stripe
- JWT secret
- OAuth client secrets
- Chaves privadas SSL
Troque tudo o que for possível. Mesmo depois de um vazamento, ainda dá tempo de reduzir o dano.
Etapas para implementar Docker Secrets
Decidiu usar Docker Secrets? Siga esta ordem:
Etapa 1: faça um inventário das informações sensíveis
Liste tudo o que precisa ser protegido:
✓ Senha de root do MySQL
✓ Senha do banco de dados da aplicação
✓ Senha do Redis
✓ Chave de assinatura JWT
✓ Chaves de API de terceiros (pagamento, SMS etc.)
✓ Chave privada do certificado SSL
✓ OAuth client secret
Etapa 2: escolha a ferramenta
Com base na comparação anterior, escolha Docker Secrets, K8s Secrets ou Vault. Não fique paralisado pela decisão: adote uma opção agora e migre depois, se necessário.
Etapa 3: crie os secrets
# se você usa Docker Swarm
docker swarm init
docker secret create db_password <(echo "senha")
docker secret create api_key <(echo "chave")
# se você usa file secrets do docker-compose
mkdir secrets
echo "senha" > secrets/db_password.txt
echo "chave" > secrets/api_key.txt
chmod 600 secrets/*
Etapa 4: altere o arquivo de configuração
Substitua os campos de environment no docker-compose.yml por secrets:
# antes
services:
app:
environment:
DB_PASSWORD: "hardcoded_password" # ❌
# depois
services:
app:
secrets:
- db_password
environment:
DB_PASSWORD_FILE: /run/secrets/db_password # ✅
Etapa 5: altere o código da aplicação, se necessário
Se o framework não oferecer suporte ao sufixo _FILE, adapte o código para ler o arquivo:
// exemplo em Node.js
const fs = require('fs');
const dbPassword = process.env.DB_PASSWORD_FILE
? fs.readFileSync(process.env.DB_PASSWORD_FILE, 'utf8').trim()
: process.env.DB_PASSWORD;
Etapa 6: teste e valide
Primeiro, execute tudo no ambiente de teste e confirme que:
- O serviço inicia normalmente
- A senha é lida corretamente
docker inspectnão mostra o valor em texto simples- As funcionalidades continuam funcionando
Etapa 7: implante em produção
Se tudo estiver certo, faça a implantação em produção. Por segurança, mantenha temporariamente a configuração antiga de variáveis de ambiente como fallback. Remova-a somente depois de confirmar que a nova solução está estável.
Manutenção contínua da segurança
Adotar Docker Secrets não resolve tudo para sempre. A segurança exige manutenção contínua.
Faça a rotação periódica dos segredos — a recomendação é a cada 90 dias
Crie um lembrete no calendário e troque as senhas a cada trimestre. Quando alguém sair da empresa, troque também todas as senhas relacionadas ao acesso dessa pessoa.
Monitore os logs de acesso aos segredos
Se você usa Vault, revise periodicamente os logs de auditoria e procure padrões de acesso anormais.
Docker Secrets e K8s Secrets não oferecem logs de auditoria por padrão, o que é uma limitação. Se você precisa desse controle, combine-os com outras ferramentas, como Falco.
Aplique o princípio do menor privilégio
Não permita que todos os serviços acessem todos os secrets. Cada serviço deve receber apenas o que realmente precisa:
services:
frontend:
secrets:
- api_key # o frontend só precisa da chave da API
backend:
secrets:
- db_password # o backend precisa da senha do banco
- api_key
Use ferramentas de varredura de segredos
Integre estas ferramentas ao CI/CD:
- trufflehog: examina o histórico do Git
- git-secrets: evita commits com informações sensíveis
- gitleaks: detecta segredos no código
Executá-las em um hook de pre-commit ajuda a impedir muitos envios acidentais.
Cinco cuidados para evitar armadilhas
Por fim, veja alguns erros comuns.
1. Não use ARG para transmitir informações sensíveis
# ❌ errado
ARG DB_PASSWORD=secret
ENV DATABASE_URL=postgres://user:${DB_PASSWORD}@db/myapp
O valor de ARG fica registrado no histórico de build da imagem e pode ser visto com docker history.
2. Não imprima secrets em stdout
# ❌ errado
password = open('/run/secrets/db_password').read()
print(f"Using password: {password}") # aparecerá no docker logs!
O sistema de logs captura toda a saída stdout. Depois que uma senha entra nos logs, removê-la completamente é muito difícil.
3. Não use o mesmo secret em vários ambientes
Separe as senhas de desenvolvimento, teste e produção. Não reutilize o mesmo valor por conveniência; se o ambiente de teste for comprometido, a produção também ficará em risco.
4. Não copie o secret para outro caminho dentro do contêiner
# ❌ errado
cp /run/secrets/db_password /app/config/password.txt
/run/secrets usa tmpfs, um sistema de arquivos em memória cujo conteúdo desaparece quando o contêiner para. Se você copiar o arquivo para outro caminho, ele poderá ser gravado em disco, o que reduz a segurança.
Leia o valor diretamente de /run/secrets.
5. Não se esqueça de monitorar a expiração e a rotação dos secrets
Se você usa credenciais dinâmicas com prazo de validade, como as oferecidas pelo Vault, configure renovação ou rotação automática. Não espere a senha expirar no meio da noite e derrubar todos os serviços para descobrir o problema.
Conclusão
Depois de tudo isso, a ideia principal cabe em uma frase: não coloque senhas em lugares onde elas podem ser vistas.
Variáveis de ambiente parecem convenientes, mas docker inspect pode expor todos os valores. Instruções ENV no Dockerfile são ainda mais perigosas, pois ficam registradas permanentemente nas camadas da imagem. Muitos incidentes de segurança começam com pequenos atalhos adotados por conveniência.
Docker Secrets não é perfeito: exige o modo Swarm, não permite alterar o conteúdo de um secret e é pouco prático para desenvolvimento em uma única máquina. Ainda assim, resolve o problema central: os segredos são armazenados e transmitidos de forma criptografada e não aparecem nas variáveis de ambiente nem nas imagens. Para um cluster Docker Swarm, é a solução mais simples e direta.
Se você usa Kubernetes, escolha K8s Secrets. Para necessidades corporativas, considere Vault. Se toda a infraestrutura está na AWS, Secrets Manager também é uma boa opção. Não existe a melhor ferramenta para todos, apenas a mais adequada a cada cenário.
O importante é começar. Ainda hoje, verifique:
- Há senhas no histórico do seu Git?
- O arquivo
.envestá no.gitignore? docker inspectconsegue mostrar suas senhas?
Se as respostas forem “sim”, “não” e “sim”, reserve um tempo para corrigir isso. Você não precisa implantar Vault de uma vez; até mesmo substituir variáveis de ambiente por file secrets já melhora a situação.
Segurança é um processo contínuo, não uma configuração feita uma única vez. Faça a rotação periódica de senhas, monitore acessos anormais e use ferramentas de varredura no código. Esses hábitos são mais importantes que qualquer ferramenta isolada.
Por fim, compartilhe este artigo com sua equipe. O gerenciamento de segredos não é responsabilidade de uma única pessoa, mas de todos. Padronizar as práticas e fazer revisões periódicas é o que realmente reduz os riscos.
Espero que os alertas das três da manhã não voltem a acordar você.
Recursos de referência:
- Documentação oficial do Docker — Manage sensitive data with Docker secrets
- Documentação oficial do HashiCorp Vault
- AWS Secrets Manager
- trufflehog — ferramenta para procurar segredos no Git
Processo completo para gerenciar segredos com segurança no Docker
Gerencie senhas e chaves de API de contêineres com segurança, compare Docker, Kubernetes e Vault e siga um checklist completo para produção
⏱️ Estimated time: 1 hr
- 1
Step 1: Entenda o problema de segurança e as práticas erradas
Problema de segurança:
• O invasor usou diretamente a senha correta: a senha do MySQL gravada no docker-compose.yml
• No mês anterior, um estagiário havia feito fork do projeto para um repositório público pessoal
• O vazamento da senha levou a varreduras por força bruta no banco de dados
Práticas erradas:
• Colocar a senha diretamente no arquivo de configuração
• Achar que usar variáveis de ambiente já resolve a segurança
• Dizer 'meu repositório é privado, então não há problema'
• Todas essas práticas criam riscos de segurança
Erros comuns:
• Colocar senhas no Dockerfile
• Colocar senhas no docker-compose.yml
• Usar senhas em variáveis de ambiente e enviá-las ao Git
• Usar um arquivo .env e esquecer de adicioná-lo ao .gitignore - 2
Step 2: Use Docker Secrets para gerenciar segredos
Solução com Docker Secrets:
• Crie o segredo com docker secret create: docker secret create mysql_password -
• Configure secrets no docker-compose.yml: secrets: - mysql_password
• Acesse o segredo no contêiner pelo caminho /run/secrets/: cat /run/secrets/mysql_password
• O segredo fica armazenado de forma criptografada no Docker Swarm
Criação do segredo:
• echo "your-password" | docker secret create mysql_password -
• Referencie-o no docker-compose.yml: secrets: - mysql_password
• Leia-o no contêiner: cat /run/secrets/mysql_password - 3
Step 3: Compare outras soluções e aplique as práticas recomendadas
Comparação com outras soluções:
• Docker Secrets (indicado para Docker Swarm, com armazenamento criptografado)
• Kubernetes Secrets (indicado para ambientes K8s, com codificação Base64)
• HashiCorp Vault (gerenciamento corporativo, com suporte a credenciais dinâmicas)
• AWS Secrets Manager (indicado para ambientes AWS e integrado aos serviços da AWS)
• Arquivo de variáveis de ambiente (.env, não recomendado para produção)
Práticas recomendadas:
• Em produção, use um gerenciador de secrets para informações sensíveis
• Faça a rotação periódica dos segredos
• Use uma ferramenta de varredura de segredos, como trufflehog, para verificar o repositório Git
• Configure o controle de acesso para evitar vazamentos
• Nunca grave senhas diretamente no código
FAQ
Por que não se deve colocar senhas no Dockerfile ou no docker-compose.yml?
Práticas erradas:
• Colocar a senha diretamente no arquivo de configuração
• Achar que usar variáveis de ambiente já resolve a segurança
• Dizer 'meu repositório é privado, então não há problema'
• Todas essas práticas criam riscos de segurança
Erros comuns:
• Colocar senhas no Dockerfile
• Colocar senhas no docker-compose.yml
• Usar senhas em variáveis de ambiente e enviá-las ao Git
• Usar um arquivo .env e esquecer de adicioná-lo ao .gitignore
Como usar Docker Secrets para gerenciar segredos?
• Crie o segredo com docker secret create (docker secret create mysql_password -)
• Configure secrets no docker-compose.yml (secrets: - mysql_password)
• Acesse o segredo no contêiner pelo caminho /run/secrets/ (cat /run/secrets/mysql_password)
• O segredo fica armazenado de forma criptografada no Docker Swarm
Criação do segredo:
• echo "your-password" | docker secret create mysql_password -
• Referencie-o no docker-compose.yml: secrets: - mysql_password
• Leia-o no contêiner: cat /run/secrets/mysql_password
Qual é a diferença entre Docker Secrets e outras soluções de gerenciamento de segredos?
• Docker Secrets (indicado para Docker Swarm, com armazenamento criptografado)
• Kubernetes Secrets (indicado para ambientes K8s, com codificação Base64)
• HashiCorp Vault (gerenciamento corporativo, com suporte a credenciais dinâmicas)
• AWS Secrets Manager (indicado para ambientes AWS e integrado aos serviços da AWS)
• Arquivo de variáveis de ambiente (.env, não recomendado para produção)
Recomendação de escolha:
• Em ambientes Docker Swarm, use Docker Secrets
• Em ambientes K8s, use Kubernetes Secrets
• Para necessidades corporativas, use Vault
• Em ambientes AWS, use Secrets Manager
Quais são as práticas recomendadas de gerenciamento de segredos em produção?
• Em produção, use um gerenciador de secrets para informações sensíveis
• Faça a rotação periódica dos segredos
• Use uma ferramenta de varredura de segredos, como trufflehog, para verificar o repositório Git
• Configure o controle de acesso para evitar vazamentos
• Nunca grave senhas diretamente no código
Verificações periódicas:
• Use trufflehog para examinar o repositório Git
• Verifique se houve vazamento de segredos
• Configure uma varredura automática no fluxo de CI/CD
• Ao encontrar um vazamento, faça imediatamente a rotação do segredo
24 min de leitura · Publicado em: 18 dez 2025 · Atualizado em: 4 set 2026
Guia prático Docker
Se você chegou pela busca, o caminho mais rápido é ir para o post anterior ou próximo desta série.
Anterior
Segurança no Docker: como evitar contêineres executados como root
Entenda os riscos de executar contêineres Docker como root e configure usuários sem privilégios, Capabilities, sistema de arquivos somente leitura e AppArmor para proteger ambientes de produção.
Parte 27 de 34
Próximo
Guia completo de limites de recursos no Docker: evite que vazamentos de memória derrubem o servidor
Como um vazamento de memória em um contêiner pode derrubar o servidor inteiro? Este guia vai dos fundamentos de cgroups à prática com --memory e --cpus, além do monitoramento com docker stats, cAdvisor e Prometheus para proteger ambientes de produção com limites de recursos.
Parte 29 de 34



Comentários
Entre com GitHub para comentar