Gestão de Secrets na Prática: Onde Guardar Senhas, Chaves e Tokens
Segredo em variável de ambiente, em arquivo commitado ou em Vault? Entenda o ciclo de vida de um secret, rotação, criptografia em repouso e os padrões que evitam o próximo vazamento.
Neste artigo
Toda aplicação séria precisa provar quem é para falar com o banco, com a fila, com o provedor de pagamento. Essa prova é um segredo: uma senha, uma chave de API, um token, um certificado. E é justamente o material mais sensível do sistema que, historicamente, é tratado com o menor cuidado — colado num arquivo .env que vai parar no Git, exposto numa variável que aparece em log, ou compartilhado por mensagem entre a equipe.
Gestão de secrets é a disciplina de guardar, distribuir, rotacionar e revogar esse material sem que ele vaze e sem que a operação trave. Não é um produto que você compra e esquece; é um conjunto de decisões sobre o ciclo de vida de cada segredo. Vamos entender esse ciclo e os padrões que separam uma operação madura de um incidente esperando para acontecer.
O que é um secret, e por que ele é diferente de config#
Nem toda configuração é secreta. A URL de um serviço, o nível de log, o timeout de uma requisição — isso é config comum, pode ir para um ConfigMap, um arquivo versionado, um painel. Um secret é a subclasse de config cujo vazamento compromete a segurança: credenciais, chaves de assinatura, tokens de acesso.
A distinção importa porque os dois exigem tratamentos diferentes. Config pode ser lida por qualquer um com acesso ao ambiente. Secret precisa de criptografia em repouso, controle de acesso granular, auditoria de quem leu, e um plano de rotação. Misturar os dois — jogar senha no mesmo ConfigMap da config — é o primeiro erro.
O ciclo de vida de um secret#
Pensar em ferramenta antes de pensar em ciclo de vida é colocar o carro na frente dos bois. Todo segredo passa por cinco fases, e a maioria dos vazamentos acontece por descuido em uma delas.
Geração#
Um segredo precisa ser gerado com entropia suficiente e por uma fonte criptograficamente segura. Senha de serviço, token de sessão, chave de API: nada disso pode sair de um gerador previsível.
``bash # Token com 256 bits de entropia, de uma fonte CSPRNG. openssl rand -base64 32 # ou head -c 32 /dev/urandom | base64 ``
Nunca use Math.random(), o relógio do sistema ou um "gerador de senha" caseiro para material sensível. Se dá para prever, dá para forjar.
Armazenamento#
O segredo em repouso precisa estar criptografado. É aqui que entra o conceito de envelope encryption: o segredo é cifrado com uma chave de dados (DEK), e essa chave de dados é cifrada por uma chave-mestra (KEK) que fica em um módulo separado (um HSM ou um KMS gerenciado). Assim, roubar o banco onde os segredos moram não basta — sem a chave-mestra, o dado é ruído.
Distribuição#
O segredo precisa chegar até a aplicação em runtime, sem passar por lugares que o exponham. Os caminhos mais comuns, do pior para o melhor:
- Hardcoded no código: proibido. O segredo vira parte do artefato e vaza para
todo mundo com acesso ao repositório ou à imagem.
- Variável de ambiente: aceitável, mas com ressalvas — variáveis vazam em
dumps de processo, logs de erro e ferramentas de introspecção. Melhor que hardcoded, longe do ideal.
- Arquivo montado em runtime: a plataforma monta o segredo como um arquivo em
um volume tmpfs (memória), que a aplicação lê. Não persiste em disco, não aparece na lista de variáveis.
- Busca dinâmica via API: a aplicação pede o segredo a um cofre no momento em
que precisa, autenticando-se com uma identidade de máquina. O segredo nunca é gravado em lugar nenhum fixo.
Rotação#
Todo segredo tem prazo de validade. Rotação é trocar o segredo antigo por um novo periodicamente — e, obrigatoriamente, após qualquer suspeita de vazamento. O desafio operacional é rotacionar sem downtime: durante a janela de troca, o segredo velho e o novo precisam ser aceitos ao mesmo tempo, senão a aplicação cai no momento do corte.
``text t0: válido = [chave_A] # só a chave antiga t1: válido = [chave_A, chave_B] # nova entra, ambas aceitas t2: aplicações recarregam, passam a usar chave_B t3: válido = [chave_B] # chave antiga revogada ``
Segredos de vida curta são a evolução dessa ideia: em vez de rotacionar uma senha estática a cada 90 dias, o cofre gera credenciais dinâmicas que expiram em minutos ou horas. Um vazamento de uma credencial que expira em 15 minutos tem impacto minúsculo.
Revogação e auditoria#
Quando um segredo vaza ou um serviço é desativado, você precisa revogar imediatamente e ter o registro de quem acessou o quê e quando. Sem auditoria, um vazamento vira um mistério: você não sabe o que foi comprometido, então tem de tratar tudo como comprometido.
O antipadrão número um: segredo no repositório#
O erro mais comum e mais caro é commitar segredo no controle de versão. E o detalhe cruel: apagar o segredo em um commit posterior não resolve. O Git guarda o histórico inteiro; o segredo continua lá, recuperável, para sempre — ou até você reescrever o histórico, o que é doloroso.
A defesa tem camadas:
``bash # .gitignore barra os arquivos de ambiente. echo ".env" >> .gitignore echo "*.pem" >> .gitignore echo "secrets/" >> .gitignore ``
Além do .gitignore, vale um scanner de segredos rodando no pipeline e como hook de pré-commit, que detecta padrões de chave (AWS, tokens, chaves privadas) antes que entrem no repositório. E, no dia em que um segredo vaza para o Git, a regra é dura e inegociável: rotacione o segredo. Ele deve ser considerado comprometido no instante em que tocou o repositório, mesmo em repo privado.
Segredos no Kubernetes: o que o <code>Secret</code> é e o que não é#
Kubernetes tem um objeto chamado Secret, e ele confunde muita gente. Por padrão, um Secret é apenas codificado em base64, não criptografado. Base64 é ofuscação, não segurança — qualquer um com acesso de leitura ao objeto decodifica em um comando.
``bash # base64 não é criptografia; isto "revela" o segredo trivialmente. echo "c2VuaGEtc3VwZXItc2VjcmV0YQ==" | base64 -d ``
Para que o Secret do Kubernetes seja realmente seguro, você precisa de três coisas que não vêm ativadas por padrão:
- Encryption at rest do etcd: configurar o cluster para cifrar os secrets
antes de gravá-los no etcd, idealmente com uma KEK em um KMS externo.
- RBAC restritivo: limitar quem e quais service accounts podem ler cada
secret. Sem isso, qualquer pod no namespace pode ler tudo.
- Nunca versionar o manifesto do Secret com o valor real. Isto reabre o
problema do segredo no Git.
É por causa dessas limitações que padrões complementares surgiram. O Sealed Secrets permite versionar o segredo cifrado no Git (só o controlador no cluster consegue decifrar), viabilizando GitOps sem expor o valor. O External Secrets busca o segredo de um cofre externo e o materializa como Secret nativo, mantendo a fonte da verdade fora do cluster.
Cofres centralizados e identidade de máquina#
Em uma operação madura, os segredos moram em um cofre central — um gerenciador dedicado — e as aplicações os buscam em runtime. A pergunta que sempre aparece é: "se a aplicação precisa de uma credencial para autenticar no cofre, onde guardo essa credencial?" É o problema do secret zero.
A resposta moderna é identidade de máquina: a aplicação não usa uma senha para provar quem é ao cofre; ela usa uma identidade emitida pela própria plataforma — o service account do pod no Kubernetes, o IAM role da instância na nuvem — que o cofre verifica. O primeiro segredo deixa de existir porque a identidade é atestada pela infraestrutura, não por um segredo pré-compartilhado.
``text Pod --(identidade do service account)--> Cofre Cofre verifica a identidade com o control plane do cluster Cofre devolve credencial dinâmica de banco, válida por 1h Pod usa a credencial; ela expira sozinha ``
Esse é o pulo do gato: credenciais dinâmicas e de vida curta, emitidas sob demanda para identidades atestadas, eliminam boa parte da superfície de ataque. Não há senha estática de banco para vazar — a que existe hoje some em uma hora.
Um roteiro pragmático#
Nem todo time precisa, no dia um, de um cofre com credenciais dinâmicas. A maturidade se constrói em camadas, e sair do zero já reduz muito o risco. Uma progressão sensata:
- Tire os segredos do código e do Git. Scanner no pipeline,
.gitignore
correto, rotação imediata do que já vazou. Este passo sozinho elimina a maioria dos incidentes.
- Separe secret de config. Segredos em um mecanismo próprio, com acesso
restrito e criptografia em repouso; config comum onde for prático.
- Injete em runtime, de preferência como arquivo em memória, não hardcoded
na imagem.
- Centralize num cofre com controle de acesso e auditoria, à medida que o
número de serviços cresce.
- Evolua para credenciais dinâmicas e de vida curta onde o backing service
suportar, começando pelos mais sensíveis (banco, chaves de assinatura).
Vale um alerta sobre um erro sutil que aparece mesmo em times cuidadosos: o segredo que vaza para lugares indiretos. Um segredo bem guardado no cofre pode escapar por caminhos laterais — impresso num log de erro, exposto numa mensagem de exceção devolvida ao cliente, incluído no corpo de uma requisição capturada por uma ferramenta de APM, ou gravado num arquivo de core dump. A gestão de secrets não termina no armazenamento; ela exige disciplina em toda a borda onde o segredo circula. Redija segredos antes de logar, nunca ecoe detalhe interno em respostas de erro, e trate como comprometido qualquer credencial que possa ter passado por um desses canais. O cofre mais robusto do mundo não protege contra um print(config) esquecido no código.
Outro ponto frequentemente ignorado é a separação por ambiente. O segredo de produção nunca deve estar acessível em desenvolvimento ou homologação, e vice-versa. Cada ambiente tem seu próprio conjunto de credenciais, isolado dos demais, para que o comprometimento de um ambiente de teste — tipicamente menos protegido — não dê acesso a produção. Compartilhar a mesma chave de banco entre dev e prod "para simplificar" é criar uma ponte direta do ambiente mais frágil para o mais crítico. A paridade entre ambientes, tão desejável em config comum, tem exatamente a exceção oposta nos segredos: aqui o isolamento é a regra.
A regra que costura tudo: um segredo que você não sabe rotacionar rápido é um segredo que vai te assustar no pior momento possível. Projete para a rotação desde o começo — assuma que todo segredo vai vazar um dia e pergunte-se quanto tempo levaria para trocá-lo em produção sem derrubar nada. Se a resposta for "não faço ideia", você já sabe qual é a próxima tarefa da sprint.