リポジトリに API キーやトークンが混入していないかをコミット履歴ごと走査する、gitleaks を CI に入れました。たいしたことではないと思って gitleaks-action@v2 を貼り付けようとしたら、Organization 配下のリポジトリではライセンスキー必須(=有料)になっていて、ちょっと足踏み。
結論としては MIT ライセンスの gitleaks CLI バイナリを直接ダウンロードして実行する 形に落ち着いたので、その手順を残しておきます。
なぜ CLI 版を選んだか
gitleaks/gitleaks-action は GitHub Action として配布されているラッパーで、貼り付けるだけで動く便利さがあります。ただ v2 から Organization 所有のリポジトリでは GITLEAKS_LICENSE が必須 になりました(個人リポジトリは無料)。会社・コミュニティで運用しているリポジトリだと、これだけのために有料プランに乗るのは割に合わない。
一方、gitleaks 本体(CLI)は MIT ライセンスのまま で、ライセンスキー不要で使えます。GitHub Releases にプラットフォーム別のバイナリが置いてあるので、Actions ワークフローから直接ダウンロードすれば同じ機能が無料で得られる、というだけの話。
採用したワークフロー
.github/workflows/secret-scan.yml:
name: secret-scan
on:
pull_request:
push:
branches: [main]
permissions:
# 最小権限:チェックアウトした repo を読むだけで十分
contents: read
jobs:
secret-scan:
name: Secret Scan (gitleaks)
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0 # コミット全履歴を走査するので深さ無制限で取る
- name: Install gitleaks
env:
GITLEAKS_VERSION: 8.30.1
# https://github.com/gitleaks/gitleaks/releases から拾った
# gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz の SHA256。
# GITLEAKS_VERSION を上げたら一緒に更新する。
GITLEAKS_SHA256: 551f6fc83ea457d62a0d98237cbad105af8d557003051f41f3e7ca7b3f2470eb
run: |
set -euo pipefail
ARCHIVE="gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz"
curl -sSfL -o "$ARCHIVE" \
"https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/${ARCHIVE}"
echo "${GITLEAKS_SHA256} ${ARCHIVE}" | sha256sum -c -
sudo tar -xz -C /usr/local/bin -f "$ARCHIVE" gitleaks
rm -f "$ARCHIVE"
gitleaks version
- name: Run gitleaks (full history scan)
run: gitleaks detect --source . --redact --verbose --exit-code 1
ポイントは 4 つだけ:
fetch-depth: 0—gitleaks detectは git log 全部を走査するので、shallow clone だと過去のコミットにあるリークが拾えない。- SHA256 検証 —
curlで取ったバイナリを盲信しない。バージョンを上げるときは Releases ページで配布されている公式 SHA256 と差し替える。サプライチェーン攻撃の穴を 1 つ塞ぐだけのコストの安い対策。 --redact— 検知したシークレットの中身を「****」化してログに出さない。CI ログは PR 経由で第三者に見える可能性があるので、見つけたシークレットを CI ログに書き出して二次漏洩、というのは避けたい。--exit-code 1— 何か見つかったら job を fail させる(PR をブロックする)。デフォルトで設定されているけど明示しておくほうが意図が伝わる。
誤検知の許可リスト
リポジトリのルートに .gitleaksignore を置くと、gitleaks がそのファイルの行を無視してくれます。書式は
<commit-sha>:<file>:<rule-id>:<line>
の 1 行 1 件。コミット SHA、ファイル、ルール、行番号 が全部一致したものだけ silence される、という強い指紋方式なので、
- 同じファイルでも別の行に新しい疑わしい文字列が現れたら再検知
- 同じ行でも別のコミットに移動したら再検知(rebase で SHA が変わるなど)
例えば、テストフィクスチャに「いかにもキーっぽいけど本物ではないダミー」を入れているケース、ドキュメントに API のサンプルレスポンスを貼っているケース、などは指紋を .gitleaksignore に登録しておくと CI を通せます。「ぱっと見だと検知されるけど中身は実際には機密ではない」場面は思った以上に多いので、運用に入ったあとは少しずつ追記していくのが現実的。
注意点として、指紋には gitleaks のルール ID(stripe-access-token など)が入っているので、gitleaks のバージョン上げでルールがリネームされると指紋が外れて誤検知が再浮上することがあります。バージョン bump と一緒に再確認するのが安全。
一回入れておくと安心
CI に走らせておけば、
- うっかりコミットに入れた API キー、トークンの類が PR の段階で気付ける
- 過去にコミットして消した(けど git log には残っている)シークレットも検知できる
- 履歴を遡って消す or 再発行する判断がしやすい
という、「気をつけよう」では限界がある領域に網を張れる感じになります。
少なくとも MIT ライセンスの CLI 版だけでも入れておくと、後から「あれリークしてたかも」と冷や汗をかく頻度はだいぶ下がります。Organization のライセンスキーを払うかどうかは、その後で考えれば十分。