CircleCIのセキュリティアラートに対応した時の振り返り

 

株式会社mikan バックエンドエンジニアのgamiです。最近はFactorioにハマってしまい黙々と工場を建設しています。

2023年の年明けにCircleCIからセキュリティアラートが通知され、Twitterのトレンドになるほど多くの皆さんから反応があったことをご存知でしょうか?

circleci.com

mikanでもCircleCIを利用していたため、シークレットのローテーションなどの対応を実施しました。

この記事は社内用に残した対応履歴のドキュメントを社外用に書き直し、振り返りを付け加えたものです。

TL;DR

  • 結果的にmikanのシステムには問題ありませんでした。
  • CircleCIをアクティブに利用していたプロジェクトは1つだけだったため、CircleCIで組んでいたワークフローは他のプロジェクトに合わせてGitHub Actionsへ移行しました。

タイムライン

2023/01/05 11:34 JST メール受信

CircleCI Security Alert - 4 Jan 2023 - Rotate any secrets stored in CircleCIという件名でメールが来ました。

早速反省点ですが、この時点ではすぐに対応を開始することができませんでした。

この日はmikanの期初のタイミングで全体的にバタバタしており、加えてチームメンバーの休暇や突発的な採用業務などが重なったためです。

本来であればメールの内容を確認した上で対応の優先順位を判断すべきでしたが、後回しにしてしまいました。

2023/01/05 19:42 JST 関係者への共有

関係者へセキュリティアラートの共有。

関係者にSlackで周知した際のキャプチャ

正式な表記はCircleCIですが、半角スペースを入れてしまっています。

これからオペレーションを実施するには時間が遅いので、翌日に対応を行うことにしました。

しかし翌日もバックエンドチームのメンバーは休暇予定だったため、代表のkazuさんに協力を依頼しました。

Slackでペア作業の依頼をする様子

翌日を逃すと3連休に入ってしまい、対応がかなり遅れるリスクがありました。

四半期の始まりで各プロジェクトの方針レビューなどがある忙しいタイミングで快諾していただけて本当に良かったです。

Slackで快諾してくれるkazuさんのキャプチャ

楽しそうなkazuさん

2023/01/05 20:27 JST 事前準備

対応方針の書き起こし

翌日に作業実施が決まったため、下記のざっくりと対応計画を立てました。

  1. シークレットのリストアップ
  2. 1.の中から不要な鍵を特定し削除
  3. 使用中のシークレットのうち、他のシステムでも使っているものをリストアップ
  4. 3.で見つけたシークレットを更新

これはよく見ると2番は後回しでも良いです。実際に鍵が漏洩して悪用されていた場合、鍵を無効化することが優先されるため、いかに早く4番を完了させるかが重要でした。

実際の作業では2番よりも4番を優先できたので良かったと思います。

シークレットのリストアップ

mikanでCircleCIが有効になっているプロジェクトは2つありました。mikanで管理しているリポジトリは40件を超えているため、そこから比較するとかなり少ない件数です。

後日CircleCIからシークレットをリストアップするツールが公開されることになりますが、この時点では件数も少なかったので手作業で以下を確認しました。

  • Environment variables
  • Contexts
  • Deploy Key

ここで見つけたものはスプレッドシートでキー名を管理し、翌日の仕分けに利用しました。

2023/01/05 PST CircleCIからの追加情報

CircleCIから追加情報がありました。

