Skip to main content

リポジトリからの機微なデータの削除

Git リポジトリへのパスワードや SSH キーといった機密データをコミットする場合、そのデータを履歴から削除することができます。 不要なファイルをリポジトリの履歴から完全に削除するには、git filter-repo ツールか BFG Repo-Cleaner オープンソース ツールのいずれかを使用します。

git filter-repo ツールと BFG Repo-Cleaner によって、リポジトリの履歴が書き換えられます。これにより、変更した既存のコミットと依存するコミットの SHA が変更されます。 コミットの SHA を変更すると、リポジトリ内の開いている pull request に影響する場合があります。 リポジトリからファイルを削除する前に、開いているすべての pull request を結合または閉じることをお勧めします。

git rm を使用して、最新のコミットからファイルを削除することができます。 最新のコミットで追加されたファイルを削除する方法については、「GitHub での大きいファイルについて」を参照してください。

警告: この記事では、機密データを含むコミットを、GitHub.com のリポジトリ内のブランチやタグからアクセスできないようにする方法について説明しています。 ただし、こうしたコミットも、リポジトリのクローンやフォークからは、GitHub でキャッシュされているビューの SHA-1 ハッシュによって直接、また参照元の pull request によって、到達できる可能性があります。 リポジトリにある他のユーザーのクローンやフォークから機密データを削除することはできませんが、GitHub 上のキャッシュされているビューや、pull request での機密データへの参照は、GitHub サポート ポータル に連絡して完全に削除することができます。 GitHub Support は、影響を受ける認証情報をローテーションすることによってリスクを軽減できないと判断した場合にのみ、機密データの削除を支援します。

コミットを GitHub にプッシュしたら、コミット内の機密データは侵害されたと見なすべきです。 パスワードをコミットした場合は、それを変更する必要があります。 キーをコミットした場合は、新たに生成してください。 侵害されたデータを削除しても、特にリポジトリの既存のクローンやフォークでの初期漏えいは解決されません。

機密データを含むコミットがリポジトリのフォークに存在する場合、フォーク所有者がフォークから機密データを削除するか、フォークを完全に削除しない限り、それに引き続きアクセスできます。 リポジトリのフォークの所有者と調整し、適切な措置を取るように依頼する必要があります。GitHub はこれらの所有者の連絡先を提供できないことに注意してください。

リポジトリの履歴を書き換える場合は、これらの制限事項と課題を考慮して決めてください。

ファイルをリポジトリの履歴からパージする

git filter-repo ツールまたは BFG Repo-Cleaner オープンソース ツールを使用し、リポジトリの履歴からファイルを消去します。

注: 機密データがバイナリ ファイルとして識別されるファイルに含まれる場合は、ファイルを変更してデータを削除または置換できないため、履歴からファイルを削除する必要があります。

BFG を使用する

BFG Repo-Cleaner は、オープンソース コミュニティによって構築および管理されているツールです。 不要なデータを削除するための、git filter-repo より高速で簡単な代替手段が提供されます。

たとえば、機密データを含むファイルを削除して、最新のコミットをそのままにしておくには、次を実行します:

bfg --delete-files YOUR-FILE-WITH-SENSITIVE-DATA

リポジトリの履歴内の場所に関係なく、passwords.txt に一覧表示されているすべてのテキストを置き換えるには、以下を実行します。

bfg --replace-text passwords.txt

機密データが削除されたら、変更を GitHub に強制的にプッシュする必要があります。 強制的にプッシュすると、リポジトリの履歴が書き換えられます。これにより、コミットの履歴から機密データが削除されます。 プッシュを強制すると、他のユーザーが作業のベースにしているコミットが上書きされる可能性があります。

git push --force

完全な使用方法とダウンロード手順については、BFG Repo-Cleaner のドキュメントを参照してください。

git filter-repo を使用する

