Security
9 min read
5130 views

機械の幽霊:Git履歴から秘密を永続的に削除する方法 👻

IT
InstaTunnel Team
Published by our engineering team
機械の幽霊:Git履歴から秘密を永続的に削除する方法 👻

すべての開発者の悪夢:最新のコミットをレビューしているときに気づく—APIキー、データベースのパスワード、またはAWSアクセス・トークンがコードに映っているのを。心臓が沈む瞬間です。すぐに新しいコミットを作成して秘密を削除し、安堵の息をつきます。でも、恐ろしい真実があります:その秘密はまだそこにあり、機械の幽霊のようにGit履歴に潜んでいるのです。

なぜ新しいコミットで秘密を削除するだけでは不十分なのか、そしてこれらのデジタル幽霊を本当に追い出す方法を理解することは、バージョン管理システムを扱うすべての開発者にとって重要な知識です。

なぜ削除だけでは不十分か:Gitの不変履歴を理解する

Gitは忘却を前提に設計されていません。その基本的なアーキテクチャは、リポジトリの一生涯にわたってすべての変更、コミット、ファイルのバージョンを保存することを目的としています。この設計思想は変更の追跡や失われた作業の回復に優れていますが、敏感なデータがリポジトリに入ったときには重大なセキュリティリスクとなります。

秘密を含むファイルをリポジトリにコミットすると、Gitはそのファイルの完全なスナップショットをオブジェクトデータベースに保存します。次のコミットで秘密を削除しても、前のコミット—秘密を含むスナップショットとともに—はリポジトリの履歴に永遠に残ります。

リポジトリにアクセスできる誰でも、git loggit checkoutgit showなどのコマンドを使って、任意の時点のファイルの状態を遡って見ることができます。リポジトリが公開されている場合や複数の開発者がクローンしている場合、その秘密は何十、何百もの場所に配布されている可能性があります。

さらに、2021年から2022年にかけて検出されたハードコーディングされた秘密の数は67%増加し、GitHubの公開コミットだけで1000万件の新しい秘密が見つかっています。これらの統計は問題の規模と、適切な秘密の除去がいかに重要かを示しています。

問題の範囲:露出後に何が起こるか

一度Git履歴に秘密が入り込むと、次のような深刻なシナリオが展開します:

自動秘密収集:悪意のある攻撃者は自動ツールを使って公開リポジトリを継続的にスキャンし、露出した資格情報を検出します。これらのボットは数分以内に秘密を検出し、悪用します。GitHubや他のプラットフォームは秘密スキャン機能を導入しており、トークンや秘密鍵などの既知のタイプの秘密をリポジトリ内で検索します。

リポジトリのフォークとクローン:リポジトリが公開されている場合やフォークされている場合、秘密はあなたの管理外の複数の場所に存在します。リポジトリの履歴を書き換えたとしても、既存のクローンやフォークはその情報を保持し続けます。

CI/CDパイプラインのログ:リポジトリ内の秘密は自動ビルドプロセス中にログに記録されることがあり、これによりさらなる露出のリスクが生まれます。

バックアップシステム:リポジトリのバックアップやアーカイブは特定の時点のGit履歴を保存しており、主要なリポジトリをクリーンアップした後も秘密を永続的に保持している可能性があります。

これらのリスクを理解することで、秘密が誤ってコミットされた場合には迅速かつ徹底的な対処が必要であることがわかります。

事前準備:重要なステップ

Git履歴から秘密を除去する前に、いくつかの必須準備を完了させる必要があります:

1. 侵害された秘密を直ちにローテーション

最初の行動は、公開された秘密を無効にすることです。新しい資格情報を生成し、APIトークンを取り消し、パスワードを変更します。このステップは、履歴を書き換える前に行う必要があります。秘密はリポジトリに入った瞬間に既に危険にさらされているからです。

2. リポジトリのバックアップ

履歴を書き換える操作は破壊的です。進行前にリポジトリの完全なバックアップを作成してください:

