【書き起こし】社内用GitHub Actionsのセキュリティガイドラインを作成した話 – Toshiki Kawamura【Merpay & Mercoin Tech Fest 2023】

Merpay & Mercoin Tech Fest 2023 は、事業との関わりから技術への興味を深め、プロダクトやサービスを支えるエンジニアリングを知ることができるお祭りで、2023年8月22日(火)からの3日間、開催しました。セッションでは、事業を支える組織・技術・課題などへの試行錯誤やアプローチを紹介していきました。
この記事は、「社内用GitHub Actionsのセキュリティガイドラインを作成した話」の書き起こしです。

@goro:今回、「社内用GitHub Actionsのセキュリティガイドラインを作成した話」というタイトルで発表させていただきます。株式会社メルコインで、バックエンドエンジニアをしております。Toshiki Kawamuraと申します。よろしくお願いします。

私は株式会社メルコインに、2022年の6月に入社しました。メルコインでは主にビットコイン取引サービスの立ち上げに参画して、バックエンドエンジニアとして開発運用を担当しております。

今回発表の題材になった、GitHub Actionsのセキュリティガイドラインの作成などの取り組みも関わっております。

まず発表の最初として、今回テーマに置いているGitHub Actionsのセキュリティガイドラインについて説明させていただきます。

GitHub Actionsセキュリティガイドラインとは、社内でのGitHub Actionsの利用の広がりに合わせて、社内有志によって検討策定された。セキュリティのガイドラインになっております。

GitHub Actionsを使うにあたり、どういった点に留意すれば、最低限の安全性を確保できるか学習してもらいたい、定期的に本ドキュメントを見返してもらい、自分たちのリポジトリが安全な状態になっているかを点検する際に役立ててもらいたいという想いに基づいて作成されているガイドラインになります。

ガイドラインは、合計4人のチームで作成しました。

まずは株式会社メルカリのSolutions Teamに所属している@vvakameさん、株式会社メルカリのバックエンドエンジニアをしている Motonori Iwataさん、株式会社メルコインのエンジニアリングマネージャーをしている sadahさん、僕の4人の有志メンバーで、このガイドラインを作成していきました。

それでは、本発表の流れを事前に紹介します。まず最初にガイドラインの中身を一部紹介いたします。その後に、ガイドラインの社内での活用状況について紹介した後に、最後にガイドライン策定の裏話ができればと思います。

それでは発表に入っていきます。まずはガイドラインの中身を一部紹介します。

ガイドラインを策定する上で、まずはチーム目標を決めました。

まず一つ目に「常に達成したいこと」として決めたのは、「外部の攻撃者からの攻撃を防ぐこと」。二つ目に、「可能であれば考慮したいこと」として、「内部と同等の権限を持つ攻撃者からの攻撃を防ぐ」。この二つを大きな目標に置いて、ガイドラインを作成していきました。

ガイドラインの構成は3部になっています。

まずはどのような脅威があるのかを知ってもらうという意図を込めて、第1部では、脅威を知るというテーマで、GitHub Actionsを利用するにあたって、起こりうるセキュリティ上の脅威を紹介しました。

2部では、1部で紹介した脅威に対して、どのような対策が取れるのかを紹介しました。

最後の3部では、主に2部の内容をベースに、どのような項目を満たすと、実際にセキュリティの対策ができるのかがわかりやすくなるように、チェックリスト形式で行って、ほしい対策について、具体的な設定方法を含め、記載しました。このような内容でガイドラインは構成されています。

それでは1部から紹介していきます。

脅威として紹介したのは、「権限設定の不備を突く攻撃」になります。プルリクエストを契機に起動するトリガーは攻撃者が何かを仕掛ける余地が大きく、不注意にワークフローを構築すると、シークレットを外部に送信されて攻撃を受ける可能性があります。

補足情報として、GitHub Actionsのトリガーにはどのようなものがあるかを紹介していきたいと思います。

例えば、ワークフローのリポジトリで発生したイベントです。例えば、リポジトリのDefault Branchにプッシュが行われたときや、リリースが作成されたとき、あるいはIssueがオープンされたとき。

プルリクエストが作成されたときなどに、ワークフローを実行するように設定することが可能です。

他にも、GitHubの外部で発生し、GitHubでリポジトリディスパッチイベントを発生させるイベントですとか、時間指定での自動実行など、さまざまなトリガーがあります。

そのようなワークフローの権限設定において不備があると、例えばシークレットが外部に送信されるなどの危険性があります。

