Skip to main content

Remover dados confidenciais de um repositório

Dados confidenciais poderão ser removidos do histórico de um repositório se você puder coordenar cuidadosamente com todos que o clonaram e estiver disposto a gerenciar os efeitos colaterais.

Sobre a remoção de dados confidenciais de um repositório

Ao alterar o histórico do repositório usando ferramentas como git filter-repo, é fundamental entender as implicações. É necessário coordenar cuidadosamente com os colaboradores o processo de reescrever o histórico para que ele seja executado com êxito, e há uma série de efeitos colaterais que devem ser gerenciados.

É importante observar que, se os dados confidenciais que você precisa remover forem um segredo (por exemplo, senha/token/credencial), como costuma ser o caso, a primeira etapa será revogar e/ou girar esse segredo. Após o segredo ser revogado ou girado, ele não poderá mais ser usado para acesso, e isso pode ser suficiente para resolver o problema. Pode não ser necessário realizar as etapas extras de reescrever o histórico e remover o segredo.

Efeitos colaterais de reescrever o histórico

Reescrever o histórico traz alguns efeitos colaterais, que incluem:

  • Alto risco de recontaminação: infelizmente, é fácil voltar a efetuar push dos dados confidenciais para o repositório e fazer uma bagunça ainda maior. Se um colega desenvolvedor tiver um clone anterior à reescrita e, depois da reescrita, simplesmente executar git pull seguido de git push, os dados confidenciais retornarão. Ele precisa descartar o clone dele e clonar novamente ou realizar cuidadosamente várias etapas para limpar o clone dele primeiro.
  • Risco de perder o trabalho de outros desenvolvedores: se outros desenvolvedores continuarem atualizando branches que contêm os dados confidenciais enquanto você estiver tentando limpá-los, você precisará refazer a limpeza ou descartar o trabalho deles.
  • Hashes de commit alterados: reescrever o histórico vai alterar os hashes dos commits que introduziram os dados confidenciais e de todos os commits que vieram depois. Qualquer ferramenta ou automação que exigir que hashes de commit não sejam alterados será interrompida ou terá problemas.
  • Desafios de proteção de branch: se você tiver proteções de branch que impedem pushes forçados, elas precisarão ser desativadas (pelo menos temporariamente) para que os dados confidenciais sejam removidos.
  • Exibição de comparação interrompida para pull requests fechadas: a remoção dos dados confidenciais exigirá a remoção das referências internas usadas para mostrar a exibição de comparação em pull requests, de modo que você não poderá mais ver essas comparações. Isso vale não apenas para a PR que introduziu os dados confidenciais, mas para qualquer PR baseada em uma versão do histórico posterior à mesclagem da PR com dados confidenciais (mesmo que essas PRs posteriores não tenham adicionado nem modificado nenhum arquivo com dados confidenciais).
  • Interação insatisfatória com pull requests em aberto: os SHAs de commits alterados resultarão em uma comparação de PR diferente e os comentários sobre a comparação de PR antiga poderão ser invalidados e perdidos, o que poderá causar confusão para autores e revisores. Recomendamos mesclar ou fechar todas as solicitações de pull abertas antes de remover arquivos do repositório.
  • Perda de assinaturas em commits e tags: as assinaturas de commits ou tags dependem dos hashes de commit. Como os hashes de commit são modificados por reescritas de histórico, as assinaturas deixarão de ser válidas e muitas ferramentas de reescrita de histórico (incluindo o git filter-repo) simplesmente as removerão. De fato, git filter-repo remove também assinaturas de commit e de tag para commits anteriores à remoção dos dados confidenciais também. (Tecnicamente, é possível contornar isso com a opção --refs para git filter-repo, quando necessário, mas nesse caso você precisará ter cuidado para garantir que especifique todas as referências com dados confidenciais em seu histórico e que incluam os commits que introduziram os dados confidenciais em seu intervalo).
  • Direcionamento de outras pessoas para os dados confidenciais: o Git foi criado com verificações de criptografia incorporadas nos identificadores de commit, de modo que pessoas mal-intencionadas não pudessem invadir um servidor e modificar o histórico sem serem detectadas. Isso é útil da perspectiva de segurança, mas da perspectiva de dados confidenciais significa que expurgar esses dados é um processo de coordenação muito elaborado. Significa ainda que, quando você modifica o histórico, usuários atentos com um clone existente observarão a divergência de históricos e poderão usar isso para localizar com rapidez e facilidade os dados confidenciais que ainda estão no clone que você removeu do repositório central.

Sobre a exposição de dados confidenciais

