この記事は、Techouse Advent Calendar 2024 15日目です。
昨日は 青木真一 さんによる Figmaプラグインを使って楽をしようとしたらCORSの壁に阻まれた でした。
15日目は keima が担当します。ちなみにTechouseではジョブハウス工場のモバイルアプリ開発をしています。
はじめに
Techouseに入社して純粋に思ったこととして、「セキュリティ意識が高いなぁ…」と思いました。 過去に勤務した経験のあるどの組織よりもセキュリティ意識がしっかりしていると感じました(もちろん近年はセキュリティ意識をより求められているというのもありますので、これまで勤めた組織もセキュリティ意識は向上していっているとは思います)。
お客様の情報をはじめとした情報資産の保護について、弊社の情報セキュリティ方針 を掲げるだけでなく、しっかり実行していくということに矜持を感じました。
そのような組織で働くと、自然と自分自身も同様の視点を持つようになります。そこで今回は、その視点を踏まえたうえでCI/CDに着目し、改善に取り組むことにしました。
TechouseではGitHub Actionsを用いてCI/CDを構築しています。 GitHub Actionsを用いるうえでは、その利便性と同時に、潜在的なセキュリティリスクを考慮する必要があります。ここからは、GitHub Actionsにおけるセキュリティリスクと、そのリスクを軽減できるツールについて取り上げていきます。
GitHub Actionsにおけるセキュリティリスク
GitHub Actionsにおけるセキュリティリスクは、条件によって色々と考えられるのですが、ひとまず業務でのリスクは以下があるということにします。
- 使用している action が汚染されないか
- GITHUB_TOKEN の権限が広く設定されていないか
- シェルスクリプトの実装ミスがないか
( PRで変更が加えられたworkflowをPRのコンテキストのまま実行する設定をしない とかもあるような気はしますが今回は割愛)
それぞれ傾向と対策を考えます。
pinact
: 使用している action が汚染されることを防ぐ
GitHub Actionsの特徴は、実行するイベントを全てシェルスクリプトで書かなくとも再利用できるようにパッケージ化されており、それが公開されており、公式だけでなく誰でも作成・利用できることにあります。
通常、私たちは uses: actions/checkout@v4
といった形でactionを指定します。これは、バージョン4の最新版を使うという指定です(厳密にはバージョン4の最新版であると配信者が指定したものを使う、詳しくは https://github.com/actions/toolkit/blob/main/docs/action-versioning.md )。
この仕組みは、常に不具合が修正された最新のバージョンを使い続けることが出来る半面、予期せず悪意のあるプログラムが自社のworkflowで実行されてしまう問題があります。また、事前にコードを読んで安全性を確認していたとしても、更新の際に汚染されたら意味がないわけです。
このような予期せぬ更新を防ぐために、タグではなくSHAコミットハッシュを指定することができます。
このような形で指定できます: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
しかし、既存プロジェクトで置き換え作業をいちいち手作業でやっていくのは大変なので、ほぼ自動化できるツールが開発されています。ありがたい!
pinact作者による解説記事は、ここで私が説明したよりも詳細に解説されています。
ghalint
: GITHUB_TOKEN の権限が広く設定されていないか確認する
GitHub Actionsでは、 push
や pull_request
などで何らかのイベントを受けた結果として、その内容をコメントしたりステータスを変更するという操作をよく行います。
そういった操作は secrets.GITHUB_TOKEN
をactionに提供するなどして実現すると思います。
GITHUB_TOKEN
によって許可される操作は、リポジトリやorgの設定によって変化します。詳しくは:
https://docs.github.com/en/actions/security-for-github-actions/security-guides/automatic-token-authentication#permissions-for-the-github_token
さて、上記リンクを確認して頂きたいのですが、permissiveな設定(リポジトリ設定の Actions > General > Workflow permissions の "Read and write permissions" 設定 )だとかなり広範囲にwrite権限が付与されています。おなじトークンで広範囲を読み書きできるのはややリスクがあります。
ということで、同じ設定の "Read repository contents and packages permissions" を設定すると、デフォルトでは書き込み権限を付与されなくなります。しかしそれでも広範囲のread権限は存在することになりますし、そもそも実運用としてwrite権限が完全にない状態は現実的ではないです。
GITHUB_TOKEN
の推奨される設定方法として、workflow yamlで permissions
設定を行うことで、当該workflowにおいて指定したスコープに対して指定した権限のみが与えられた GITHUB_TOKEN
が生成されるようになります。
例えば、 contents
は read
権限のみ、 pull-requests
は write権限を付与し、それ以外の権限付与はしないというような運用が可能になります。
それはそれとして、GitHub Actionsでは permissions
の定義がされていないときは先ほどの Workflow permissions の設定を使うことになるので、そもそも permissions
の定義をしていないことが問題になるというわけです。
以下のツールは、permissionが付与されていないworkflowを検知することが出来ます。残念ながら必要なpermissionを自動的に提案してくれたりはしませんので、そこは結構な手間がかかってしまいます。
他にも timeout-minutes
の指定漏れなども指摘してくれます。モバイルアプリのビルドではデッドロックも稀に起こるので、タイムアウト設定は入れておいて損はないでしょう。
actionlint
: シェルスクリプトの実装不備がないかチェックする
GitHub Actionsには様々なactionが提供されています。
しかし、これらでカバーできない処理もあるため、シェルスクリプトを動かせる run
を使うこともよくあります1。
ただし、雑にシェルスクリプトを実装するとスクリプトインジェクションの危険があります。特にコミットメッセージやPRタイトルなど自由入力値を取り得るものはインジェクションを引き起こしやすいです。
これを防ぐためのツールがあります。shellcheck
などで静的解析を行ってくれたり色々チェックしてくれるのでなかなか高機能です。
どのようなことを見てくれるのかはこちらのドキュメントを確認して下さい。
workflowをチェックするworkflowをつくった
今回紹介したツールは、それぞれローカルで動かせるようになっていますが、CI環境で動作させてLintツールとして使用することも出来ます。
というわけで、私のチームではworkflowが変更されたときにチェックをかけるようなworkflowを実行させるようにして、常にガードを高くした状態を維持できるようにしています。
そして、ちょっと早いクリスマスプレゼントです!実際に作成したworkflowを公開します。
# Copyright (c) 2024 Techouse, Inc. # Released under the MIT license # https://opensource.org/licenses/mit-license.php name: Lint GitHub Actions on: pull_request: paths: - '.github/actions/**/*.yml' - '.github/workflows/**/*.yml' jobs: lint: runs-on: ubuntu-latest timeout-minutes: 10 permissions: contents: read # actions/checkout steps: - name: Checkout uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: sparse-checkout: | .github - name: Install actionlint uses: jaxxstorm/action-install-gh-release@25d5e2dd555cd74f1fab9ac1e6ea117acde2c0c4 # v1.12.0 with: repo: rhysd/actionlint cache: enable # pinact-action doesn't installs pinact itself - name: Install pinact uses: jaxxstorm/action-install-gh-release@25d5e2dd555cd74f1fab9ac1e6ea117acde2c0c4 # v1.12.0 with: repo: suzuki-shunsuke/pinact cache: enable - name: Install ghalint id: install-ghalint uses: jaxxstorm/action-install-gh-release@25d5e2dd555cd74f1fab9ac1e6ea117acde2c0c4 # v1.12.0 with: repo: suzuki-shunsuke/ghalint cache: enable - name: Run actionlint run: | # 以下URLのファイルを .github/ ディレクトリに配置することで、 # actionlint の結果を GitHub のコード行にインラインで表示できるようになります # https://github.com/rhysd/actionlint/blob/main/.github/actionlint-matcher.json # echo "::add-matcher::.github/actionlint-matcher.json" actionlint -color - name: Run pinact uses: suzuki-shunsuke/pinact-action@a60b07ee63e41654915780a3297ff9f5f6b6db63 # v0.1.0 with: skip_push: true - name: Run ghalint run: ghalint run env: GHALINT_LOG_COLOR: always
まとめ
- Techouseはセキュリティを重視しています
- 今回はGitHub Actions経由でセキュリティ事故が起きづらいように守りを固めた
- 「門前の小僧習わぬ経を読む」 2
明日のTechouse Advent Calendar 2024は harashunnn さんによる 「こんにちは。わたしはDocker build --secrets。あなたのクレデンシャルを守ります。」 です。
Techouseでは、社会課題の解決に一緒に取り組むエンジニアを募集しております。 ご応募お待ちしております。
- 実は bash 以外も使える。pythonやpwsh(PowerShell Core)も使える。詳しくは https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsshell↩
- ちなみにこのことわざは、ChatGPTに「例えば、セキュリティを重視している会社に転職した結果、自分のコードなどもセキュリティを意識するようになった。こういうことを表すことわざや熟語はありますか」と聞いたら教えてくれました。勉強になるなぁ。↩