ここで、外部に送信される方法として考えられるものをいくつか記載しました。例えば、ビルドスクリプトに細工をする、依存関係にあるライブラリを悪意のあるものに差し替える、自動実行の仕組みに相乗りされる(例えばnpmのpreinstallやpostinstall)。

また、過去にも実際に人気のライブラリでローカルファイルをスキャンする事例がありました。このような方法でシークレットが外部に送信される危険性があります。

それ以外にも、権限設定の不備があると、攻撃が行われるような影響が考えられます。

例えば、攻撃者に悪意のあるActionsや、侵害されたActionsによってGitHub Actionsの計算リソースを不正に利用される可能性が考えられます。

他にも、侵害された または 悪意のあるActionsによって、リポジトリの自動ワークフローが中断される可能性もあります。他にもDeployment Keyやアクセストークンなどの、シークレットへの読み取りアクセスは攻撃者が他のリソースを侵害するために利用される可能性があります。以上が権限設定不備があった場合に、起こりうる事象の紹介です。

次に紹介したいのは、インジェクションによる攻撃です。一見安全に見えるワークフローにおいても、コードやコマンドインジェクションを引き起こす可能性があります。

事例を二つ紹介します。まず、事例の一つ目になります。スライドのコードを見てください。

このコードにはインジェクションの脆弱性があります。コメントを二重括弧で囲っている箇所がありますが、ここに1+1のようなものを入れると、Actionsは内部で二重括弧のあたりを補完するためにlodashを使っているため、Node.jsのコードが実行され、出力が2になります。

二つ目の事例です。ワークフローのインラインスクリプトに直接インジェクションを配置するシナリオも考えられます。また、ブランチ名やメールアドレスへのコマンドインジェクションも可能です。

ここで具体的に紹介するのは、こちらのコードです。

内部の式の二重括弧が評価され、結果の値に置き換えられるため、コマンドインジェクションに対して脆弱になる可能性があります。ここではプルリクエストのタイトルが二重括弧に囲まれています。

攻撃者が実際にどのようなことができるかというと、「a”;ls $ GITHUB_WORKSPACE*」というタイトルのPRを作成する可能性があります。これを利用して、ステートメントを中断し、ランナーでコマンドを実行できるようになっています。実行すると、lsコマンドが確認できます。

インジェクションが起こると、どのような影響があるかを紹介します。インジェクションをされると、攻撃者は任意のコマンドを実行できるため、外部のサーバーにシークレットを送信するHTTPリクエストを行うことが可能になります。

リポジトリへのアクセストークンを取得しても、ワークフローが完了すると失効するので、攻撃自体は簡単ではありません。しかし、攻撃者が自動化し、管理するサーバーにトークンを呼び出してコンマ数秒で攻撃を実行することが可能です。

その場合、GitHub APIを利用してリリースを含むリポジトリのコンテンツを変更するなどの影響も考えられます。

なので攻撃者は悪意のあるコンテンツをGitHub Context経由で追加できるので、潜在的に信頼できない入力として扱う必要があります。以上が第1部「GitHub Actionsでの脅威を知る」の紹介でした。

第2部は「対策を考える」です。

まず対策の一つとして紹介したいのは、「最小権限の原則に従う」ということです。最小権限の原則は、ソフトウェアがタスクを達成するために必要な最小限の権限セットで実行されるべきであるという原則です。

ワークフローで利用可能なシークレットの権限と、ワークフロートリガーの種類に基づいて自動的に提供される一時的なリポジトリトークンの両方に当てはまります。

この原則に従うと、GITHUB_TOKENの権限のデフォルト設定は、読み取りと書き込み権限から読み取り専用に変更した方がいいと思います。

実際にこの設定をやろうとすると、リポジトリのSettings > Actions > Generalから変更できるので、ぜひ変更してみてください。

また、GitHub Actionsの権限はジョブ単位で設定を行うことで、権限を最小化できますのでなるべく権限は細分化して設定することが推奨されます。

シークレットの利用についても、いくつか対策があります。例えば、Long=lived tokenを使用しない、Workload identity federationを用いたSecret Managerの利用を検討する、JSONなどの構造化データをシークレットにしないことがあげられます。

3つ目については、なぜかというと、GitHub Actionsは、全文をマスクデータとして扱ってくれますが、部分マスクはされないためです。

ワークフロー内で使用される全てのシークレットマスクをマスクするように登録することも、対策として考えられます。シークレットに保存されたアクセストークンの利用状況を観察することも必要です。

他にもスコープが最小限のクレデンシャルを使用する、登録されたシークレット監査およびローテーションする、シークレットへのアクセスについてレビューを要求する。こういった対策が考えられます。

