GitHub Actionsにはpermissionsというフィールドがあり、それぞれのWorkflow/Jobでのsecrets.GITHUB_TOKENの権限を設定できるようになっています。 secrets.GITHUB_TOKENはGitHub Actionsの実行ごとに発行されるGitHubのTokenで、多くのGitHub Actionsはこのトークンを使ってリポジトリをgit cloneしたり、Issueにコメントを書いたりしています。

このpermissionsをちゃんと設定することでサプライチェーン攻撃などの影響を軽減することができます。 たとえば、次のpermissionsは、このWorkflowにおける secrets.GITHUB_TOKEN は リポジトリの読み取りを許可するという意味になります。

name: test
on: [ push, pull_request ]
permissions:
  contents: read
jobs:
  test:
    name: "Test on Node.js"
    runs-on: ubuntu-18.04

    steps:
      - name: checkout
        uses: actions/checkout@v2
      - name: setup Node.js
        uses: actions/setup-node@v2
        with:
          node-version: 14
      - name: Install
        run: yarn install
      - name: Test
        run: yarn test

GitHub Actionsのデフォルトパーミッションはwrite-allです。 つまり、リポジトリの読み書き、IssueやPRの読み書きなど全部の権限がデフォルトでついています。 そのため、uses: actions/checkout@v2 のようにread onlyでよいGitHub Actionsも、実際にはリポジトリやIssueへの書き込みできる権限も持ってしまっています。

このパーミッションのデフォルト値は、リポジトリごと または Organization単位で、"Read repository contents permission" へと変更もできます。 "Read repository contents permission" は次のパーミッションと同じ意味なので、リポジトリのコンテンツを読み取りのみできるというパーミッションです。

permissions:
  contents: read

contents: readがあれば、リポジトリをcloneしてテストをするには十分です。 この場合は、それ以外の権限をyamlファイルにpermissionsとして付け足していくという形になります。

つまり、GitHub ActionsのWorkflowのパーミッションを必要最小限にするには次のステップが必要です。

  • Workflow(yamlファイル)ごとにpermissionsを設定する
  • リポジトリ or Organizationのデフォルトパーミッションを "Read repository contents permission" にする

しかし、必要なpermissionsをREADMEに書いてるActionはとても少ないので、Workflowファイルにpermissionsを定義するのはかなり面倒です。 そのため、permissionsの設定を自動的に追加ツールを書きました。

@pkgdeps/update-github-actions-permissions

@pkgdeps/update-github-actions-permissionsは、GitHub Actionsのyamlファイルに自動的にpermissionsを付け足してくれます。

yamlファイルで使っているActionから必要なpermissionsを推定して設定してくれます。

Requirements: Node.js 14+

次のようにnpxコマンドなどで、permissionsを更新したいyamlファイルのパスを指定します。

npx @pkgdeps/update-github-actions-permissions ".github/workflows/*.{yaml,yml}"

実行すると自動的にpermissionsフィールドを追加します。

update-github-actions-permissions result

40種類以上のactionspermissionsの定義リストから、自動的に必要なpermissionsを合成して設定するという形になっています。

定義リストにないActionを見つけた場合は、write-allを設定します。 もし、未定義のActionを見つけた場合は、Pull Requestを送ってください。

全てのWorkflowファイルのpermissionsが設定できたら、リポジトリのデフォルトパーミッションを"Read repository contents permission"にできます。

  • Workflow(yamlファイル)ごとにpermissionsを設定する → @pkgdeps/update-github-actions-permissions
  • リポジトリ or Organizationのデフォルトパーミッションを "Read repository contents permission" にする → 手動で設定

将来的には、GitHub ActionsもGitHub Appのように、Actionを提供する側で必要なpermissionsのリストを定義するようになるんじゃないかなと思います。(今はソースコードを読んだりしないと必要なpermissionsがわからない状態になっている)

contents: readのパーミッションでも問題あるケースは、リポジトリに機密情報がコミットされている状態だと思います。 そのようなケースはシークレットスキャンニングsecretlintなどを使って、そもそも機密情報をコミットしない状態を目指すのが良さそうです。