Skip to main content

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

機密データをリポジトリの履歴から削除できるのは、あなたがクローンを行った全員と慎重に調整することができて、副作用を管理する意思がある "場合のみ" です。__

リポジトリからの機密データの削除について

git filter-repo などのツールを使ってリポジトリの履歴を変更する場合、その影響を理解することが重要です。 履歴の書き換えを成功させるには、コラボレーターとの慎重な調整が必要であり、管理する必要がある多くの副作用を伴います。

多くの場合、削除する必要がある機密データがシークレット (パスワード、トークン、資格情報など) である場合、最初の手順として、そのシークレットを失効させたり、ローテーションしたりする必要があることに注意してください。 シークレットが失効されるかローテーションされると、アクセスには使用できなくなりますが、問題を解決するには十分な場合があります。 履歴を書き換えてシークレットを削除するために追加の手順を実行しても、保証されない場合があります。

履歴を書き換えることによる副作用

履歴の書き換えには多くの副作用があります。次に例を示します。

  • 再汚染の高いリスク: 残念ながら、機密データをリポジトリに再プッシュして、さらに大きな混乱が起こることはよくあります。 他の開発者が書き換え前のクローンを持っていて、書き換え後に単に git pull に続いて git push を実行した場合、機密データが返されます。 クローンを破棄して再クローンするか、まずクローンをクリーンアップするために複数の手順を慎重に実行する必要があります。
  • 他の開発者の作業が失われるリスク: クリーンを試みている間に他の開発者が機密データを含むブランチの更新を続けた場合、クリーンをやり直すか、その作業を破棄する必要があります。
  • 変更されたコミット ハッシュ: 履歴を書き換えると、機密データを導入したコミットのハッシュ "と" その後のすべてのコミットが変更されます。__ コミット ハッシュが不変であることに依存するツールや自動化は、動作しなくなったり、問題が発生したりする可能性があります。
  • ブランチ保護の課題: 強制プッシュを防ぐブランチ保護がある場合、機密データを削除するには、それらの保護を (少なくとも一時的に) 無効にする必要があります。
  • 中止された pull request の差分ビューの破損: 機密データを削除するには、pull request の diff ビューの表示に使われる内部参照を削除する必要があるため、これらの diff は表示できなくなります。 これは、機密データを導入した PR だけでなく、機密データ PR がマージされた後のバージョンの履歴に基づいて構築されるすべての PR にも当てはまります (その後の PR が機密データを含むファイルを追加または変更しなかった場合でもそうです)。
  • 開いている pull request との連携が不十分: コミット SHA が変更されると、別の PR diff が生じ、古い PR diff に対するコメントが無効になって失われる可能性があります。その結果、作成者やレビュー担当者が混乱する可能性があります。 リポジトリからファイルを削除する前に、開いているすべての pull request を結合または閉じることをお勧めします。
  • コミットとタグのシグネチャが失われる: コミットまたはタグのシグネチャはコミット ハッシュに依存しています。コミット ハッシュは履歴の書き換えによって変更されるため、シグネチャは無効になり、多くの履歴書き換えツール (git filter-repo を含む) では単にシグネチャが削除されます。 実際、git filter-repo の場合、機密データの削除より前の日付のコミット シグネチャとタグ シグネチャも削除されます (技術的には、必要に応じて --refs オプションを git filter-repo に設定することでこれを回避できますが、その場合は、履歴に機密データが含まれているすべての参照を指定し、その範囲に機密データが含まれているコミットを含めるように注意する必要があります)。
  • 他のユーザーを機密データに直接誘導する: Git は、悪意のある個人が気付かれることなくサーバーに侵入して履歴を変更できないように、コミット識別子に暗号チェックを組み込むように設計されています。 これはセキュリティの観点からは役立ちますが、機密データの観点から見ると、機密データの消去は非常に複雑な調整のプロセスであることを意味しています。さらに、履歴を変更すると、既存のクローンを持っている知識豊富なユーザーであれば、履歴の相違に気付き、それを利用して、中央リポジトリから削除したクローン内にまだ残っている機密データを短時間で簡単に見つけることができることを意味します。

機密データの公開について

リポジトリから機密データを削除するには、次の 4 つの大まかな手順が必要です。

  • git-filter-repo を使ってリポジトリをローカルで書き換える
  • ローカルで書き換えられた履歴を使って GitHub 上のリポジトリを更新する
  • 同僚と連携して、存在する他のクローンをクリーンアップする
  • 再発を防ぎ、将来の機密データの流出を回避する

履歴を書き換えてフォース プッシュするだけの場合、機密データを含むコミットは他の場所からアクセスできる可能性があります。

  • リポジトリのクローンまたはフォーク内
  • GitHub のキャッシュされたビューで SHA-1 ハッシュを直接介して
  • それらを参照するプル リクエストを通じて。

自分のリポジトリの他のユーザーによるクローンから機密データを削除することはできません。git filter-repo マニュアルの「他のコピーがクリーンアップされていることを確認する: 同僚のクローン」の手順を相手に送信して、クリーンアップしてもらう必要があります。 ただし、GitHub の pull request 内のキャッシュされたビューと機密データへの参照は、GitHub サポート ポータル に問い合わせることで完全に削除できます。

Important

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

機密データを導入したコミットがフォークに存在する場合は、引き続きそこでアクセスできます。 フォークのオーナーと調整し、機密データを削除するかフォークを完全に削除するように依頼する必要があります。 GitHub はこれらのオーナーの連絡先情報を提供できません。

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

