問題点:シークレットはハッカーにとっての新たな「金」
何度も見てきた光景ですが、開発者が急いでいるときにAWSのテンポラリキーやデータベースのパスワードをテスト用にハードコードしてしまい、気づかないうちにそのキーが公開リポジトリに残ってしまうことがあります。
自動化されたボットがそのシークレットを見つけ、高額なインスタンスを立ち上げたり、データベースをダンプしたりするのに1分もかかりません。私の実務経験上、これはマスターすべき必須スキルの一つです。なぜなら、たった一つの認証情報の漏洩が、企業の評判や財務に壊滅的な被害をもたらす可能性があるからです。
根本的な原因は、通常、無能さではなく人間の性質にあります。私たちは忘れる生き物です。コミット前にキーを削除しようと思っていても、つい他のことに気を取られてしまいます。手動のコードレビューだけでシークレットを見つけようとするのは無理な話です。眠ることのない自動化されたセーフティネットが必要なのです。
クイックスタート:5分でシークレットを検出する
Gitleaksは、Gitの履歴や現在のファイルからシークレットをスキャンするために設計された、高速で軽量なツールです。使い始めるのに複雑な設定は不要です。Dockerがインストールされていれば、すぐにプロジェクトをスキャンできます。
docker run -v $(pwd):/path zricethezav/gitleaks:latest detect --source="/path" -v
ローカルバイナリを好む場合は、macOSならHomebrewでインストールするか、Linux/Windows用の実行ファイルをダウンロードできます。インストール後のスキャン実行は非常に簡単です。
gitleaks detect --source . --verbose
detectコマンドは現在の状態をチェックします。コミット履歴全体をスキャンしたい場合(既存のプロジェクトには強く推奨します)、gitモードを使用します。
gitleaks detect --source . --log-opts="--all"
Gitleaksが何かを見つけると、終了コードとして0以外を返します。これはCI/CDパイプラインにおいて、デプロイを失敗させてブロックするためにまさに必要な挙動です。
ディープダイブ:パイプラインへのGitleaks統合
自分のPCでGitleaksを実行するのも良いですが、真価を発揮するのは、すべてのプルリクエストに対してGitleaksのチェックを強制するときです。主要な2つのプラットフォームでの設定方法を見ていきましょう。
GitHub Actionsへの統合
GitHubでは、公式のGitleaksアクションを使用して非常に簡単に設定できます。`.github/workflows/gitleaks.yml`ファイルを作成します。
name: Gitleaks
on:
pull_request:
push:
branches: [main]
jobs:
scan:
name: Gitleaks Scan
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: gitleaks/gitleaks-action@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
`fetch-depth: 0`に注目してください。これが重要です。デフォルトでは、多くのCIツールは最新のコミットのみを取得します。Gitleaksは、マージされようとしている古いコミットにシークレットが隠されていないかを確認するために、完全な履歴を必要とします。
GitLab CIへの統合
GitLabユーザーの場合は、GitleaksのDockerイメージを使用して`.gitlab-ci.yml`ファイルにジョブを追加できます。
gitleaks_scan:
stage: test
image:
name: zricethezav/gitleaks:latest
entrypoint: [""]
script:
- gitleaks detect --source=$CI_PROJECT_DIR --verbose --redact
`–redact`フラグはCIにとって優れた機能です。レポート作成時にビルドログへ実際のシークレットが再び出力されて漏洩してしまうのを防ぐために、シークレットを隠してくれます。
高度な使い方:カスタマイズとベースラインの設定
シークレットのように見える文字列がすべて本物のシークレットであるとは限りません。誤検知(False positive)は開発の生産性を下げる敵です。テスト用のダミーキーでパイプラインが止まってしまうと、開発者はツールを無視し始めるでしょう。
.gitleaksignoreによる誤検知への対応
もしGitleaksが、安全だと分かっているファイルや特定の行をフラグした場合は、そのままにしないでください。ルートディレクトリに`.gitleaksignore`ファイルを作成します。Gitleaksの出力に含まれる特定のFingerprint(検出結果のハッシュ)を指定して無視させることができます。
# .gitleaksignore
# 特定のテスト用認証情報を無視する
6f7d8e9a... (ここにフィンガープリントを記述)
ベースラインの設定
何千ものコミットがある古いプロジェクトにGitleaksを導入する場合、何百もの「シークレット」が見つかるかもしれません。その中には古いもの、失効したもの、あるいは誤検知も含まれるでしょう。ツールを使い始めるために500個もの問題を修正したくはないはずです。そこでベースラインを使用します。
gitleaks detect --source . --baseline-path gitleaks-baseline.json
これにより、現在のすべての問題のレポートが生成されます。今後、Gitleaksは「新規に」導入されたシークレットがある場合のみ失敗するようになります。これにより、過去のクリーンアップを行う前に、まずは「流血を止める」アプローチをとることができます。
カスタムルール
企業ごとに独自の内部パターンがあります。たとえば、社内APIキーが常に`MYCORP_`で始まるとします。`gitleaks.toml`ファイルでカスタムルールを定義できます。
[[rules]]
id = "mycorp-api-key"
description = "MyCorpの社内APIキーを検出"
regex = '''(?i)MYCORP_[a-z0-9]{32}'''
keywords = ["mycorp"]
漏洩のないワークフローのための実践的アドバイス
CIにGitleaksを実装するのは最後の防衛線ですが、それだけであるべきではありません。チームの安全を守るために私が実践している戦略を紹介します。
1. Pre-commitフック:プッシュ前にキャッチする
CIが失敗するまで待つ必要はありません。`pre-commit`をインストールし、ローカルのワークフローにGitleaksを追加しましょう。これにより、シークレットが開発者のマシンから離れることさえ防げます。
# .pre-commit-config.yaml
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.18.2
hooks:
- id: gitleaks
2. シークレットが見つかったらどうするか?
もしプルリクエストでGitleaksがシークレットを見つけたら、**単に行を削除して再度コミットするだけではいけません**。そのシークレットは依然としてGitの履歴に残っています。もしシークレットが一度でもリモートサーバーにプッシュされたなら、それは漏洩したものとして扱う必要があります。
- 無効化(Rotate): 直ちにキーを失効させ、新しいものを生成してください。
- 削除(Remove): どうしても履歴から抹消する必要がある場合は、`git-filter-repo`やBFG Repo-Cleanerなどのツールを使用してください。ただし、常に無効化が最優先です。
3. 環境変数を使用する
当たり前のことのように思えますが、Gitleaksの失敗を避ける最善の方法は、コードにシークレットを入れないことです。`.env`ファイルを使用し(`.gitignore`に追加するのを忘れずに)、AWS Secrets ManagerやHashiCorp Vaultのようなシークレット管理サービスを活用してください。私の経験上、Gitleaksで多くの除外設定が必要になっているなら、シークレットに対するアーキテクチャ上の approach 自体に問題がある可能性が高いです。
シークレット検出を自動化することで、「何事もないことを願う」文化から、プロアクティブなセキュリティ体制へと移行できます。設定には1時間もかかりませんが、エンジニア人生で最悪の日を回避できるかもしれません。

