Pular para o conteúdo
Categoria: Segurança da Informação14 min de leitura

Gestão de segredos e chaves de API sem vazar dados

Por Schematize Blog ·

Como armazenar, injetar e rotacionar chaves de API e segredos com segurança, por que nunca commitar credenciais e como construir um ciclo de vida completo de gestão de segredos.

Toda aplicação moderna depende de segredos: chaves de API, senhas de banco, tokens de acesso. E quase todo desenvolvedor já cometeu, ao menos uma vez, o pecado de deixar um desses segredos escapar — num commit, num log, num print de tela. Neste artigo você vai aprender a tratar segredos como o ativo crítico que eles são: onde guardá-los, como entregá-los à aplicação, como rotacioná-los quando algo dá errado e como construir um ciclo de vida que torna o vazamento um incidente controlado em vez de uma catástrofe.

O que conta como segredo

Antes de proteger, é preciso reconhecer. Um segredo é qualquer credencial que dá acesso a um recurso e que, nas mãos erradas, causa dano. Os mais comuns:

    A OWASP Foundation (2021), no Application Security Verification Standard 4.0, dedica uma seção inteira à gestão de segredos justamente porque o vazamento de credenciais é uma das vias mais diretas para um comprometimento total. Uma chave de banco vazada não é "um bug" — é acesso de leitura e escrita a todos os seus dados.

    Vale também distinguir segredo de configuração. A URL pública da sua API não é um segredo; a chave que autentica chamadas para ela é. Confundir os dois leva a dois erros opostos: tratar configuração trivial com cerimônia excessiva, e tratar credencial real como se fosse configuração inofensiva. A pergunta-guia é simples: se isto vazar, alguém consegue fazer algo que não deveria? Se a resposta for sim, é segredo.

    O pecado capital: segredos no código

    A regra mais importante é também a mais violada: nunca coloque segredos no código-fonte. Isso inclui hardcodar uma chave numa variável, deixá-la num arquivo de configuração versionado ou colá-la num comentário "temporário".

    O problema não é só o presente. Sistemas de controle de versão guardam histórico. Quando você entende o que é Git e como funciona o controle de versão, percebe que apagar um segredo num commit posterior não o remove do histórico — ele continua recuperável por qualquer pessoa com acesso ao repositório. Por isso, um segredo commitado deve ser considerado comprometido e rotacionado imediatamente, mesmo que você "já tenha apagado".

    Há ainda o agravante dos repositórios públicos. Bots varrem o GitHub continuamente em busca de padrões de chave recém-publicados; o intervalo entre commitar uma chave de nuvem e vê-la sendo abusada para minerar criptomoedas pode ser de minutos. Não é exagero teórico — é um dos incidentes mais documentados da indústria.

    Duas defesas práticas:

      Um exemplo de .gitignore mínimo para um projeto que usa arquivos de ambiente:

      # Arquivos de segredo nunca versionados
      .env
      .env.*
      !.env.example
      *.pem
      *.key
      secrets/

      Repare na linha !.env.example: ela reabre uma exceção para um arquivo de exemplo, sem valores reais, que documenta quais variáveis o projeto espera. Esse arquivo é commitável e ajuda novos desenvolvedores a configurar o ambiente sem nunca expor um valor verdadeiro.

      Variáveis de ambiente: o básico bem feito

      A forma mais difundida de injetar segredos é por variáveis de ambiente. Em vez de a chave viver no código, ela vive no ambiente onde a aplicação roda, e o código apenas a lê:

      import os
      
      api_key = os.environ.get("OPENAI_API_KEY")
      if not api_key:
          raise RuntimeError("OPENAI_API_KEY não configurada")

      Repare no detalhe: ler com os.environ.get e validar a presença logo no início ("fail fast") evita que a aplicação suba pela metade e só quebre na primeira chamada externa, muitas vezes em produção e sob carga. Validar a configuração no boot é uma prática barata que economiza horas de depuração.

      Em desenvolvimento, é comum usar um arquivo .env (nunca versionado) carregado por uma biblioteca como python-dotenv, dotenv no Node ou equivalentes. Em produção, as variáveis são definidas pela plataforma de deploy. Esse padrão já é um enorme avanço sobre hardcodar, e é o mínimo aceitável. Ele é, inclusive, um dos princípios do manifesto Twelve-Factor App (Wiggins, 2017): configuração que varia entre ambientes deve viver no ambiente, não no código.

      Mas variáveis de ambiente têm limites:

        Para sistemas maiores, variável de ambiente é o ponto de partida, não a linha de chegada.

        Gerenciadores de segredos

        Um gerenciador de segredos (secrets manager) é um serviço dedicado a guardar, controlar acesso e auditar segredos. Exemplos incluem HashiCorp Vault e os serviços gerenciados das nuvens (AWS Secrets Manager, Google Secret Manager, Azure Key Vault). As vantagens sobre variáveis de ambiente:

          A ideia de cada serviço ter sua própria identidade para buscar segredos conecta-se diretamente ao controle de acesso da aplicação. Vale entender a diferença entre autenticação e autorização: o gerenciador de segredos autentica qual serviço está pedindo e autoriza quais segredos ele pode ler.

          Na prática, o acesso a um gerenciador segue mais ou menos este fluxo:

          1. A aplicação inicia com uma identidade (role IAM, token de service account, etc.).
          2. Ela apresenta essa identidade ao gerenciador de segredos.
          3. O gerenciador verifica a política: essa identidade pode ler este segredo?
          4. Se autorizado, devolve o segredo cifrado em trânsito (TLS).
          5. A aplicação mantém o segredo apenas em memória, nunca em disco.
          6. O acesso é registrado no log de auditoria.

          O ponto sutil e importante é o problema do segredo-zero (secret zero): para buscar segredos, a aplicação precisa de alguma credencial inicial. A boa arquitetura resolve isso amarrando essa credencial à identidade da infraestrutura (uma role de instância na nuvem, por exemplo), de modo que nenhuma chave de longo prazo precise ser distribuída manualmente. É a infraestrutura que prova "eu sou esta máquina", e o resto deriva daí.

          Segredos dinâmicos: o ideal a almejar

          Segredos dinâmicos levam a ideia adiante. Em vez de uma senha de banco fixa que vive por meses, o gerenciador cria um par usuário/senha na hora, válido por minutos ou horas, e o destrói depois. Se esse segredo vazar, a janela de abuso é minúscula. Para bancos, filas e provedores de nuvem, segredos dinâmicos são o padrão-ouro porque eliminam a credencial de longa duração — o alvo mais valioso para um atacante.

          Rotação: porque vazamentos acontecem

          Rotacionar um segredo é substituí-lo por um novo e invalidar o antigo. É a sua rede de segurança para quando — não se — um segredo vazar. Boas práticas:

            A possibilidade de rotacionar depende de uma decisão de arquitetura tomada cedo: se a sua aplicação lê a chave de uma fonte central a cada uso, rotacionar é trocar um valor; se a chave está espalhada em dez lugares, é um pesadelo. Centralizar a origem dos segredos é o que torna a rotação viável.

            O padrão de chaves sobrepostas

            A rotação sem downtime quase sempre usa o padrão de sobreposição (overlap). A ideia é manter duas chaves válidas ao mesmo tempo durante a janela de troca:

            T0  → Chave A ativa.                          Validamos: A.
            T1  → Cria-se a Chave B. As duas valem.       Validamos: A ou B.
            T2  → Todos os clientes passam a usar B.       Validamos: A ou B.
            T3  → Chave A é revogada.                      Validamos: B.

            Esse padrão se aplica tanto a chaves de API entre serviços quanto a chaves de assinatura de JWT. No caso do JWT, por exemplo, manter a chave antiga válida por um período permite que tokens já emitidos continuem aceitos até expirarem naturalmente, sem deslogar todos os usuários de uma vez. Pular a etapa de sobreposição é a causa número um de "rotacionei a chave e derrubei a produção".

            Segredos e chaves criptográficas

            Nem todo segredo é uma senha de acesso; alguns são chaves criptográficas, e essas têm um ciclo de vida próprio. Uma chave usada para cifrar dados não pode simplesmente ser descartada na rotação — você precisa conseguir decifrar os dados antigos. Entender o que é criptografia, abordando simétrica, assimétrica e hashing, ajuda a desenhar esse ciclo: versionar chaves, manter as antigas disponíveis apenas para decifrar e usar a nova para cifrar é o padrão que evita perder acesso aos próprios dados.

            Uma técnica que simplifica muito esse cenário é a envelope encryption. Em vez de cifrar todos os dados diretamente com a sua chave mestra, você cifra cada dado com uma chave de dados única e, então, cifra apenas essa chave de dados com a chave mestra. Rotacionar a chave mestra passa a exigir recifrar apenas as pequenas chaves de dados, não terabytes de informação. É assim que os serviços de gerenciamento de chaves (KMS) das nuvens operam por baixo dos panos.

            Segredos no caminho de produção

            A entrega de segredos não termina na aplicação; ela atravessa todo o pipeline. Alguns pontos de atenção frequentemente esquecidos:

              Vale insistir no caso do Docker, porque é uma armadilha sutil. Mesmo que você remova um segredo num passo posterior do Dockerfile, a camada onde ele foi introduzido continua na imagem e pode ser extraída com docker history ou inspecionando o sistema de arquivos em camadas. A solução moderna é usar montagens de segredo em build (--mount=type=secret), que disponibilizam o valor apenas durante aquele passo, sem persistir em nenhuma camada:

              # syntax=docker/dockerfile:1
              RUN --mount=type=secret,id=npm_token \
                  NPM_TOKEN=$(cat /run/secrets/npm_token) npm ci

              No CI, o equivalente é registrar o segredo como uma variável protegida e garantir que a ferramenta o mascare automaticamente na saída. Mas mascaramento não é infalível: se você transforma o segredo (codifica em base64, por exemplo) e imprime o resultado, o mascaramento por correspondência exata não pega. A regra é não imprimir, nunca.

              Esses cuidados conversam diretamente com a proteção dos seus endpoints. Reforçar a segurança de APIs e proteger seus endpoints inclui garantir que os segredos que autenticam chamadas entre serviços não vazem nos próprios fluxos que deveriam proteger.

              Caso prático: integrando uma API de terceiro

              Imagine que você está consumindo um serviço externo. Ao seguir os primeiros passos com a API da OpenAI na prática, o primeiro impulso é colar a chave direto no código para "testar rápido". Resista. O fluxo correto, desde o primeiro teste:

                Esse hábito custa poucos minutos e elimina a classe inteira de incidentes em que chaves de API de serviços pagos vazam e geram cobranças inesperadas ou abuso.

                Há um sexto passo que muita gente esquece: mantenha a chave fora do frontend. Uma chave de LLM ou de pagamento embarcada no JavaScript do navegador é pública por definição — qualquer pessoa abre o DevTools e a copia. Quando o cliente precisa falar com a API de terceiro, o caminho correto é o seu próprio backend agir como intermediário (proxy), guardando a chave do lado servidor e expondo apenas o que o cliente precisa. Segredo no frontend é, em essência, segredo publicado.

                Defesa em profundidade para segredos

                Nenhuma medida isolada é suficiente; combine camadas:

                  A OWASP Foundation (2021) e o NIST (2024) convergem nesse ponto: segurança não é um controle único, e sim camadas que se reforçam. Se uma falhar, outra contém o estrago.

                  Erros comuns que anulam tudo

                  Mesmo equipes que adotam um gerenciador de segredos tropeçam em detalhes. Os mais frequentes:

                    Perguntas frequentes

                    Variável de ambiente é seguro o suficiente? Para projetos pequenos e em estágio inicial, com .env fora do versionamento e injeção pela plataforma de deploy, sim — é o mínimo aceitável e cobre a maioria dos casos. À medida que cresce o número de serviços, segredos e pessoas com acesso, migrar para um gerenciador dedicado deixa de ser luxo e vira necessidade, principalmente pela auditoria e pela rotação.

                    Commitei uma chave por engano. Basta apagar no próximo commit? Não. O valor permanece no histórico do Git e deve ser considerado comprometido. O procedimento correto é: rotacionar a chave imediatamente no provedor (o que invalida a versão vazada), e só então, se necessário, reescrever o histórico. A ordem importa: rotacione primeiro, porque a limpeza do histórico leva tempo e a chave já está exposta.

                    Com que frequência devo rotacionar? Não há número mágico. Segredos de alto impacto (banco de dados, chaves de assinatura) merecem rotação mais frequente e, idealmente, automática. O mais importante é conseguir rotacionar rapidamente quando preciso — uma arquitetura que torna a rotação trivial vale mais do que um calendário rígido que ninguém cumpre.

                    Posso guardar segredos cifrados no próprio repositório? Existem ferramentas (como SOPS ou git-crypt) que cifram segredos antes de versioná-los, decifrando apenas em tempo de deploy com uma chave mestra guardada fora do repositório. É uma abordagem legítima para times pequenos, desde que a chave mestra esteja protegida. Ainda assim, você apenas moveu o problema do segredo-zero para a chave mestra — que continua exigindo cuidado.

                    Conclusão

                    Segredos são as chaves do reino, e tratá-los com descuido anula qualquer outra medida de segurança. O caminho é claro: nunca commite credenciais, injete-as por ambiente ou por um gerenciador dedicado, rotacione com regularidade e assuma que todo segredo exposto está comprometido. Comece pelo básico bem feito — .env no .gitignore e variáveis de ambiente — e evolua para um gerenciador de segredos com identidades por serviço, auditoria e, quando possível, segredos dinâmicos à medida que o sistema cresce. Some a isso o menor privilégio por chave, ambientes separados e um plano de resposta ensaiado. O custo dessas práticas é baixo; o custo de uma chave vazada, raramente.

                    Referências

                      Leituras relacionadas

                      Nenhum comentário ainda

                      Seja o primeiro a comentar.

                      Deixe seu comentário

                      Entre com sua conta Canverly para comentar. Você pode usar a mesma conta em qualquer site da rede.

                      Entrar com Canverly