git clone --mirror https://your-repository-url.git backup-repo

このミラークローンはすべてのブランチ、タグ、リファレンスを保持し、何か問題があった場合に復元可能です。

3. チームと調整

複数の開発者がリポジトリを扱っている場合は、計画を明確に伝えてください。履歴を書き換えると、全員がリポジトリを再クローンするか、ローカルブランチを慎重にリベースする必要があります。可能であれば、低活動時間帯に作業を行ってください。

4. 影響を受けるブランチを記録

秘密を含む可能性のあるすべてのブランチを特定します:

git log --all --full-history --oneline -- path/to/file/with/secret

このコマンドは、秘密を含むファイルを変更したすべてのコミットを表示します。

ツール選択:git-filter-repo vs BFG Repo-Cleaner

Git履歴を書き換える主要なツールは、git-filter-repoとBFG Repo-Cleanerです。それぞれに長所と適した用途があります。

git-filter-repo:柔軟性の高いパワーハウス

git-filter-repoは、非推奨のgit-filter-branchコマンドの公式推奨置換ツールです。複雑なリポジトリの書き換えに比類なき柔軟性を提供します。

利点: - 非常に柔軟なフィルタリング機能 - パスベースの詳細なフィルタリングが可能 - リポジトリの分割や複数リポジトリの結合も対応 - 活発にメンテナンスされている - git-filter-branchより高速

適用例: - 複雑な書き換えシナリオ - 特定のパスやファイルパターンに秘密がある場合 - 複数のフィルタを同時に使いたい場合 - Pythonベースのツールに慣れているチーム

BFG Repo-Cleaner:高速処理のスペシャリスト

BFG Repo-Cleanerは、git-filter-branchの代替として、パスワードや資格情報、その他のプライベートデータを除去するために設計されたシンプルで高速なツールです。

利点: - シンプルで高速 - コマンドが直感的 - Javaで動作し、クロスプラットフォーム - 簡単な秘密除去に最適

適用例: - 特定の文字列を全ファイルから除去 - シンプルなクリーンアップ - 迅速な結果を求める場合 - 秘密が単純な文字列として現れる場合

方法1:BFG Repo-Cleanerを使った迅速な秘密除去

BFGは、リポジトリ全体から特定の文字列パターンを除去するのに優れています。以下は詳細なステップバイステップガイドです。

インストール

BFGはJava 8以上が必要です。公式リポジトリから最新版をダウンロードしてください:

# BFGをダウンロード(最新版を確認)
wget https://repo1.maven.org/maven2/com/madgag/bfg/1.14.0/bfg-1.14.0.jar

# 簡単に使えるエイリアスを作成
alias bfg='java -jar /path/to/bfg-1.14.0.jar'

秘密除去のステップ

ステップ1:新しいミラーをクローン

リポジトリのベアミラークローンを作成します:

git clone --mirror https://your-repository-url.git temp-repo.git
cd temp-repo.git

--mirrorフラグは、すべてのリファレンス、ブランチ、タグを取得し、完全なクリーンアップを可能にします。

ステップ2:秘密リストファイルを作成

除去したい秘密をリストアップしたテキストファイルを作成します。各秘密は別行に記載します:

sk_live_51AbCdEfGhIjKlMnOp
AKIAIOSFODNN7EXAMPLE
db_password_prod_2024
google_api_key_12345

このファイルをsecrets.txtとしてリポジトリ外に保存します。

ステップ3:BFGを実行

秘密を置換します:

bfg --replace-text secrets.txt temp-repo.git

BFGはリポジトリ全体をスキャンし、リストされた秘密の出現箇所をデフォルトで***REMOVED***に置き換えます。必要に応じて置換文字列をカスタマイズ可能です。

ステップ4:リポジトリのクリーンアップ

BFGはコミットとすべてのブランチ・タグを更新しますが、不要なデータを物理的に削除しません。Gitのガーベジコレクションを使って完全に削除します:

