📜

Gitのコミット履歴から機密情報を消す方法(2種)

2024/01/04に公開

やりたいこと

外部システムのトークンやパスワードなどの機密情報をcommitした履歴が存在するGitリポジトリから、機密情報をcommit履歴も含めてすべて削除する。

個人的にはprivateリポジトリであれば機密情報がcommitされた履歴があってもそれほど大きな危機感を持たなくても良いと思っている。しかし、過去に開発ツール側のセキュリティ事故が原因で、private設定のGitリポジトリが社外に漏洩する事故が発生したこともあった。
そういったケースに備える目的で、記事タイトルのような要件が発生することがある。

取り得る手段

  1. Gitリポジトリをゼロから作り直す
  2. bfgというツールを使って、既存のGitリポジトリから機密情報に関わる履歴だけを削除する

シンプルなのは手段1.の方法。
ただ、履歴が消えることで「なぜこのステップはこんな実装になっているのか?」という経緯を追うのが難しくなってしまう副作用がある。

そこで私のチームで取ったのが手段2.の方法。
この方法であればcommit履歴は維持したまま、残ってほしくない履歴情報だけを削除できる。

ただ、手段2.は手順が少し面倒。
その手順は下記の通り。

bfgによる機密情報削除の手順(うろ覚え)

以下の内容は、macOS Venturaで動作させたもの。
ただ、正直この作業を実施してから日が経ってしまっていて、以下の手順は改めて調べ直しながら書いているもの。
もしかするとうまく動かないものが含まれているかも。。

  1. Homebrewでbfgをインストール
$ brew update
$ brew install bfg
  1. チームメンバーも含めて、開発中のブランチをすべてマージする
    • この手順は必須ではない(と、思う…)
    • Gitの設計からして、マージ先のブランチと開発中のブランチのcommit履歴が一致しない状態になるとマージが面倒になることは明らかなので、開発ブランチはゼロにしておくに越したことはないはず
  2. GitHubリポジトリの設定画面で、各ブランチのprotection rulesを無効化
    • あとで元に戻すので、既存のルールは別の場所にメモしておくと良い
  3. Gitリポジトリを--mirrorオプション付きで新たにcloneする
    • 正直--mirrorオプションは「付けたほうが良い」という記事をよく見かけたのでなんとなく付けているだけで、必要性は理解できてない…
    • 作業ミスに備えて、予めcloneしてある普段遣いのディレクトリとは別の箇所にcloneすることは必須だと思う
$ mkdir bfg # bfgディレクトリを作成
$ cd bfg # ↑で作ったbfgディレクトリに移動
$ git clone --mirror https://github.com/beryu/sample.git # 新たにclone
  1. 上記4.でGitリポジトリをcloneしたbfgディレクトリにpassword.txtという名前でファイルを作成し、削除したい機密情報の文字列を改行区切りで書いていく
password.txt
hoge
fuga
  1. bfgを実行
$ bfg --replace-text passwords.txt sample.git
  1. Gitリポジトリをpushする
$ cd sample.git
$ git reflog expire --expire=now --all && git gc --prune=now --aggressive
$ git push
  1. Gitのcommit履歴を確認し、上記5.で指定した文字列が残っていた履歴が**REMOVED**という文字列に置き換わっていることを確認
  2. 上記3.で無効化していたprotection rulesを元に戻す

Discussion