メドピア開発者ブログ

集合知により医療を再発明しようと邁進しているヘルステックカンパニーのエンジニアブログです。読者に有用な情報発信ができるよう心がけたいので応援のほどよろしくお願いします。

GitHub Appsの作成とOrgへの所有権の委譲手順

CTO室SREの @sinsoku です。

ドキュメントをテックブログとして書いておくと一石二鳥なことに気づいたので、ここに書きます。

GitHub Appsが必要なユースケース

GitHub Actions で使用できる secrets.GITHUB_TOKEN には以下の制限があります。

  • secrets.GITHUB_TOKEN を使用した操作では新しいワークフローが実行されません
    • Actions で作成したプルリクで Actions のテストが動かない
  • 他リポジトリのコードを参照できません
    • プライベートリポジトリのgemやnpmの取得ができない

この問題を回避するため、GitHub Appsで一時的なアクセストークンを生成して使用します。

なぜ Personal Access Token(PAT)を使うべきではないか?

PATを使用することは以下の理由から推奨していません。

  • PATを作成した人が退職した場合、引き継ぎを忘れると動かなくなる
  • PATの有効期限の管理が煩雑になる
    • 無期限にするのはセキュリティ上好ましくない
  • マシンユーザーの人数分の費用が増加する
    • アカウントを使い回すのはセキュリティ上好ましくない*1

GitHub Apps の作成手順

公式ドキュメント

GitHub Docs に手順が記載されているので、まだ読んだことない方は一度目を通しておいてください。

作成手順

  1. Register new GitHub App で各項目を埋めてください
    • 項目
      GitHub App name 適当な名前
      (弊社だと mpg-xxx-bot の命名規則)
      Homepage URL 適当なURL
      (弊社だと https://github.com/medpeer-dev
      Webhook 不要なので Active のチェックを外す
      Repository permissions Permissions required for GitHub Apps を参照して必要な権限を選択してください。
      例: コードを参照する場合はContents、プルリクを作る場合は Pull requests など
  2. GitHub Apps 作成したら、秘密鍵を生成する
  3. 使用したいリポジトリの Secrets に以下を設定する
    • GitHub AppsのID
    • 生成した秘密鍵

Orgに所有権を委譲する

作成したGitHub Appsの所有権をOrgに委譲し、必要なリポジトリで使えるようにOrgにインストールする必要があります。

公式ドキュメント

GitHub Docs に所有権の委譲の手順があるため、参照してください。

Ownerへの依頼手順

弊社ではSREメンバーがOwner権限を持っているため、以下のような運用にしています。

  1. 作成したGitHub Appsの所有権をOrgに委譲する
  2. Backlogで以下を記載したチケットを作成する*2
    • GitHub Appsの用途
    • GitHub Appsをアクセスするリポジトリ一覧
    • GitHub Appsの管理者アカウント

SREメンバーは 用途権限 に問題がなければ、所有権の委譲リクエストを承認します。 承認した後、以下の作業をします。

  • GitHub Apps に管理者を追加する
  • GitHub Apps をOrgにインストールする
    • Only select repositories で指定のリポジトリだけ許可する

アクセストークンの使い方

GitHub Actionsでの利用

tibdex/github-app-token を使用します。

README の引用ですが、以下のように簡単に使用できます。

- name: Generate token
  id: generate_token
  uses: tibdex/github-app-token@v1
  with:
    app_id: ${{ secrets.APP_ID }}
    private_key: ${{ secrets.PRIVATE_KEY }}
    # Optional (defaults to ID of the repository's installation).
    # installation_id: 1337
    # Optional (defaults to the current repository).
    # repository: "owner/repo"
- name: Use token
  env:
    TOKEN: ${{ steps.generate_token.outputs.token }}
  run: |
    echo "The generated token is masked: ${TOKEN}"

CircleCIでの利用

CircleCI では簡単に扱う方法がないため、以下のスクリプトを使用します。

#!/usr/bin/env ruby
# frozen_string_literal: true

# GitHub Appsで使うアクセストークンを生成し、標準出力に表示するスクリプト。

# デフォルトgemではないjwtを入れる
require 'bundler/inline'
gemfile do
  source 'https://rubygems.org'
  gem 'jwt'
end

require 'openssl'
require 'net/http'
require 'json'
require 'jwt'

# 環境変数からAPP_ID, PRIVATE_KEYを読み込む。
gh_app_id = ENV['GITHUB_APPS_ID']
# Circleでは複数行の値を環境変数に使えないため、Base64でエンコードして設定
gh_private_pem_base64 = ENV['GITHUB_APPS_KEY_BASE64']
gh_private_pem = Base64.decode64(gh_private_pem_base64)

payload = {
  iat: Time.now.to_i - 60,
  exp: Time.now.to_i + (10 * 60),
  iss: gh_app_id
}
private_key = OpenSSL::PKey::RSA.new(gh_private_pem)
jwt = JWT.encode(payload, private_key, "RS256")

# httpリクエストを投げるのに必要な変数を用意
headers = { Authorization: "Bearer #{jwt}", Accept: "application/vnd.github.v3+json" }
http = Net::HTTP.new('api.github.com', 443).tap { |h| h.use_ssl = true }

# GitHubのAPIでアクセストークンを生成する
#
# - https://docs.github.com/en/rest/apps/apps#get-a-repository-installation-for-the-authenticated-app
# - https://docs.github.com/en/rest/apps/apps#create-an-installation-access-token-for-an-app
installation = http.get("/repos/medpeer-dev/medpeer/installation", headers).then { |r| JSON.parse(r.body) }
access_token = http.post("/app/installations/#{installation["id"]}/access_tokens", {}.to_json, headers).then { |r| JSON.parse(r.body) }

# アクセストークンを出力
puts access_token["token"]

スクリプトの出力を環境変数に設定することで、プライベートリポジトリにアクセスできます。

- run:
    name: Set GitHub access token
    command: |
      export GITHUB_ACCESS_TOKEN="`./bin/gh_apps_token`"
      export BUNDLE_GITHUB__COM="x-access-token:${GITHUB_ACCESS_TOKEN}"

参考ページ


メドピアでは一緒に働く仲間を募集しています。 ご応募をお待ちしております!

■募集ポジションはこちら

https://medpeer.co.jp/recruit/entry/

■開発環境はこちら

https://medpeer.co.jp/recruit/workplace/development.html

*1:全てのプロジェクトのリポジトリへのアクセス権限を持つことになってしまうため

*2:社内の方はSREプロジェクトの「依頼: GitHub Appsの委譲」のテンプレを参照してください。