cd temp-repo.git
git reflog expire --expire=now --all
git gc --prune=now --aggressive

これらのコマンドはすべてのreflogエントリを期限切れにし、積極的にガーベジコレクションを行って、秘密を含むオブジェクトを物理的に削除します。

ステップ5:確認とプッシュ

秘密が除去されたことを確認するために、作業コピーをクローンします:

cd ..
git clone temp-repo.git verification-repo
cd verification-repo
git log -p --all | grep -i "your-secret-pattern"

成功を確認したら、リモートリポジトリに強制プッシュします:

cd temp-repo.git
git push --force --all
git push --force --tags

方法2:git-filter-repoを使った精密除去

git-filter-repoは、単純なテキスト置換を超えた高度なフィルタリングが必要な場合に適しています。

インストール

pipやパッケージマネージャを使ってインストールします:

# pipを使用
pip install git-filter-repo

# Ubuntu/Debian
apt-get install git-filter-repo

# macOS
brew install git-filter-repo

パスベースの詳細フィルタリング

ステップ1:リポジトリをクローン

新しいクローンを作成します(今回はベアではなく普通のクローン):

git clone https://your-repository-url.git cleanup-repo
cd cleanup-repo

ステップ2:秘密を含むファイルを削除

特定のファイルに秘密が含まれている場合、そのファイルを完全に削除します:

git filter-repo --path config/secrets.yaml --invert-paths

--invert-pathsフラグは、指定したパスをすべての履歴から除外します。

ステップ3:特定のファイルから秘密を除去

ファイル内の内容を除去するには、--replace-textオプションを使います:

echo "sk_live_51AbCdEfGhIjKlMnOp==***REMOVED***"  replacements.txt
git filter-repo --replace-text replacements.txt

ステップ4:複雑なケースのパスベースフィルタリング

複数の操作を組み合わせることも可能です。例えば、特定のディレクトリだけから秘密を除去する場合:

git filter-repo --path src/legacy/ --replace-text secrets.txt

ステップ5:確認とプッシュ

フィルタリング後の状態を確認します:

git log --all --oneline --graph
git log -p | grep -i "secret-pattern"

リモートにプッシュします(git-filter-repoは安全のためリモートを削除します):

git remote add origin https://your-repository-url.git
git push --force --all
git push --force --tags

クリーンアップ後の重要なフォローアップ

履歴を書き換えることは始まりに過ぎません。完全な修復を確実にするために、いくつかの重要なステップがあります:

1. チーム全員に通知

明確な指示を全員に送ります:

重要:リポジトリの履歴が書き換えられ、機密データが削除されました。

必要なアクション:
1. ローカルのクローンを削除
2. 新しいクローンを取得: [repository-url]
3. 既存のブランチとマージやリベースをしない

未プッシュの作業がある場合は、パッチとして保存してください:
git format-patch origin/main

2. 既存のプルリクエストを更新

古い履歴に基づくプルリクエストは再作成が必要です。古いコミットは書き換えられた履歴と互換性がなくなります。

3. フォークとミラーを確認

リポジトリがフォークやミラーされている場合は、その所有者に連絡し、セキュリティ上の問題を説明し、古いコピーの更新または削除を依頼してください。

4. CI/CDのログとアーティファクトを確認

ビルドログやアーティファクトに秘密が含まれていないか確認します。これらはキャッシュされている場合があります。

5. 不正使用の監視

ローテーション後も、古い資格情報の不正使用を監視し、疑わしいアクセスに対してアラートを設定してください。

予防策:二度と起こさない

Git履歴に秘密を入れさせない最良の方法は、最初から防ぐことです:

1. プリコミットスキャン用Gitフックの導入

秘密の可能性をスキャンするプリコミットフックを設定します:

# .git/hooks/pre-commit
#!/bin/bash
if git diff --cached | grep -iE "password|secret|api[_-]?key|token"; then
    echo "⚠️  潜在的な秘密が検出されました!コミットをブロックします。"
    exit 1
