ソースコードに書き込まれた大量のシークレット事案(インシデント)について調査、優先順位付け、修復を行う

この記事は、アプリケーション・セキュリティチームを対象に、ソースコードに書き込まれたシークレット事案(インシデント)の優先順位付け、調査、修復を効果的かつ大規模に実践する方法について解説します。

Investigating, prioritizing, and remediating thousands of hardcoded secrets incidents

本記事は、GitGuardian社のホームページで公開されたブログ記事を基に、日本語に翻訳したものです。
(原題)Investigating, prioritizing, and remediating thousands of hardcoded secrets incidents

はじめに(インシデントは突然起こる)

シークレットの流出と認証情報の露出はいたるところで起きている”ということをどこかで見聞きしたあなたの会社のセキュリティ担当者は、「自社のプライベートリポジトリが気になって仕方がない」とあなたに言ってきました。そこであなたは、「そんな流出や露出、たくさんはあるわけがない」と高を括りながら、手始めに/AKIA[0-9A-Z]{16}/といった正規表現を使って検索を実行します。すると驚くことなかれ、有効なAWS APIキーと思しき結果が山のように見つかります。

この時点で、あなたはこれは氷山の一角であると確信します。1つのブランチ、1つの正規表現だけでは不十分ということで、GitGuardian(あるいはGitleaksやTruffleHog等)の力をかりて、リポジトリ一つ一つでシークレットの自動スキャンを実行します。問題の大きさを理解するのに、ものの数分もかかりません。数えきれないほどのシークレットが検出されてくるのです。あなたとセキュリティ担当者は呆然とした面持ちで顔を見合わせ、膨大な量のセキュリティ負債に対処しなければならなくなったことを悟ります。

このような話は、GitGuardianでは珍しい話ではありません。当社、GitGuardianが、何百人もの開発者と何百件ものリポジトリを抱える大手企業で実施する概念実証(Proof of Concept:PoC)でも、この手の何千件もの結果が表面化したことで数年来の悪しき管理体制が露呈するという話はよく耳にします。それでもなお信じがたいという方は、ぜひ当社の最新レポートをお読みください。Twitch、NVIDIA、Microsoft社のリポジトリ流出について分析を行っています。

コード内のシークレットの脅威は何が違うのか

外部からアクセスできるシークレットは、ソースコードに見つかるほかとは異なるタイプの脆弱性といえます。コードがコンパイル済か実行中かに関係なく、ソースコードに書き込まれたシークレットはそれ自体がリスクになります。最初の侵入地点としてリポジトリにアクセスした攻撃者は、その後すべてのブランチ、コミット履歴に足を延ばし、有効なシークレットがないか検索します。シークレットが見つかる場所がメインブランチか、短命と言われるバグフィックスブランチかは重要ではありません。有効であること、どこかにアクセスできることが重要になります。この点を念頭に、GitGuardianではインシデントの一つ一つを、放置することのできない潜在的な脅威とみなしています。


では、セキュリティエンジニアの処理能力を超えたインシデント件数が存在するとき、このような状況にどう対処すればいいのでしょうか?

インシデントの優先順位付けを行う

スタートは発見フェーズから

コードのセキュリティ対策、とりわけシークレット管理は、エンジニアリングチームごとに異なります。そのため、リポジトリのセキュリティ対策も一様ではなく、このことはインシデントで最も影響を受けるソースを検証すると顕著です。

Analyze your historical incidents to identify high-risk repositories
過去のインシデント分析により、高リスクリポジトリを特定する

取り掛かりとして、まずは最もシークレットの多いリポジトリを特定し、そのリポジトリが自社の開発チームが保守するどのアプリケーション、サービスのものかの紐づけからスタートすることをお勧めします。 続いて発見フェーズに入りますが、今回はシークレットを重点的に探すことにします。シークレット露出の傾向と経時的な変化について考察し、最も流出の多いシークレットのタイプとそれらシークレットでアクセスするサービスを特定します。

Analyze your historical incidents to identify very leaky secrets
過去のインシデントの分析により、流出しやすいシークレットを特定する

重大度レベルを定義する

本来であればここで一気に過去インシデントの修復に取り掛かりたいところですが、その前に優先順位付けのルールを設定することを提案したいと思います。以下は、インシデントの重大度とその優先度を判断する前に考慮すべき項目です:

タイプこれらはKubernetesクラスターの認証情報か、それともSlackのウェブフックURLか?
信頼性と現存の有無このシークレットは今でも悪用可能か?今でもGit履歴に残っているか。
露出このシークレットはパブリックリポジトリで外部からアクセスできる状態か?
リカバリこのシークレットは直近の四半期のものか、それとも5年前のものか?
インシデントの発生このシークレットは複数のファイルおよびリポジトリで露出されていたものか?
テストディレクトリこのシークレットはテスト目的で使われているか?

インシデントを修復する

