Gitのコミット履歴から機密情報を削除する
状況
- あるメンバーが、機密情報をコミットしてGitHubにPushしてしまった
- 1年以上経ってからそれに気がついた
- 該当の機密情報をファイルから削除しても、過去のコミット履歴を見れば機密情報が参照できてしまうので、参照できないようにしたい
選択肢
Gitに載ってしまった情報を削除するには、以下の2つの選択肢がある
- git filter-branch
- gitの内部コマンドなので、追加のツールをインストールする必要がない
- 細かい調整がしやすい
- 使い方がやや複雑で、処理速度もやや遅め
- BFG Repo-Cleaner
- 細かい調整ができないけど、シンプルに使える
- brew install等でインストールして使う
今回はできるだけシンプルにやりたいので、BFG Repo-Cleanerを使うことにした
手順
実施タイミングの調整
BFG Repo-CleanerはGitの履歴を書き換えるので、処理実行前に作ったブランチから、処理実行後のブランチへのマージがうまくいかない可能性がある。
ちょっとした修正なら、処理実行後にもう一度開発環境を作って、全く同じ修正を手動でやれば良いけど、大きめの改修をしてたりすると大変。
チームメンバーと相談し、実装途中の大きめの改修などがないタイミングを狙って実施日を決める。
既存のPull Requestを整理
BFG Repo-Cleanerを実行すると、実行前の環境で作ったPull Requestはマージできなくなる。
なので、既存のPull Requestはできるだけ全てマージする。
bfgをインストール
$ brew install bfg
$ bfg --version
bfg 1.14.0
ミラーリポジトリをclone
Gitの履歴を削除するには、全てのブランチ、タグ、履歴を含むリポジトリ(ミラーリポジトリ)を手元に持ってきて、作業する必要がある。
--mirror
オプションを付けることで、ミラーリポジトリをcloneすることができる。
$ git clone --mirror git@github.com:nyshk97/my-app.git
特定のファイルの情報を削除する
./my-app.git/secret.txt
の情報を削除する場合
$ bfg --delete-files secret.txt my-app.git
reflog情報を削除
過去にgitに載せてしまった機密情報を見れなくするためには、git reflog expireコマンドで過去の全てのreflog情報を削除する必要がある。
過去の全てのreflog情報を削除することで、以下の2つの問題が発生しうるので、許容できるか確認してから実行する。
- リポジトリの全体的な履歴が失われ、過去の状態への復元が難しくなる
- 他のエンジニアが今やってる作業(reflog情報の削除前にやった作業)がうまくマージできなくなる
$ cd my-app.git
$ git reflog expire --expire=now --all && git gc --prune=now --aggressive
force push
保護されているブランチがあると失敗する。
その場合はhttps://github.com/{ユーザー名}/{リポジトリ名}/settings/branches
から、ブランチの保護を解除してから実行する。
$ git push --force
開発用のリポジトリをcloneし直す
既存の開発用リポジトリ(ミラーリポジトリではない)を再度cloneし直す。
$ cd {開発用リポジトリがある1つ上のディレクトリ}
$ mv my-app my-app-old
$ git clone git@github.com:nyshk97/my-app
# 必要に応じて、環境構築をし直す
チーム開発をしている場合、他の全てのエンジニアに同じことをしてもらう。
GitHubのサポートに、関連するPull Requestの削除依頼する
BFG Repo-Cleanerを実行しただけでは、Pull Requestの履歴から、機密情報を見ることができてしまう。
Pull Requestを削除するためには、GitHubのサポートに連絡して対応してもらう必要がある。
https://support.github.com/request/remove-data より「プルリクエストを削除する」をクリックし、案内に従ってPull Requestの削除を依頼する。
削除依頼してから1日くらいで削除完了の連絡がきた。これで完了。
注意点
BFG Repo-Cleanerの処理実行後、古い開発環境からGitHubにPushをすると、再度機密情報がGitHub上に載ってしまう(&クソデカPRが生まれる)ので注意。
参考
Discussion