🔓

GitHub Actions から別プライベートリポジトリにアクセス

2023/02/20に公開

はじめに

Go の独自パッケージ (ライブラリ) を Private Repo で管理していたのですが、 CI/CD (GitHub Actions) から利用する際の認証をどうするか検討しているといろいろ手段があったので、備忘録の意味も込めてまとめます。

下記の前提を踏まえると、今回ベストなのは 手段1 ですので、結論だけ読みたい方はそちらをどうぞ。

また、最後に まとめ (比較と解説) を用意しており、本記事を用意するに至った理由はここに詰まっています。

前提・定義

  • きっかけで Go について書きましたが、本ドキュメントの目的はタイトルの通りであるため、 Go 固有の話には言及しません。 GOPRIVATE などお忘れなく。
  • 個人ではなく組織での開発であり、登場する Repository はすべて同じ Organization 内である前提です。 (状況が多少異なっても、部分的に参考にはなると思います。)
  • GitHub Actions は理解している前提です。
  • 登場する Repo を下記の通り定義します。
    また、どちらも同じ Org 内にあり、どちらも Private Repo であります。
    • Lib Repo: ライブラリとなる参照される側の Repo 。自作の Go Package などを想定。
    • App Repo: アプリケーションなど、ライブラリを参照する側・CIを実行する側の Repo。

手段1. GitHub App - A

GitHub App 作成

https://github.com/organizations/{org}/settings/apps/new
下記の内容を参考に、 Org Setting ページから、 GitHub App を作成してください。
下記に無いものは適宜判断してください。

項目 内容
Homepage URL 公開するわけではないので https://example.com など適当に
Webhook Active 使わないので false に
Repository permissions Contents のみ Read-only に
Where ... installed? 社内利用のみを想定しているので Only on this account

App Install

1 で作成した GitHub App を自分の Org にインストールします。
この時 Only select repositories を指定する場合、 Lib Repo [1]のみ選択すれば OK です。

Install 画面 Repo 選択画面

Actions secrets に登録

作成した App の Settings > General から、下記2つの値を取得します。
また、下記の「Secret name」の名称で Actions secrets に設定した体で進めます。

Secret name 取得方法
App ID APP_ID 上部に記載あり
Private Key PRIVATE_KEY 生成して得られた .pem ファイルの中身を貼り付ける

また、Actions secrets に設定する際には、 Org 側か Repo 側かの選択肢があります。
今回の事例でいうと、わざわざ Repo を切り出してライブラリ化しているので、Org 側の secrets に設定し、Org 内全体で使い回せたほうがいいだろうと思います。

GitHub Actions で認証

App Repo [1:3]側の GitHub Actions 上で、 Lib Repo [1:4]を参照したいので、今回作成した GitHub App を経由して認証します。
下記を参考に steps 内に追記してください。

.github/workflows/example.yml
- uses: getsentry/action-github-app-token@v2.0.0
  id: get-token
  with: 
    app_id: ${{ secrets.APP_ID }}
    private_key: ${{ secrets.PRIVATE_KEY }}
    scope: ${{ github.repository_owner }}

- run: git config --global url."https://x-access-token:${{ steps.get-token.outputs.token }}@github.com/".insteadOf "https://github.com/"

手段2. GitHub App - B

基本的に 手段1. GitHub App - A と同じですが、なぜか認証に tibdex/github-app-token を使う案内をしているブログ記事[2]が多数でした。(実際同様のリポジトリの中でも Star は一番多い?)

この Action を使う場合のやりかたも一応書いておきます。
基本的に 手段1 と同様です。 手段1 との差分のみ記載します。

App Install (App Repo も選択)

Lib Repo [1:5]のみでなく、 App Repo [1:6]も含めて権限を与えるようにします。

GitHub Actions で認証

手段1とは異なり下記のように記載します。

.github/workflows/example.yml
- uses: tibdex/github-app-token@v1.7.0
  id: get-token
  with: 
    app_id: ${{ secrets.APP_ID }}
    private_key: ${{ secrets.PRIVATE_KEY }}

- run: git config --global url."https://x-access-token:${{ steps.get-token.outputs.token }}@github.com/".insteadOf "https://github.com/"

手段3. GitHub App - C

手段2. GitHub App - B の改善版です。同じく 手段1 との差分のみ記載します。

App Install

こちらは Lib Repo のみの選択で問題ありません。(App Repo 不要)

Actions secrets に登録 (Installation ID も)

手段1 の App IDPrivate Key は同様に登録しますが、追加で Installation ID というものも登録します。

Installation ID 取得方法

GitHub App を Install した Org の Setting > GitHub Apps > Installed GitHub Apps > 該当 App の "Configure" をクリック > アクセスされた URL の末尾が Installation ID
https://github.com/organizations/{org}/settings/installations/{id}

GitHub Actions で認証

Installation ID の指定を追記します。

.github/workflows/example.yml
- uses: tibdex/github-app-token@v1.7.0
  id: get-token
  with: 
    app_id: ${{ secrets.APP_ID }}
    private_key: ${{ secrets.PRIVATE_KEY }}
    installation_id: ${{ secrets.INSTALLATION_ID }}

- run: git config --global url."https://x-access-token:${{ steps.get-token.outputs.token }}@github.com/".insteadOf "https://github.com/"

手段4. Personal access token

