GitHub Appインストールアクセストークンを使ってGitHub Actionsを実行する

Today I Learned

この記事では、GitHub Personal Access Token(PAT)の代わりに、GitHub Appインストールアクセストークン(以降、GitHub Appトークン)を使ってGitHub Actionsを実行する方法を説明する。

Info

2023年10月8日追記
この記事ではサードパーティ製のtibdex/github-app-tokenというactionを利用する方法を紹介している。
GitHub公式が作ったactionsの使い方は、次の記事を参照のこと。
公式アクションでインストールアクセストークンを発行しほかのリポジトリを操作する

PAT の問題点

GitHub ActionsでGitHubへの認証が必要な操作をするとき、GITHUB_TOKENでは権限不足に陥ることがある。
たとえば、GitHub Actions内でプライベートリポジトリをcloneしたり、コミットを作ってリポジトリにpushしたりするケースである。 GITHUB_TOKENで権限が足りない場合にはBotユーザーに紐づくPATを使うが、PATには次の問題点がある。

  • PATを発行するためのBotユーザーが必要
  • PATの有効期限を過ぎると動かなくなる
    • PATを再発行する度にSecretsの設定変更が必要

GitHub App トークンとは

これらのPATの問題点を解決する手段として、GitHub Appを使って発行したGitHub Appトークンを使う方法がある。
GitHub Appトークンは、PATと同様に権限を細かく設定でき、トークンの有効期限が短いため、万が一漏えいしても影響が小さくて済む。
また、ユーザーアカウントに依存しないため、上記に挙げたPATの問題点を解決できるメリットがある。

GitHub App のセットアップ

STEP1:GitHub App を作成する

  1. 次のURLにアクセスする。

  2. アプリの設定内容を入力する。

    • 「Register new GitHub App」セクション
      • GitHub App name - アプリの名前
        すべてのGitHubユーザーや組織でユニークにする必要がある。
        自分のみがインストールできるアプリにしていても、「https://github.com/apps/<APP_SLUG>」にアクセスするとアプリ名は全ユーザーに表示される。
      • Homepage URL - アプリのURL
        何でも良い。
    • 「Webhook」セクション
      • Active - 選択を外す
    • 「Permissions」セクション - トークンに付与する権限
      権限はアプリ作成後に変更できる。
      今回はプライベートリポジトリのクローンでGitHub Appトークンを使用するため、以下の権限を付与する。
      • Contents > Read-only
      • Metadata > Read-only
    • 「Subscribe to events」セクション
      • Where can this GitHub App be installed - アプリをインストールできるアカウント
        「Only on this account」を設定すると、自分のみを対象にできる。
  3. [Create GitHub App]をクリックすると、アプリが作成される。

  4. 「About」セクションの「App ID」をメモしておく。 GitHub Appトークンを取得する際のサードパーティアクションで使用する。

  5. 「Private keys」セクションで、[Generate a private key]をクリックする。 秘密鍵ファイルがダウンロードされる。

後から「Permissions」を変更した場合

https://github.com/settings/installations/<APP_ID> の画面でGitHub Appを再承認する必要がある。
スクリーンショット:permission の承認を促すメッセージが表示されている

STEP2:GitHub App をインストールする

GitHub Appを利用するリポジトリに、GitHub Appをインストールする。

  1. インストールするGitHub Appの左メニューから[Install App]をクリックする。
    または、https://github.com/settings/apps/<APP_SLUG>/installationsにアクセスする。

  2. [Install App]をクリックする。

  3. インストールするリポジトリを選択する。 ユーザー(または組織)の全リポジトリ、または特定のリポジトリを選択できる。

    • All repositories
    • Only select repositories

今回は、GitHub Actionsでプライベートリポジトリをクローンする例を示すため、次の2つのリポジトリにインストールする。

  • GitHub Actionsを実行するリポジトリ
  • クローンするプライベートリポジトリ