A remoção de dados confidenciais de um repositório envolve quatro etapas gerais:

  • Reescrever o repositório localmente usando git-filter-repo
  • Atualizar o repositório no GitHub usando seu histórico reescrito localmente
  • Coordenar com colegas para limpar outros clones existentes
  • Impedir repetições e evitar futuros vazamentos de dados confidenciais

Se você apenas reescrever o histórico e efetuar o push forçado dele, commits com dados confidenciais ainda poderão estar acessíveis em outro lugar:

  • Em quaisquer clones ou forks do seu repositório
  • Diretamente por meio de seus hashes SHA-1 em exibições em cache em GitHub
  • Por meio de pull requests que façam referência

Não é possível remover dados confidenciais dos clones de outros usuários do repositório. Você precisará enviar as instruções por meio de Garantir que as outras cópias foram limpas: clones de colegas no manual do git filter-repo para que façam isso por conta própria. No entanto, você pode remover permanentemente as exibições armazenadas em cache e as referências aos dados confidenciais em pull requests no GitHub entrando em contato com o conosco por meio do Portal de suporte do GitHub.

Important

O Suporte do GitHub não remove dados não confidenciais e só ajuda na remoção de dados confidenciais nos casos em que determinarmos que o risco não pode ser mitigado pela rotação das credenciais afetadas.

Se a confirmação que introduziu os dados confidenciais existir em qualquer fork, ela continuará acessível lá. Você precisará coordenar com os proprietários dos forks, pedindo-lhes para remover os dados confidenciais ou excluir o fork completamente. GitHub não é capaz de fornecer informações de contato para esses proprietários.

Considere essas limitações e desafios ao tomar a decisão de reescrever a história do repositório.

Como limpar um arquivo do histórico do repositório local usando o git-filter-repo

  1. Instale a última versão da ferramenta git filter-repo. É preciso ter uma versão com o sinalizador --sensitive-data-removal, o que significa, no mínimo, a versão 2.47. Você pode instalar o git filter-repo manualmente ou usando um gerenciador de pacotes. Por exemplo, para instalar a ferramenta com HomeBrew, use o comando brew install.

    brew install git-filter-repo
    

    Para obter mais informações, confira INSTALL.md no repositório newren/git-filter-repo.

  2. Clone o repositório no computador local. Confira Clonar um repositório.

    git clone https://github.com/YOUR-USERNAME/YOUR-REPOSITORY
    
  3. Navegue até o diretório de trabalho do repositório.

    cd YOUR-REPOSITORY
    
  4. Execute um comando git filter-repo para limpar os dados confidenciais.

    Se quiser excluir um arquivo específico de todos os branches/tags/referências, execute o seguinte comando substituindo PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA pelo caminho do Git para o arquivo que você deseja remover, não apenas o nome de arquivo (por exemplo, src/module/phone-numbers.txt):

    git filter-repo --sensitive-data-removal --invert-paths --path PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA
    

    Important

    Se o arquivo com os dados confidenciais existia em qualquer outro caminho (devido a ter sido movido ou renomeado), adicione um argumento --path extra para esse arquivo ou execute esse comando uma segunda vez nomeando o caminho alternativo.

    Se você quiser substituir todo o texto listado em ../passwords.txt em todos os arquivos não binários encontrados em qualquer lugar do histórico do repositório, execute o seguinte comando:

    git filter-repo --sensitive-data-removal --replace-text ../passwords.txt
    
  5. Verifique se você removeu tudo o que queria do histórico do repositório.

  6. Descubra quantas pull requests serão afetadas negativamente por essa reescrita de histórico. Você precisará dessas informações abaixo.

    $ grep -c '^refs/pull/.*/head$' .git/filter-repo/changed-refs
    4
    

    Remova o -c para ver quais pull requests são afetadas:

    $ grep '^refs/pull/.*/head$' .git/filter-repo/changed-refs
    refs/pull/589/head
    refs/pull/602/head
    refs/pull/604/head
    refs/pull/605/head
    

    Essa saída inclui o número da pull request entre a segunda e a terceira barra "/". Se o número de pull requests afetadas for maior do que o esperado, descarte esse clone sem efeitos nocivos e refaça a reescrita ou suspenda a remoção dos dados confidenciais. Depois que você passar para a próxima etapa, a reescrita se tornará irreversível.

  7. Quando estiver satisfeito com o estado do repositório, efetue o push forçado das alterações locais para substituir seu repositório no GitHub.com. Embora --force esteja implícito por --mirror, nós o incluímos abaixo como um lembrete de que você está usando a atualização forçada para todos os branches, tags e referências e que está descartando as alterações que outras pessoas possam ter feito a essas referências enquanto você estava limpando o repositório.

    git push --force --mirror origin
    

    Esse comando não efetuará push de nenhuma referência que começa com refs/pull/, pois o GitHub marca as referências como somente leitura. Essas falhas de push serão abordadas na próxima seção. Em caso de falha de push de alguma outra referência, é provável que você tenha a proteção de branch ativada para o branch em questão. Será preciso desativá-la temporariamente e refazer o push. Repita esta etapa até que as únicas falhas de atualização sejam as referências que começam com refs/pull/.