警告: 変更の一時退避後に git filter-repo を実行すると、その他の stash コマンドを使用して変更を取得できなくなります。 git filter-repo を実行する前に、行ったすべての変更の一時退避を解除することをお勧めします。 最後に一時退避した一連の変更の一時退避を解除するには、git stash show -p | git apply -R を実行します。 詳細については、「Git ツール - 一時退避とクリーニング」を参照してください。

git filter-repo の動作を説明するために、リポジトリの履歴から機密データを含むファイルを削除し、それを .gitignore に追加して確実に、誤って再コミットされないようにする方法を示します。

  1. git filter-repo ツールの最新リリースをインストールします。 git-filter-repo は手動で、またはパッケージ マネージャーを使用してインストールすることができます。 たとえば、HomeBrew でツールをインストールするには、brew install コマンドを使用します。

    brew install git-filter-repo
    

    詳細については、newren/git-filter-repo リポジトリ内の INSTALL.md ファイルを参照してください。

  2. 履歴に機密データを含むリポジトリのローカル コピーがまだない場合は、ローカル コンピューターにリポジトリをクローンします。

    $ git clone https://github.com/YOUR-USERNAME/YOUR-REPOSITORY
    > Initialized empty Git repository in /Users/YOUR-FILE-PATH/YOUR-REPOSITORY/.git/
    > remote: Counting objects: 1301, done.
    > remote: Compressing objects: 100% (769/769), done.
    > remote: Total 1301 (delta 724), reused 910 (delta 522)
    > Receiving objects: 100% (1301/1301), 164.39 KiB, done.
    > Resolving deltas: 100% (724/724), done.
    
  3. リポジトリの作業ディレクトリに移動します。

    cd YOUR-REPOSITORY
    
  4. 次のコマンドを実行します。PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA は、ファイル名だけでなく、削除するファイルへのパスに置き換えてください。 これらの引数では、次のことが行われます。

    • すべてのブランチとタグの履歴全体を Git に強制的に処理させるが、チェックアウトはしない

    • 指定されたファイルと、結果として生成された空のコミットをすべて削除する

    • リモート URL など、 .git/config ファイルに格納されている一部の構成を削除する。 後で復元するために、このファイルを事前にバックアップすることができます。

    • 既存のタグを上書きする

        $ git filter-repo --invert-paths --path PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA
        Parsed 197 commits
        New history written in 0.11 seconds; now repacking/cleaning...
        Repacking your repo and cleaning out old unneeded objects
        Enumerating objects: 210, done.
        Counting objects: 100% (210/210), done.
        Delta compression using up to 12 threads
        Compressing objects: 100% (127/127), done.
        Writing objects: 100% (210/210), done.
        Building bitmaps: 100% (48/48), done.
        Total 210 (delta 98), reused 144 (delta 75), pack-reused 0
        Completely finished after 0.64 seconds.
      

    注: (移動または名前が変更されたため) 他のパスに機密データが使用されたファイルが存在する場合は、これらのパスでもこのコマンドを実行する必要があります。

  5. 機密データを含むファイルを .gitignore に追加して確実に、誤って再度コミットしないようにします。

    $ echo "YOUR-FILE-WITH-SENSITIVE-DATA" >> .gitignore
    $ git add .gitignore
    $ git commit -m "Add YOUR-FILE-WITH-SENSITIVE-DATA to .gitignore"
    > [main 051452f] Add YOUR-FILE-WITH-SENSITIVE-DATA to .gitignore
    >  1 files changed, 1 insertions(+), 0 deletions(-)
    
  6. リポジトリの履歴から必要なすべてを削除し、すべてのブランチがチェックアウトされていることを再確認します。

  7. git filter-repo ツールによって、構成済みのリモートが自動的に削除されます。 git remote set-url コマンドを使用すると、リモートが復元され、OWNERREPO はリポジトリの詳細で置き換えられます。 詳しくは、「リモートリポジトリを管理する」を参照してください。

    git remote add origin https://github.com/OWNER/REPOSITORY.git
    
  8. リポジトリの状態に問題がなく、リモートの設定が適切に完了したら、ローカルの変更を強制的にプッシュして、GitHub.com 上のリポジトリと、プッシュしたブランチをすべて上書きします。 コミットの履歴から機密データを削除するには、強制プッシュが必要です。

    $ git push origin --force --all
    > Counting objects: 1074, done.
    > Delta compression using 2 threads.
    > Compressing objects: 100% (677/677), done.
    > Writing objects: 100% (1058/1058), 148.85 KiB, done.
    > Total 1058 (delta 590), reused 602 (delta 378)
    > To https://github.com/YOUR-USERNAME/YOUR-REPOSITORY.git
    >  + 48dc599...051452f main -> main (forced update)
    
  9. タグ付けされたリリースから機密ファイルを削除するには、Git タグに対して強制的にプッシュする必要もあります。

    $ git push origin --force --tags
    > Counting objects: 321, done.
    > Delta compression using up to 8 threads.
    > Compressing objects: 100% (166/166), done.
    > Writing objects: 100% (321/321), 331.74 KiB | 0 bytes/s, done.
    > Total 321 (delta 124), reused 269 (delta 108)
    > To https://github.com/YOUR-USERNAME/YOUR-REPOSITORY.git
    >  + 48dc599...051452f main -> main (forced update)
    