git-filter-repo を使ってローカル リポジトリの履歴からファイルを消去する

  1. git filter-repo ツールの最新リリースをインストールします。 --sensitive-data-removal フラグの設定されたバージョン (つまり、バージョン 2.47 以降) が必要です。 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
    
  3. リポジトリの作業ディレクトリに移動します。

    cd YOUR-REPOSITORY
    
  4. git filter-repo コマンドを実行して機密データをクリーンアップします。

    すべてのブランチ、タグ、参照から特定のファイルを削除する場合は、次のコマンドを実行して、PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA を、ファイル名だけでなく、削除するファイルの git パスに置き換えます (例: src/module/phone-numbers.txt)。

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

    Important

    機密データを含むファイルが (移動または名前が変更されたため) 他のパスに存在していた場合は、そのファイルに追加の --path 引数を追加するか、代替パスを指定してこのコマンドを 2 回実行する必要があります。

    リポジトリの履歴内で任意の場所にあるバイナリ以外のファイルから、../passwords.txt に記載されているすべてのテキストを置換する場合は、次のコマンドを実行します。

    git filter-repo --sensitive-data-removal --replace-text ../passwords.txt
    
  5. リポジトリの履歴から必要なものをすべて削除したことをダブルチェックします。

  6. この履歴の書き換えによって悪影響を受ける pull request の数を確認します。 この情報は後で必要になります。

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

    -c をドロップすると、どの pull request が影響を受けるかを確認できます。

    $ 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
    

    この出力には、2 つ目と 3 つ目のスラッシュの間に pull request 番号が含まれています。 影響を受ける pull request の数が予想より多い場合は、このクローンを破棄しても問題ありません。そして、書き換えをやり直すか、機密データの削除を中止することができます。 次の手順に進むと、書き換えは元に戻せなくなります。

  7. リポジトリの状態に問題がない場合は、ローカルの変更を強制プッシュして、GitHub.com のリポジトリを上書きします。 --force--mirror で暗示されていますが、あなたはすべてのブランチ、タグ、参照を強制的に更新しており、リポジトリのクリーンアップ中に他のユーザーがそれらの参照に対して行った変更がある場合は破棄することになることを示すために、以下に記載しています。

    git push --force --mirror origin
    

    それらは GitHub によって読み取り専用とマークされているため、このコマンドでは refs/pull/ で始まる参照をプッシュできません。 これらのプッシュ エラーは、次のセクションで処理します。 他の参照がプッシュに失敗した場合は、そのブランチに対してブランチ保護が有効になっている可能性があり、一時的にオフにしてプッシュをやり直す必要があります。 更新に失敗するのが refs/pull/ で始まる参照のみになるまで繰り返します。

GitHub

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

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

  1. GitHub サポート ポータル に問い合わせ、次の情報を提供してください。

    • 問題の所有者とリポジトリ名 (例: YOUR-USERNAME/YOUR-REPOSITORY)。
    • 前の手順で見つかった、影響を受ける pull request の数。 これは、影響を受ける範囲をユーザーが理解していることを確認するためにサポートが利用します。
    • git filter-repo によって報告された "First Changed Commit(s)" (出力の NOTE: First Changed Commit(s) を探してください)。
    • git-filter-repo の出力に NOTE: There were LFS Objects Orphaned by this rewrite がある場合 ("First Changed Commit" の直後)、"LFS Objects Orphaned" があることを伝え、指定されたファイルもチケットにアップロードします。

    PR 以外のすべての参照を正常にクリーンアップし、機密データへの参照を含むフォークがない場合、サポートは次のことを行います。

    • GitHub 上の影響を受ける PR を逆参照または削除します。

    • サーバー上でガベージ コレクションを実行して、機密データをストレージから消去します。

    • キャッシュされたビューを削除します。

    • LFS オブジェクトが関係している場合は、孤立している LFS オブジェクトを削除または消去します。

    Important

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

  2. コラボレーターは、以前の (汚染された) リポジトリの履歴から、作成したブランチをマージ "ではなく"、リベースする必要があります。__ マージコミットを 1 回でも行うと、パージで問題が発生したばかりの汚染された履歴の一部または全部が再導入されてしまいます。 必要に応じて追加の手順を実行します。git filter-repo マニュアルの「他のコピーがクリーンアップされていることを確認する: 同僚のクローン」を参照してください。

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

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

共有すべきではないものをコミットまたはプッシュしないようにするために、いくつかの対策があります。

  • git で追跡すべきではない機密データがファイル内で見つかる可能性がある場合は、そのファイル名を .gitignore に追加します (そして、他の開発者を守るために、その変更を必ずコミットして .gitignore にプッシュします)。
  • コードにシークレットをハードコーディングしないでください。 実行時にシークレットを管理および挿入するには、環境変数またはシークレット管理サービス (Azure Key Vault、AWS Secrets Manager、HashiCorp コンテナーなど) を使います。
  • 機密データのコミット前またはどこかにプッシュされる前にチェックするコミット前フックを作成するか、コミット前フックで git-secrets や gileaks などのよく知られたツールを使います (各コラボレーターに対して、選んだコミット前フックを設定するように必ず依頼してください)。
  • GitHub Desktopgitk などのビジュアル プログラムを使用して変更をコミットします。 ビジュアルプログラムは通常、各コミットでどのファイルが追加、削除、変更されるかを正確に把握しやすくするものです。
  • コマンド ラインでの catch-all コマンド git add .git commit -a を回避するには、代わりに git add filenamegit rm filename を使用してファイルを個別にステージします。
  • git add --interactive を使用して、各ファイル内の変更を個別に確認およびステージします。
  • git diff --cached を使用して、コミットのステージした変更を確認します。 これは、git commit フラグを使用しない限り -a で生成される正確な差分です。
  • リポジトリのプッシュ保護を有効にして、ハードコーディングされたシークレットを含むプッシュがコードベースにコミットされないようにします。 詳しくは、「プッシュ保護について」をご覧ください。

参考資料