ここでは Fine-grained personal accesss token [3]を利用します。
また、 Org / Personal の Settings を行き来するので、混乱しないように注意してください。

Org Settings で token 作成許可

https://github.com/organizations/{org}/settings/personal-access-tokens
Lib Repo [1:7]が置いてある Org の設定ページにて、token 自体を作成できるように設定しておきます。

Personal Settings で token 生成

https://github.com/settings/personal-access-tokens/new

項目 内容
Resource owner Lib Repo が置いてある Org を選択
Repository access 指定する場合は Lib Repo のみ選択 ( App Repo は含めなくて良い )
Repository permissions Contents のみ Read-only を付与

Org Settings で Actions secrets に登録

2 で生成した token を、今回は TOKEN という名称で登録します。
(登録する場所は、 App Repo [1:8]が参照できる場所なので、その Repo の Settings か、その Repo が置いてある Org の Settings です。)

GitHub Actions で認証

App Repo [1:9]側の GitHub Actions の yaml 内に、下記を追記してください。

.github/workflows/example.yml
- run: git config --global url."https://x-access-token:${{ secrets.TOKEN }}@github.com/".insteadOf "https://github.com/"

まとめ (比較と解説)

手段1.
GitHub App - A
手段2.
GitHub App - B
手段3.
GitHub App - C
手段4.
Personal access token
1. 有効期限
2. 組織管理
3. 一方向アクセス
4. Installation ID 管理 -

今回の事例では 手段1 がベストかと思います。
また、実際には 手段 4 → 2 → 3 → 1 の順序で調査しました。(冒頭にベストな手段を記載しようと思い、順序が前後してしまいました。)

1. 有効期限

今回使用している Fine-grained personal access token は、最長で 90 days の Expiration が設定可能[4]です。
有効期限が来るたびに token の差し替えが発生するため、手段4 はオペレーション上のデメリットと捉えられます。[5]

2. 組織管理

今回の事例では、個人に紐付いた内容ではなく、組織として管理されるべきものです。
そのため、 GitHub Apps を用いた運用が推奨されます。

3. 一方向アクセス

上述の通り、認証に tibdex/github-app-token を使う案内をしているブログ記事が多数[2:1]でしたが、これには最大のデメリットがあります。
Token を取得する際に必要な Installation ID を、リポジトリに紐づけて取得する手段[6]しか提供されていないため、 GitHub App インストール時に App Repo [1:10]にも権限を与えなけばなりません。

今回のケースでは App Repo -> Lib Repo [1:11]の一方向の参照ができればよいのに、両方ともに権限を与えると、 Lib Repo [1:12]から App Repo [1:13]を参照できてしまう状況となり、必要のない双方向アクセスが可能となってしまいます。

4. Installation ID 管理

Token を取得する際に必要な Installation ID を、リポジトリに紐づけて取得する手段しか提供されていない

上述の 3. 一方向アクセス でこのように伝えましたが、厳密には違います。
実際には、Installation ID を直接指定する手段も提供されています。[7]
これにより、不要な双方向アクセスは回避できますが、一方で Installation ID の管理が必要となります。

これらを踏まえ、下記2点から、デメリットと捉えることができます。

  • ID を Actions secrets などの変数を追加で管理しなければならない
  • GitHub App をアンインストール・再インストールすると ID が変わってしまうことへの考慮が必要

補足. getsentry/action-github-app-token について

手段1 で使っている getsentry/action-github-app-token Action では、 scope というパラメータが使えて、これには Owner (≒ Org) を指定できる。[8]
これにより、tibdex/github-app-token のデメリット (手段2,3のデメリット) が解消される。

(また、 Star 数はまけるが、有名な Sentry が公開しているリポジトリという点でも少し安心感[9]があるかも、、、?)

脚注
  1. App Repo と Lib Repo は定義をご参照ください ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎

  2. 例えば
    https://zenn.dev/farstep/articles/32751d92dd1452
    https://dev.classmethod.jp/articles/getting-an-access-token-with-only-the-necessary-permissions-on-github-appsgithub-actions/
    https://studist.tech/migration-to-github-apps-c2752d506d9a ↩︎ ↩︎

  3. 記載時 (23/02/20) では Beta です。
    また、 Classic (従来のもの) でもある程度同様だと思いますが、必要以上に権限を渡しているなどの差分が発生する可能性があります。 ↩︎

  4. Classic な Personal access token であれば、無期限有効な token が生成可能ですが、一方で権限が不必要に広くなってしまうなどのデメリットも発生します。 ↩︎

  5. GitHub 側の意図としては、token の存在自体の失念などによりセキュリティリスクが高まることを防ぐため、有効期限を短くし、継続的に必要なのであれば定期的に管理させることで適切な運用を促すということが推測されるため、ポジティブに捉えることもできます。ただし、本ドキュメント上では差し替えなどの管理の手間を優先して とします。 ↩︎

  6. ソースコードでは octokit の getRepoInstallation() が使われている。ここで getOrgInstallation() も使われるようなコードであればよかったが。 ↩︎

  7. ソースコードの該当箇所はこちら ↩︎

  8. Action 側のソースコード該当箇所はこちら。また、関連する GitHub の REST API はこちら↩︎

  9. もちろん過信は禁物であるし、どちらもオープンソースなのだからちゃんとソースを読めば良い。 ↩︎

Discussion