🔑

GitHubの複数リポジトリでSecretsやVariablesを共有したい

に公開

CI/CD の結果をアップロードしたり通知したりするために Slack の Webhook URL や S3 のアクセスキーなどをよく設定したくなります.

しかし, いくつものリポジトリを所持しているとこれら値の管理が面倒になってきます.

GitHub Organization の有料プランには Organization secrets & variables があり, この機能を使って複数リポジトリで横断的な secrets や variables を設定することでこの面倒な問題を解決できます.

これは正攻法ですがお金がかかってしまうため, なるべく出費を抑えたい個人開発では避けたいソリューションです.

Secrets や Variables を sync する GitHub Actions を作成することでそれなりに満足できる運用が構成できたので紹介します.

GitHub Actions

次のようなワークフローを作成します:

name: Sync Secrets and Variables

on:
  workflow_dispatch:

defaults:
  run:
    shell: bash

jobs:
  sync_secrets:
    runs-on: ubuntu-latest
    timeout-minutes: 1
    strategy:
      fail-fast: false
      matrix:
        include:
          - repo: repo-aaa
            secrets:
              - "R2_ACCOUNT_ID"
              - "R2_BUCKET_NAME"
              - "R2_ACCESS_KEY_ID"
              - "R2_SECRET_ACCESS_KEY"
              - "SLACK_WEBHOOK"
          - repo: repo-bbb
            secrets:
              - "R2_ACCOUNT_ID"
              - "R2_BUCKET_NAME"
              - "R2_ACCESS_KEY_ID"
              - "R2_SECRET_ACCESS_KEY"
              - "SLACK_WEBHOOK"
    steps:
      - name: Set secrets
        run: |
          for secret_name in ${{ join(matrix.secrets, ' ') }}; do
            secret_value="${!secret_name}"
            echo "Setting $secret_name for ${{ matrix.repo }}"
            echo "$secret_value" | gh secret set "$secret_name" \
              --repo="${{ github.repository_owner }}/${{ matrix.repo }}"
          done
        env:
          GH_TOKEN: ${{ secrets.TOKEN_RW_SECRETS_VARIABLES }} # needed to use gh cli to set secrets on other repos
          R2_ACCOUNT_ID: ${{ secrets.R2_ACCOUNT_ID }}
          R2_BUCKET_NAME: ${{ secrets.R2_BUCKET_NAME }}
          R2_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }}
          R2_SECRET_ACCESS_KEY: ${{ secrets.R2_SECRET_ACCESS_KEY }}
          SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}

  sync_vars:
    runs-on: ubuntu-latest
    timeout-minutes: 1
    strategy:
      fail-fast: false
      matrix:
        include:
          - repo: repo-aaa
            vars:
              - "R2_PUBLIC_DEV_URL"
          - repo: repo-bbb
            vars:
              - "R2_PUBLIC_DEV_URL"
    steps:
      - name: Set vars
        run: |
          for var_name in ${{ join(matrix.vars, ' ') }}; do
            var_value="${!var_name}"
            echo "Setting $var_name for ${{ matrix.repo }}"
            gh variable set "$var_name" \
              --repo="${{ github.repository_owner }}/${{ matrix.repo }}" \
              --body="$var_value"
          done
        env:
          GH_TOKEN: ${{ secrets.TOKEN_RW_SECRETS_VARIABLES }} # needed to use gh cli to set vars on other repos
          R2_PUBLIC_DEV_URL: ${{ vars.R2_PUBLIC_DEV_URL }}

補足と解説

  • なんてことはないワークフローです
  • このワークフローを実行するリポジトリの Secrets & Variables を他のリポジトリに送りつけます
  • gh secret setgh variable set を使うことで, 他リポジトリへの Secrets & Variables 設置を実現しています
  • そのためには適切な権限を設定した Personal Access Token が必要です. TOKEN_RW_SECRETS_VARIABLES がそれです. Read and Write access to actions variables and secrets をパーミッションとして与えた PAT を作成してください
  • envmatrix.include の部分で細かなマッピングを指定できるようにしています. 各々の目的に合わせてカスタマイズしてください
    • リポジトリや変数の個数が増えてくると記述が冗長になってきます. もっと工夫できる箇所ですが, 今の方法も明示的でわかりやすいので気に入ってます
    • (※ 2025-11-03 追記) 数カ月前にアンカー記法がサポートされた ようなので, これを使えばより簡潔に記述できます. 試してみたところうまく動きました. ただし, vscode の拡張機能で構文エラーと誤検知してしまいますが...

運用方法

初期設定

  • 上述の通り PAT を作成して設定してください

通常運用

  1. 共有したいリポジトリや Secrets & Variables が出てきたら, このワークフローを編集する
  2. コミット & プッシュ
  3. プッシュしたブランチでこのワークフローを実行する
  4. 共有先のリポジトリで結果を確かめる. Repository secrets のリストには Last updated の欄があるので, そこを見るとよい

※ Secrets の共有はセキュリティリスクがあるため, どの値を共有するのか, どのリポジトリに送信するのかは慎重に検討してください.

Discussion