修復フェーズを開始する前に、過去のインシデントに対する詳細な修復プロセスを規定する必要があります。自身のケースに照らし合わせて以下の質問に答えてみてください:

  • インシデントの修復はどのチームまたは役職が担当するのか?
  • どのチームまたは役職が、修復の進捗状況の追跡とオープン(対応中)インシデントのレビューの説明責任を持つのか?
  • 修復プロセス中の相談先はどのチームまたは役職か(例:シークレットのローテンション中にサービス停止を回避するためにDevOpsエンジニアが介入する等)
  • インシデントの解決にあたり開発者にどの程度自律性を持たしてもよいと考えているか?

開発者の力をかりて修復作業を大規模展開する

セキュリティエンジニアの数は開発者に比べてはるかに少なく(平均的な比率は100対1)、最新のアクティビティで生じた脆弱性すべてを処理できない可能性があるということはもはや周知の事実です。インシデントの修復作業を大規模展開するには、開発者をそのプロセスに引き寄せ、相応の役割を担ってもらう必要があります。具体的な方法を以下に示します:

手順1:特定とアラートの通知

過去のインシデントごとに、インシデント詳細の提供に協力してくれる開発者を特定します。ここでは、シンプルにコミットのオーサーメールを使用します。

手順2:フィードバックの収集

すべてのインシデントとそれぞれの協力開発者がリストアップできたら、インシデント詳細の一斉共有を自動化し、開発者にフィードバックを提供してもらうよう依頼をする必要があります。これにより、さらに次のような情報が得られます:

  • そのシークレットはテスト環境の認証情報か?それとも、誤判定か?
  • 機密のサービスまたはデータに直接アクセスできるか?
  • 本番環境で使用されているものか?
  • 開発者によってすでに無効になっているか?

手順3:解決

これでインシデントの優先順位付けと対応に必要なものはすべてそろいました。

▶修復ワークフローをフルに実行する場合は、開発者とDevOpsチームに調整を依頼し、以下を実行します:

  • まず、当該のシークレットを無効にし、ローテーションを実施する
  • コード中のシークレットを環境変数または集中化されたシークレットストレージへの適切な呼び出しに置き換える
  • 必要に応じて、当該インシデントの全記録が削除されるよう、Gitの履歴を書き換える(ただしGitは非常にややこしいため、この作業はお勧めしません)

▶あるいは、インシデントを速やかにクローズします。インシデントを再開したときのために、状況が分かるようフラグの追加を忘れないようにしてください(誤判定、テストキー等)

手順4:検証

上記手順についてすべて確認済みの通知を受け取ったら、インシデントを「解決済み(Resolved)」に設定します。そのシークレットが無効になったことを確認し、修復の証拠を得るために、当該のホストへの呼び出し(HTTPやSSH等)を自動化してもいいでしょう。

チーム間の協力体制が強化され、すべてのチームが修復プロセスになれてきたところで、セキュリティチームはその信頼を受け入れつつただし方針の検証していくことを提案します。長い目で考えた場合、開発者にはセキュリティチームからの介入をなるべく減らす形でインシデントを自ら解決する力を持たせることが重要です。

以下は自動ワークフローの一例ですので参考にしてください。

Automated workflow for enabling developer-driven remediation (incident sharing and resolution)
開発者主導の修復を可能にする自動ワークフロー(インシデント共有と解決)

 ‘忘れられた’インシデントにご注意

修復ワークフローでは一つ重要な点に留意する必要があります。それは、そのインシデントに協力してくれた開発者がいまも会社にいるか?ということです。答えが「ノー」であれば、その開発者の助けあるいは知識なしにことを運ばなければいけません。以下は、このような状況に直面した場合の対処方法です:

ステップ1:特定

最初は、その開発者が今も在籍しているかどうかを確認します(可能であれば):

  • 開発者が稼働状態であったときに所属していたチームを突き止める(LDAPを照会する等)。
  • (インシデント発生場所の)書き込み権限を持つリポジトリの管理者およびユーザーを特定する。

ステップ2:引継ぎ

‘忘れられた’インシデントの影響を受けるすべてのチームが特定されたら、過去のインシデントをまとめてエンジニアリング責任者、リポジトリの管理者あるいは然るべきチームメンバーに引き継ぎます。

あるいは、「セキュリティチャンピオン(推進リーダー)」のような育成プログラムが実施されている場合は、こうした便利なリソースの活用を図ります。修復のタスクは、すでに在籍していない開発者に変わってセキュリティチャンピオンが引き受けてくれる場合もあります。

最後に

コードに書きこまれた認証情報というインシデントを過去何年分修復するとう作業は、最初は非現実的に思えるかもしれません。しかし、入念な準備と相応のリソース、さらに適切な度合いのオートメーションにより、完全に取り除くことは可能であると考えます。

本ガイドでは、コード内シークレットというインシデントの修復に伴う複雑な側面についていくつか考察しました。AppSecプログラムにおけるシークレット検出と修復の最終的な目的は、予防に力を入れ、修復の負担を減らすことです。新たなインシデント回避の策を講じなくても、過去のインシデント解決に力を入れていけば、トータル件数は減らなかったとしても、修復にかかる労力は将来的には減っていくはずです。

GitGuardianのブログでは、近日中にセキュアな開発ライフサイクル(SDLC)におけるシークレット露出リスクを軽減する指針を公開する予定です。お見逃しのないようブログのチェックをお願いします!