STEP3:リポジトリに GitHub App ID と秘密鍵を登録する

GitHub Actionsを実行するリポジトリのシークレットに、GitHub App IDと秘密鍵を登録する。

  1. リポジトリの[Settings]をクリックする。

  2. 「Secrets and variables」の[Actions]をクリックする。

  3. [New Repository secret]をクリックし、次の2つのSecretを登録する。

    • APP_ID:STEP1でメモしたGitHub AppのApp ID
    • PRIVATE_KEY:秘密鍵ファイルの内容
      「-----BEGIN RSA PRIVATE KEY-----」から「-----END RSA PRIVATE KEY-----」まで
  4. 秘密鍵ファイルはこの先の手順で不要となるので、パソコン内から削除する。

GitHub Actions で GitHub App トークンを生成する

GitHub App トークンを生成する方法

GitHub Appトークンの生成方法は、以下のドキュメントで紹介されている。

この記事では詳細を省略するが、大まかな流れは次の通り。

  1. アプリのJSON Webトークン (JWT) を生成する。
  2. インストールのIDを取得する。
  3. JSON WebトークンとインストールIDを使って、GitHub Appトークンを生成する。

GitHub ActionsでGitHub Appトークンを利用するには、上記の処理をActions上で実施する必要がある。
Actions上で実施するには次の2つの方法がある。

  • actionを利用する
  • GitHub Appトークンを取得する処理を自前で実装する

この記事では、上記の処理をActionsで提供している、サードパーティアクションの「tibdex/github-app-token」を使用する。
改ざんの恐れのあるサードパーティアクションを利用することは、セキュリティ上好ましくないが、Commit SHAでバージョンを固定して影響を最小限にする。
参照:Using third-party actions

tibdex/github-app-token でGitHub App トークンを生成する

「tibdex/github-app-token」を使ってGitHub Appトークンを生成するactionは、次のように利用する。
バージョンは、v1.8.0のCommit SHAを指定して固定する。
生成したGitHub Appトークンを、ほかのStepへ渡すためにStepのidを指定しておく必要がある。

- name: Generate GitHub App Token
  id: app-token
  uses: tibdex/github-app-token@b62528385c34dbc9f38e5f4225ac829252d1ea92 # v1.8.0
  with:
    app_id: ${{ secrets.APP_ID }}
    private_key: ${{ secrets.PRIVATE_KEY }}

トークンを利用する側は、${{ steps.app-token.outputs.token }}でGitHub Appトークンを参照する。

- name: Use token
  env:
    GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
  run: |
    # 環境変数の GITHUB_TOKEN に GitHub App トークンが設定されている
    echo $GITHUB_TOKEN # 実際には Actions のログに出力されない

GitHub App トークンを利用してプライベートリポジトリをクローンするワークフロー

Pull Requestを作成したときに、プライベートリポジトリをクローンするワークフローを作成する。

.github/workflows/clone-private-repository.yml
name: Clone a private repository

on: pull_request

jobs:
  clone:
    runs-on: ubuntu-latest
    timeout-minutes: 5
    steps:
      - name: Generate GitHub App Token
        id: app-token
        uses: tibdex/github-app-token@b62528385c34dbc9f38e5f4225ac829252d1ea92 # v1.8.0
        with:
          app_id: ${{ secrets.APP_ID }}
          private_key: ${{ secrets.PRIVATE_KEY }}

      - name: Clone private repository
        env:
          token: ${{ steps.app-token.outputs.token }}
        run: |
          # クローンするプライベートリポジトリ名に応じて <OWNER> と <REPO_NAME> を書き換える
          gh repo clone https://github.com/<OWNER>/<REPO_NAME>
          ls -la

動作確認

Pull Requestを作成してみる。 GitHub Actionsのログで、プライベートリポジトリをクローンできていることを確認する。

スクリーンショット:GitHub Actions のログにクローンしたリポジトリのディレクトリが表示されている