Remover completamente os dados de GitHub

Depois de usar git filter-repo para remover os dados confidenciais e efetuar push das alterações para o GitHub, você precisa executar mais algumas etapas para remover por completo os dados do GitHub.

  1. Entre em contato com o conosco por meio do Portal de suporte do GitHub e informe o seguinte:

    • O nome do proprietário e do repositório em questão (por exemplo, YOUR-USERNAME/YOUR-REPOSITORY).
    • O número de pull requests afetadas, encontradas na etapa anterior. Isso é usado pelo Suporte para verificar se você está ciente do quanto será afetado.
    • Os Primeiros Commits Alterados relatados pelo git filter-repo (procure NOTE: First Changed Commit(s) na saída).
    • Se NOTE: There were LFS Objects Orphaned by this rewrite aparecer na saída do git-filter-repo (logo após o Primeiro Commit Alterado), mencione que você tinha objetos LFS órfãos e carregue o arquivo nomeado no tíquete também.

    Se você tiver limpado com êxito todas as referências que não sejam PRs e nenhum fork tiver referências aos dados confidenciais, o Suporte vai:

    • Desreferenciar ou excluir as PRs afetadas no GitHub.

    • Executar um GC no servidor para excluir os dados confidenciais do armazenamento.

    • Remover as exibições armazenadas em cache.

    • Se objetos LFS estiverem envolvidos, exclua e/ou limpe os objetos LFS órfãos.

    Important

    O Suporte do GitHub não removerá dados não confidenciais e só ajudará na remoção de dados confidenciais nos casos em que determinarmos que o risco não pode ser mitigado pela rotação das credenciais afetadas.

  2. Os colaboradores precisam trocar a base (não fazer o merge) dos branches que criaram fora do histórico do repositório antigo (afetado). Um commit de merge poderia reintroduzir o histórico antigo completo (ou parte dele) que você acabou de se dar ao trabalho de corrigir. Talvez eles também precisem realizar etapas adicionais. Confira Garantir que as outras cópias foram limpas: clones de colegas no manual do git filter-repo.

Evitar commits acidentais no futuro

Impedir que colaboradores façam commits acidentais pode ajudar a evitar que informações confidenciais sejam expostas. Para saber mais, confira Melhores práticas para evitar vazamentos de dados na sua organização.

Você pode fazer algumas coisas para evitar fazer commit ou push de coisas que não devem ser compartilhadas:

  • Se os dados confidenciais provavelmente forem encontrados em um arquivo que não deve ser rastreado pelo git, adicione esse nome de arquivo a .gitignore (e faça commit e push dessa alteração para .gitignore para que outros desenvolvedores sejam protegidos).
  • Evite embutir segredos em código. Use variáveis de ambiente ou serviços de gerenciamento de segredos como o Azure Key Vault, o AWS Secrets Manager ou o HashiCorp Vault para gerenciar e injetar segredos no runtime.
  • Crie um gancho pré-commit para verificar se há dados confidenciais antes que seja feito commit ou push deles para qualquer lugar, ou use uma ferramenta conhecida em um gancho pré-commit, como git-secrets ou gitleaks. (Peça a cada colaborador para configurar o gancho pré-commit escolhido por você.)
  • Use um programa visual como o GitHub Desktop ou o gitk para fazer commit das alterações. Nos programas visuais, geralmente é mais fácil ver exatamente quais arquivos serão adicionados, excluídos e modificados em cada commit.
  • Evite os comandos catch-all git add . e git commit -a na linha de comando: use git add filename e git rm filename para preparar os arquivos individualmente.
  • Use git add --interactive para revisar e preparar alterações individualmente em cada arquivo.
  • Use git diff --cached para revisar as alterações que você preparou para commit. Essa é a comparação exata que git commit produzirá, desde que você não use o sinalizador -a.
  • Habilite a proteção por push para seu repositório para detectar e impedir que envios por push contendo segredos codificados sejam confirmados na sua base de código. Para saber mais, confira Sobre a proteção por push.

Leitura adicional