(https://circleci.com/blog/january-4-2023-security-alert/Security update 01/05/2023 の部分)

ここではシークレットのローテーションに関する対応手順が書かれていたため、まずは該当の有無を確かめました。

CircleCIからの追加情報をまとめたNotionのキャプチャ

この調査にあたり、CircleCIのコンソールで私の権限では見れないものに関してはkazuさんにも非同期で確認してもらいました。

 

2023/01/06 11:57 JST ローテーションの開始

一人で対応可能なOAuthトークンのリフレッシュ及びDeploy Keyの差し替えのみを実施しました。

Deploy Keyの差し替えは少しだけ罠がありました。

  1. GitHub側のSSH Keysを削除
  2. Circle CI側のDeploy Keysを削除
  3. Circle CI側でAdd Deploy Keys
    • このとき、紐づくGitHubリポジトリのAdmin権限がないと画面上は何も起きない(ブラウザコンソールに404エラーが出力される)

コンソールに出ていたエラーは

{
	"message":"Not Found",
	"documentation_url":"https://docs.github.com/rest/reference/repos#create-a-deploy-key"
}

となっており、GitHubのドキュメントが案内されていたため、GitHubの権限を確認しました。

案の定権限が足りていなかったため、インフラ作業用の強い権限を持つアカウントで該当リポジトリの権限設定を修正してからリトライしました。(具体的には、Adminロールに個人アカウントだけが含まれている状態だったため、チームを招待しました。)

これにより、GitHub側でSSH Keysが更新されたことを確認しました。

2023/01/06 13:37 JST CircleCI-Env-Inspector

念のため、CircleCIから提供されたツールを実行してみました。 

github.com

そのまま動かすとエラーになったため軽くパッチを当てたところ、前日にリストアップした内容に問題ないことが分かりました。

2023/01/06 15:33 JST 追加の調査と手順書作成

ローテーション対象の絞り込み

リストアップした環境変数のうち、明らかに利用されていないものがいくつかあったため、本当に利用されているものだけを絞り込むために調査を行いました。

作業内容としては、対応するリポジトリに対して、CircleCIで設定している環境変数を呼び出している箇所をgrepして確認するという地道なものになりました。

この調査の結果、対象範囲をかなり絞り込むことができました。

ローテーションの具体的な手順書を作成

上記調査をもとに、アプリケーションの動作確認を含むローテーション作業の手順書を作成しました。(AWSの一部サービスを利用するIAMが対象でした。)

  1. IAMで認証情報を新規作成
  2. 検証用の新たな環境変数を作り、1の情報をコンテキストにセット
  3. 検証用の新たな環境変数を参照するようにアプリケーションを修正
  4. アプリケーションをデプロイ
  5. IAMが利用されたことと、AWSのサービスを利用する処理が問題なく動作することを確認する
  6. IAMの古い認証情報を削除
  7. 既存の環境変数を置き換え
  8. 4を再実行
  9. 5を再実行

上記を各環境 (開発環境、ステージング環境、本番環境) で実行します。

 

2023/01/06 16:00 JST ペアでローテーション実施

軽く背景の共有と状況報告を行い、kazuさんとペアで作業を開始しました。

3連休を控えた週末に何度もデプロイをすることになりましたが、一緒に見てもらえたことで焦らずに作業することができました。

不具合なく作業を完了できたのは、ペアで作業したからこそだと思います。

2023/01/06 18:00 JST 頃 サービスアカウントの停止

ひととおりデプロイ作業が完了したため、Firebase CLIトークンを発行しているサービスアカウントを停止しました。

振り返ってみると、トークンは真っ先に無効化しておくべきだったと思います。Firebaseのサービスアカウントを乗っ取られていた可能性があるためです。

mikanはFirebaseに依存したシステムがいくつかあるため、悪用されたときの影響はかなり大きくなってしまいます。

2023/01/10 16:30 JST ログ調査

シークレット漏洩の可能性のあるサービスはAWSとFirebaseの2種類のサービスだったためログの調査を実施しました。

AWSの方は、1つのサービスの許可しか与えられていないIAMのアクセスキーだったため、該当のサービスのログを確認し、不審なものがないかを探しました。

Firebaseの方は影響範囲が広かったため、まずはFirebaseのGUIコンソール上で異常がないかを確認し、その後APIの利用状況などを調べました。

これらの調査の結果を踏まえ、mikanへの問題はなかったと判断しました。

2023/01/18 17:40 JST ワークフローをGitHub Actionsへ移行

mikanでCircleCiを利用しているプロジェクトは2つあり、そのうち1つはメンテナンスが終了していました。

そのため、アクティブにCircleCIを利用しているプロジェクトは1つのみとなり、他のリポジトリのほとんどはGitHub Actionsを利用していたため、今回ローテーションを実行したプロジェクトもGitHub Actionsへ移行することにしました。

GitHub Actionsへ移行するついでにGitHub OIDCを利用するようにワークフローを修正し、よりセキュアな状態に組み替えました。

また、先日発表されたGitHub Actionsの構成変数を利用し、機密性の低いものは暗号化しないことで有事の際の調査に役立つようにしました。

github.blog

終わりに

新年早々大変な作業となりました。本件の対応に当たった各社及び個人の皆様もお疲れ様でした。

mikanでは結果的にCircleCIの利用を辞めてしまいましたが、CircleCIの今回の案内は非常に誠実だったと感じており、好感を持ちました。

CircleCIで実際に何が起きたのかといったレポートも公開してくれています。

これを機に、mikanのセキュリティの甘い部分に関しても改めて話題に挙がるようになってきました。

少ない人数で事業を拡大させつつ守りも盤石にしていかなければならず、一筋縄には行かないかも知れませんが、一つずつ着実に進めていこうと思います。

以上、CircleCIのセキュリティアラート対応の振り返りでした。