Blog

TrufflehogでGitHub上にある認証情報をチェックして検知結果をIssue化する

最近GitHubの認証情報の取り扱いで悩んでいる GHE管理者の石川です。

GitHub ActionsのOIDCを使った各種クラウドとの認証便利ですよね!
OIDC利用も増えてきたしPAT周りをもっと綺麗にできないだろうかと考えています。

classic PAT廃止してFine-grained PATとGitHub Appにしたい
→ いまどのくらい使われているのだろう
→ GitHub上に認証情報記載されてない?
といった具合に、整理よりも先に掃除の必要性を感じてきました。

弊社のGitHub組織には現状Publicリポジトリはないため、即座に危うい状態というわけではありませんが、連携先やデプロイ先で漏洩する可能性はあるので、昨年何度が記事を目にした Trufflehog を導入することにしました。

サンプルリポジトリでお試し

都合よく認証情報の入ったリポジトリは記憶にないので、公式が用意してくれている認証情報が入ったリポジトリをので体験してみます。

Trufflehogのサンプルリポジトリーをスキャンした検出結果

いい感じですね、コマンド一発でやりたいことができるのは素晴らしい!

組織内全リポジトリに対してスキャン

組織内のすべてのリポジトリに対して実行すると、かなりの時間がかかるのでローカルではなく適当なサーバー上から初回スキャンをしてみます。詳しくは後述してますがGitHub API制限にひっかかりそうなのでスリープをいれて実行しました。

--no-verification で有効有無を問わず存在を確認して、どのようなDetectorが検証されたのか、検証ありで実行しても大丈夫そうか確認して、本番スキャンでは --results=verified,unknown にして実行しました。

結果、思ったよりたくさん検出されました!え、こんなにあるの!?と思った大部分はSlack Webhook。これは最悪漏洩しても影響は微量なので一旦放置。
ほかにも見過ごせない認証情報もありましたので、検知結果をIssue化する仕組みを作っていきます。

定期実行用GitHub Actionsを作成

事前準備

GitHub AppとPATを用意します。

  • 更新リポジトリチェック&Issue作成用GitHub App
    • Read access to metadata
    • Read and write access to issues and organization projects
  • Trufflehogスキャン用PAT
    • Read access to code, issues, metadata, and pull requests

WF1: 更新のあったリポジトリを取得してTruffehogを実行

日次で更新のあったリポジトリのみをスキャン対象としています。
GCSに入れた後BigQueryで集計したいので使いたいので結果は --json で出力しています。

  1. cronで日次実行
  2. 更新のあったリポジトリ一覧を取得(GitHub App Tokenを使用)
  3. Trufflehogでスキャン(PATを使用)
  4. スキャン結果をGCSに保存

個々のリポジトリでCI時にスキャンしたい場合

git-secrets等でコミット前に防ぐのが最適ではありますが一応TIPSとして。

--since-commit で特定のコミット以降、 --max-depth で対象とするコミット数、 --branch で対象ブランチなどを指定すればスキャン時間を短縮できます。--github-actions でGitHub Actions用の出力結果にすることもできます。

WF2: 検知結果を対象リポジトリのIssueへ登録

デバッグしやすいのでスキャンのワークフローとは分けてます。

  1. WF1が成功したら実行
  2. スキャン結果とIssue登録済みmd5をGCSから取得
  3. スキャン結果のmd5を作成してIssue作成済みならスキップ or 特定のDetectorならスキップ
  4. 作成済みではない検知結果を リポジトリ・パス・Detector で group by
    (一つ一つIssueを作ったら邪魔なのである程度まとめる)
  5. 対象リポジトリにIssueを作成し、指定Projectに追加(GitHub App Tokenを使用)
  6. Issue登録済みmd5をGCSへ保存

GitHub Projectに追加することで、どのリポジトリにどのくらい認証情報が残っているか、一覧で確認することができます。

コード側は変更して対処したり、認証情報を無効化した場合、次回スキャン結果から消えます。それをトリガーに自動でIssueも閉じたら綺麗ですがそこまではやっていません。

ちなみに初回スキャンで見つけた検知結果はGCSに上げて、事前にActionsを手動実行することでIssue登録を済ませています。

気を付ける点

TrufflehogはGitHub App Tokenに未対応

Support scanning GitHub Orgs with GitHub App Token · Issue #1513 · trufflesecurity/trufflehog

App対応していないので、個人のPATを使いましょう。
GitHub App Tokenで動かそうとすると、Resource not accessible by integration エラーが起きます。

GitHubのAPI制限

Trufflehogがどの程度APIを叩いたかは、InsightsのREST APIのグラフからスキャンに使ったPATの所持ユーザーを選択することで確認可能です。

Trufflehogのスキャンに使っているPATのAPIリクエスト数

日次で更新されるリポジトリ数にもよりますが、いまのところ5,000req/hour の制限を超えることはまずなさそうです。

初回全リポジトリスキャン、1日に大量のリポジトリ更新、IssueやPRやコメントが大量にある場合はAPI制限を超えやすくなりますので、その場合は時間を分けてスキャンしたり、スリープ入れて1時間内スキャン数を抑えたりして回避しましょう。

参考:Rate limits for the REST API – GitHub Docs

認証情報側が更新されたらスキャンした結果も変わる

リポジトリ上からは消えていないが認証情報は無効にした場合、 VerificationFromCacheExtraData に変化がありました。検知対象の同一性を担保するユニークIDを作る時は、こういう要素を含まないように作成しましょう。これを理解していなくて、最初重複したIssueを作ってしまいました。。

Macから実行したとき error trufflehog failed to parse commit date エラーが出る

trufflehog fails to parse localized timestamp · Issue #3338 · trufflesecurity/trufflehog

検出結果のTimestampが Timestamp: 0001-01-01 00:00:00 +0000 で表示されます。
Ubuntuではエラーは起きなかったので気になる方は、サーバーなりコンテナなりで実行しましょう。

今後の予定

Trufflehog初めて使いましたが、サクッといい感じにやってくれるし、痒いところにも手が届くツールでとても便利ですね。GitHub Advanced SecurityならSecret scanningも対応していますが、組織内全リポジトリを対象にしたいとなると金銭的に厳しいものがありますし、OSSでカバーできるのはありがたいです。

実は検出まではよくても、本気でGitHub上から跡形もなく消し去るのはかなり大変な作業だったりします。
参考:GitHub上のsensitive dataを削除するための手順と道のり | メルカリエンジニアリング

そのため一旦のゴールとして以下が適当かなと思っています。

  • 最新のコードに認証情報が含まれていないこと
  • 一度でもGitHub上にコミットしてしまった認証情報は再発行すること
  • 各人のgit-secrets等の設定厳密化

まだまだ先は長そうですが、少しずつでも今日よりも明日をセキュアにしていきたいと思います。

ニフティでは、
さまざまなプロダクトへ挑戦する
エンジニアを絶賛募集中です!
ご興味のある方は以下の採用サイトより
お気軽にご連絡ください!

ニフティに興味をお持ちの方は
キャリア登録をぜひお願いいたします!

connpassでニフティグループに
参加いただくと
イベントの
お知らせが届きます!