fi

2. 秘密スキャンツールの活用

パターン認識やエントロピー検査、機械学習を使った秘密漏洩検出ツールを利用し、公開前に秘密を検出します。

3. 環境変数や秘密管理システムの利用

秘密は環境変数や専用の秘密管理システムに保存します:

  • ローカル開発.envファイル(.gitignoreに追加)
  • 本番環境:AWS Secrets Manager、HashiCorp Vault、Azure Key Vault
  • CI/CD:プラットフォームの秘密ストレージ(GitHub Secrets、GitLab CI/CD変数)

4. .gitignoreの徹底

秘密を含むファイルや設定を.gitignoreに追加します:

# 環境変数
.env
.env.local
.env.*.local

# IDE設定
.vscode/
.idea/

# 秘密を含む設定ファイル
config/secrets.yml
config/database.yml
credentials.json

# クラウド資格情報
.aws/
.gcloud/

5. コードレビューの徹底

マージ前に必ずコードレビューを行い、秘密のコミットを見逃さないようにします。

6. プッシュ保護の有効化

秘密スキャンとプッシュ保護により、特定のパターンに一致する秘密のプッシュを自動的に検出・防止できます。対応プラットフォームで有効にしてください。

結論:常に警戒を怠らない

Git履歴から秘密を除去する作業は複雑でリスクの高い操作です。ツールの使用だけでなく、周囲の調整や検証、予防策も同じくらい重要です。

以下の原則を覚えておきましょう:

  1. 即座に行動:秘密が漏れたらすぐに資格情報をローテーション
  2. 適切なツールを選択:高速でシンプルなBFG、複雑なケースにはgit-filter-repo
  3. 明確に伝える:チーム全員にプロセスと必要なアクションを理解させる
  4. 徹底的に検証:秘密が完全に除去されたことを確認
  5. 再発防止:包括的な予防策を実施し、再びこの苦痛を繰り返さない

あなたのGit履歴の幽霊は見えませんが、非常に現実的なセキュリティリスクです。正しい知識とツールを使えば、完全に追い出し、秘密を守るための習慣を築くことができます。常に警戒し、安全を確保しましょう。そして覚えておいてください:バージョン管理の世界では、入れたものは簡単には出てこない—それを実現する方法を知っている場合を除いて。

Continue from this article into the most relevant product guides and workflows.

Related Topics

#git secrets removal, remove secrets from git history, delete sensitive data git, git-filter-repo, BFG Repo-Cleaner, purge git history, remove credentials from git, git security, exposed API keys git, remove passwords from git, committed secrets fix, accidentally committed password, git history rewrite, how to remove secrets from git history permanently, leaked credentials git, API key in git history, git secret scanning, remove API keys from git repository, delete committed passwords git, clean git repository, fix git security issue, git sensitive data removal, rewrite git commits, exposed secrets github, security breach git, compromised credentials repository, git filter repo tutorial, BFG repo cleaner guide, permanently delete files from git history, remove credentials from all git branches, git secret remediation, credential rotation, repository cleanup, git force push, prevent secrets in git commits, version control security, git security best practices, GitHub secret scanning, secret detection tools, automated secret scanning, repository security audit, git filter-branch alternative, DevSecOps, CI/CD security, push protection, pre-commit hooks, secret management, git reflog, git garbage collection, GitHub secrets, clean compromised repository, remove leaked API keys, secure git repository, GitLab security, developer security, DevOps security practices, git object database, git history cleanup tools, Bitbucket repository cleaning, repository management, code security tutorial, software engineer guide, git advanced techniques, protect source code, environment variables best practices, gitignore sensitive files, git repository forensics, source code security, security incident response, eliminate security vulnerabilities git

Keep building with InstaTunnel

Read the docs for implementation details or compare plans before you ship.

Share this article

More InstaTunnel Insights

Discover more tutorials, tips, and updates to help you build better with localhost tunneling.

Browse All Articles