次は、イベントトリガーの対策です。

利用すべきイベントトリガーとして、リポジトリへのwriteはできないように制限されているので、プルリクエストの処理にはpull_requestイベントを使った方がいいです。

少し制限を緩めたものとして、pull_request_targetがあります。Github Actionsのワークフロー自体は、pull_request_targetだと、Default Branchのものが使われます。ワークフローのyamlに直接記載する場合は、攻撃者によって上書きされることはありません。チェックアウトしたコードに含まれるComposite Actionを使う場合は注意が必要となります。

ここで、Composite Actionについて補足させてください。Composite ActionはカスタムActionの一つであって、使用することで、ワークフローの複数Stepを組み合わせて一つのActionsにできます。

例えば、複数のrunコマンドを一つのActionにまとめて、そのActionsを一つのStepとしてワークフローから呼び出して実行することが可能になってきます。

なのでpull_request_targetをイベントトリガーとして使う場合、Composite Actionは、攻撃者によって上書きされる可能性があるので、注意が必要です。

シークレットの内容を露出する際、可能な限り単位を狭くする方がいいです。Job単位よりStep単位の方がより良いと考えられます。Step間のファイルによるデータのやり取りは、全ステップから可視であると考えてください。

Jobは処理によって分けることも一つの対策になります。例えば、テスト/ビルド/デプロイはそれぞれJobを分けた方がいいです。これはなぜかというと、必要なGithub ActionsのPermissionやクラウドプロバイダーの権限を制御できるためです。

次に紹介したいのが、Dependabot / Renovateを利用したGithub Actionsでの更新になります。Actionsはバグの修正や新機能によって、頻繁に更新されます。Dependabot / RenovateでGitHub Actionsの依存関係を最新に保つことができるため、設定しておくとより良いと考えます。

次はサードパーティのActionsを利用する際の注意点です。サードパーティのActionsを利用する場合、基本的にFull Changeset Hashに固定するのがいいと考えています。

サードパーティのActionsの書き方は、四つあります。

まず一つ目がFull Changeset Hash。これは基本的には衝突が困難になっています。次にあるのがShort Changeset Hash。これも衝突がしにくいですが、脆弱となっています。次に、よく使われるTag / Releaseです。この場合、タグを後で変更されて意図しない変更が混入してしまう可能性があるので、注意が必要です。Branch Nameの場合意図しない変更が混入してしまう可能性もありますし、将来壊れる可能性があるので、なるべくFull Changeset Hashで指定するのがいいと考えています。

Full Changeset Hashで記入すると、このバージョンを使っているのかがいまいちわからないなっていうのがあるので、その場合はバージョンコメントを記載するのがわかりやすくておすすめです。

同じくサードパーティActionsを利用する際の注意点でもありますが、Actionsのソースコードをしっかり観察して、サードパーティのホストにシークレット送信するなどの疑わしいことがないか確認することが必要です。

ワークフロー内で利用しているサードパーティActionsのAction permissionsの設定をセキュリティ観点で見直すことも推奨されます。この設定に関しては同じくリポジトリのSettingsで可能になっています。不要なワークフローやJobは削除した方がいいです。不要なものは削除して、なるべく依存を減らすのが良いです。

先ほども触れたインジェクションについてですが、これを防ぐためには信頼されない式の入力値を中間環境変数に設定することが、対策として考えられます。

例ではこのようにenvに中間環境変数を入れていますが、この方式は、スクリプトの生成に影響するのではなく、メモリに保存されて変数として使用されます。このように、信頼されない式の入力値を中間環境変数に設定するのも有効です。

他にも、シェル変数をダブルクォートして単語の分割を避ける。これはシェルスクリプトの一般的な水槽事項でもあります。

GitHubのカスタムアクションやワークフローを書くときは、信頼できない入力に対して書き込み権限でコードを実行することがあることを考慮した方がいいです。外部Actionsとなりますがactionlistを使用することで対策できるので、導入を検討したり、GitHub Security Labの開発するCodeQL queriesを利用したりすることも対策として考えられます。

それでも完全に攻撃を防ぐことは不可能と考えて、問題が発生したときに受ける影響を最小限に抑える必要があります。

例えば、プロダクション環境に影響を及ぼす(サービス停止など)ことが最悪のケースなので、対策が必要です。もう一つ、GitHub Action がPRを作成またはオーナーとして承認しないようにすることも対策の一つです。

最後に、第3部の「セルフチェックリスト」です。