GitHub

からデータを完全に削除する

BFG ツールまたは git filter-repo を使用して機密データを削除し、変更を GitHub にプッシュした後、GitHub からデータを完全に削除するには、さらにいくつかの手順を実行する必要があります。

  1. GitHub サポート ポータル にお問い合わせいただき、GitHub の pull request 内のキャッシュされたビューと機密データへの参照を削除するよう依頼してください。 リポジトリの名前と削除する必要があるコミットへのリンクの両方またはいずれかを指定してください。

    注: GitHub Support は非機密データを削除せず、影響を受ける認証情報をローテーションすることによってリスクを軽減できないと判断した場合にのみ、機密データの削除を支援します。

  2. 以前の (汚染された) リポジトリの履歴から、作成したブランチをマージ ではなくリベースするようにコラボレーターに指示します。 マージコミットを 1 回でも行うと、パージで問題が発生したばかりの汚染された履歴の一部または全部が再導入されてしまいます。

  3. 一定の時間が経過し、BFG ツール/git filter-repo に意図しない副作用がないことを確信したら、次のコマンドを使用して、ローカル リポジトリ内のすべてのオブジェクトが強制的に逆参照され、ガベージ コレクトされるようにします (Git 1.8.5 以降を使用)。

    $ git for-each-ref --format="delete %(refname)" refs/original | git update-ref --stdin
    $ git reflog expire --expire=now --all
    $ git gc --prune=now
    > Counting objects: 2437, done.
    > Delta compression using up to 4 threads.
    > Compressing objects: 100% (1378/1378), done.
    > Writing objects: 100% (2437/2437), done.
    > Total 2437 (delta 1461), reused 1802 (delta 1048)
    

    注: フィルター処理した履歴を、新規または空のリポジトリにプッシュして、GitHub から新しいクローンを作成しても、同じことができます。

将来にわたって誤ったコミットを回避する

共同作成者による誤ったコミットを防ぐことは、機密情報が公開されるのを防ぐのに役立ちます。 詳細については、「organization でのデータ 漏洩を防ぐためのベスト プラクティス」を参照してください。

コミット対象でないものがコミットされるのを回避するためのシンプルな方法がいくつかあります。

  • GitHub Desktopgitk などのビジュアル プログラムを使用して変更をコミットします。 ビジュアルプログラムは通常、各コミットでどのファイルが追加、削除、変更されるかを正確に把握しやすくするものです。
  • コマンド ラインでの catch-all コマンド git add .git commit -a を回避するには、代わりに git add filenamegit rm filename を使用してファイルを個別にステージします。
  • git add --interactive を使用して、各ファイル内の変更を個別に確認およびステージします。
  • git diff --cached を使用して、コミットのステージした変更を確認します。 これは、git commit フラグを使用しない限り -a で生成される正確な差分です。

参考資料