セルフチェックリストは、定期的にチェックすることで、GitHub Actionsの安全な利用に繋げるという目的があり、ガイドラインで学習した内容が本チェックリストでカバーすることを目指して作成されています。

第2部の内容をベースに、講じてほしい具体的なセキュリティ対策を設定方法含め、チェックリスト形式で記載しています。

ここでは一例を紹介します。例えばCODEOWNERSの設定を見直すことが一つチェックリストにあります。CODEOWNERSというファイルが.githubディレクトリにあるのですが、そこで適切にコードのオーナーが設定されることが必要になってきます。

Protected Branchの設定で、Default BranchへのPull RequestがCODEOWNERSによる承認が必須になっていることも、チェックする必要があります。

続いて、ワークフロートリガーを見直すこと。コードプッシュをトリガーとする場合、pull_requestか、それが難しければ、pull_request_targetを使うことを考えた方がいいです。
on: psuhをpull_request用に使っていたら見直す必要があります。
このように、具体的な対策をチェックリスト形式で書いています。

さらに詳しい内容はブログに公開しておりまして、そちらを見ていただきますと、今回発表したガイドラインの内容が更に詳しくなっておりますので、ぜひご覧いただければありがたいです。

参照
社内用GitHub Actionsのセキュリティガイドラインを公開します

次は、ガイドラインが実際に社内でどのように活用できているかを紹介します。

一つ目の活用状況として紹介したいのが、Developer Documentationの追加です。これは主に、メルカリ、メルペイ、メルコインのバックエンドエンジニアがよく参照する社内プラットフォームの使い方がまとまった社内ポータルです。そこにGitHub Actionsのセキュリティガイドラインを掲載していただきました。

次はSecure Coding Guidelinesの掲載です。このガイドラインはSecurity Teamがメンテナンスする社内基準のセキュリティルールを満たすためのガイドラインです。ここにもGitHub Actionsのガイドラインを掲載しました。

他にも各チームでのガイドライン提供やサポートなどを行っており、プロジェクトメンバーに自チームに関するリポジトリに対して、今回作成したガイドラインの内容を適用させたり、他のチームがガイドラインを適用する際のサポートや質問を受け付けるような体制となりました。

最後に、「ガイドライン策定の裏話」をします。

まず、このガイドラインをどのように作ったかについて紹介します。まず最初に、作成する上で行ったことは、GitHub Actionsのセキュリティに関する文献記事をチームメンバーで読んでいくことです。記事には複数の記事がリンクされているので、それらも読んでいきました。

そこで得たインプットをもとにガイドガイドラインのアウトラインをまとめて、3部構成を作りました。参考文献の設定を試したりしながら、ガイドラインを変えていくフェーズに入り、その後に自分たちでガイドラインをレビューして、あとSecurity Teamにもレビューしていただきました。レビューをいただいた内容を修正して、英訳して公開しました。

ちょうど1年前ぐらいから始まったプロジェクトで、2022年の7月から9月の間にメンバーを招集して、アウトライン・執筆を開始していきました。その後、10月から12月の間にレビューを実施したり、リファクタリングをした後に、2023年に入ってから最終レビューが完了して、正式版を公開しました。4月から6月の間に、エンジニアリングブログでの社外公開なども行いました。

ガイドラインを作成していく中で、気をつけた点についても、4点ほど紹介させてください。

まず一つ目は「小さく始める、無理をしない」ということ。これはボランティアメンバーで、それぞれのメンバーが別のプロジェクトを持ちながら進めていったので、なるべく無理をしない形で、進めていきました。

二つ目が、「絶対完成させるという強い意志を持つ」。こういう有志の取り組みを長期的に継続していくのは難しいかなと思うのですが、でも絶対完成させるという強い思いをみんなで持って、完成させました。

三つ目が、「適切な量のフィードバックをもらえるように意識する」。これはちゃんと外部の意見を取り入れながらリファクタリングできるようにという名目でもありますし、大量にフィードバックが降ってくると修正も大変なので、適切な量になるようにコントロールしてもらいました。

四つ目が、「正式版を公開してから育てていく」。GitHub Actionsやセキュリティなどに関連する技術は、今後も日々アップデートしていくので、正式版を公開したから終わりではなく、今後も育てていくようにしていきたいです。

GitHub Actionsのセキュリティガイドラインは、今後も適切に更新していき、よりスムーズで安全な開発をサポートできるように努めていきたいと思っています。また更新した際には外部向けにも発信していこうと考えておりますので、ぜひご覧いただけるとありがたいです。

以上です。ご清聴ありがとうございました。

  • X
  • Facebook
  • linkedin
  • このエントリーをはてなブックマークに追加