🦌

GitHub Actions で複数のプライベートリポジトリにSSHアクセスする方法

に公開

発生した現象

エラー内容

composer require で複数のプライベートリポジトリ(VCS)からパッケージをインストールする際、GitHub Actions で以下のエラーが発生した。

Failed to download your-org/private-package from dist: HTTP/2 404
Now trying to download from source
Error: Failed to execute git clone --mirror -- git@github.com:your-org/private-package.git
fatal: Authentication failed for 'https://github.com/your-org/private-package.git/'

問題の原因

  1. プライベートリポジトリのzipballはGitHub API経由でアクセスできないため、distダウンロードが失敗した(404エラー)
  2. SSH認証の問題により、sourceダウンロードも失敗した

SSHデプロイキーの制限

複数のデプロイキーを webfactory/ssh-agent で登録しても、片方のリポジトリにしかアクセスできない現象が発生する。

- uses: webfactory/ssh-agent@v0.9.1
  with:
    ssh-private-key: |
      ${{ secrets.FIRST_KEY }}
      ${{ secrets.SECOND_KEY }}

原因は、GitHubがどの登録済みキーでもSSH認証を受け入れる一方で、Deploy Keyは特定のリポジトリにのみアクセス権を持つことにある。SSHクライアントが最初に試したキーで認証が成功しても、そのキーが対象リポジトリへのアクセス権を持たなければエラーとなる。

キーの順番 認証先リポジトリ 結果
KEY_A が先 repo-a repo-a ✅ / repo-b ❌
KEY_B が先 repo-b repo-a ❌ / repo-b ✅

解決策

webfactory/ssh-agent の自動設定機能を活用

webfactory/ssh-agent は、SSHキーのコメントにリポジトリURLが含まれている場合、自動的に以下を生成する。

  • SSH config(ホストエイリアス)
  • Git URL rewrite 設定

これにより、正しいキーが自動的に選択される。

手順

1. SSHキーを生成(コメントにリポジトリURLを指定)

# リポジトリAのキー
ssh-keygen -t ed25519 -C "git@github.com:org/repo-a.git" -f ./repo_a_key -N ""

# リポジトリBのキー
ssh-keygen -t ed25519 -C "git@github.com:org/repo-b.git" -f ./repo_b_key -N ""

ここで重要なのは、-C オプションで git@github.com:org/repo.git 形式のURLを指定することである。

2. デプロイキーを登録

各リポジトリの Settings → Deploy keys に公開鍵を登録する。

cat ./repo_a_key.pub  # → repo-a のデプロイキーに登録
cat ./repo_b_key.pub  # → repo-b のデプロイキーに登録

3. GitHub Secrets を更新

秘密鍵をGitHub Secretsに登録する。

cat ./repo_a_key  # → REPO_A_SSH_KEY
cat ./repo_b_key  # → REPO_B_SSH_KEY

4. ワークフローの設定

- name: Set up SSH agent
  uses: webfactory/ssh-agent@v0.9.1
  with:
    ssh-private-key: |
      ${{ secrets.REPO_A_SSH_KEY }}
      ${{ secrets.REPO_B_SSH_KEY }}

ワークフロー側の追加設定は不要。webfactory/ssh-agent がキーコメントを読み取り、自動的に設定を生成する。

参考

webfactory/ssh-agent ドキュメントより

Deploy Keysを複数使用する際の課題があります。GitHubサーバーは最初の既知キーを受け入れますが、各キーは単一のリポジトリに限定されるため、間違ったキー/リポジトリの組み合わせが試されるとエラーになります。

このアクションはこの問題を解決するため、キーコメントをスキャンして自動的にGitとSSH設定を生成します。

  1. デプロイキー作成時にコメントに「git@github.com:owner/repo.git」のようなURLを指定
  2. アクション実行時にキーコメントがスキャンされる
  3. URLを含むコメントについて、url.<base>.insteadofを使用したGit設定が自動生成される
  4. 対応するSSH設定セクションが生成され、正しいキーでGitHub接続を完成させる

https://github.com/webfactory/ssh-agent

まとめ

方法 複数リポジトリ対応 設定の手間
デプロイキー(コメントなし)
デプロイキー(URLコメント付き)
Personal Access Token (PAT)
手動SSH config設定

SSHキー生成時に -C "git@github.com:org/repo.git" でコメントを指定する方法が最もシンプルでおすすめである。

補足

認証方式の比較

CI/CD環境でのプライベートパッケージ認証には、主に3つの方法がある。

認証方式 紐づき先 退職リスク トークン有効期限
PAT 個人アカウント あり 設定可能(最大無期限)
SSH Deploy Key リポジトリ なし なし
GitHub App Organization なし 短期間(自動更新)

SSH Deploy Keyを選択した理由

SSH Deploy Keyを使う利点は以下の通りである。

  • Deploy keyはリポジトリに紐づくため、メンバーの退職などの個人に依存しない
  • git@github.com:... 形式をそのまま使え、composer.jsonの変更が不要
  • 少数のリポジトリであれば設定がシンプル

ただし、SSH Deploy Keyには有効期限がないため、セキュリティ上は定期的なローテーションを推奨する。

PATの制約

PATは個人のGitHubアカウントに紐づく。これはGitHubの仕様であり、以下のような運用上の問題がある。

  • 特定の誰かのアカウントで生成する → その人が退職/異動したら無効化リスク
  • CI/CD専用の共有アカウントを作る → GitHubの利用規約では1人1アカウントが原則

https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens

GitHub AppとSSH Deploy Keyの使い分け

観点 SSH Deploy Key GitHub App
適したスケール 少数のリポジトリ 多数のリポジトリ
権限の粒度 リポジトリ単位(read/write) 細かいスコープ制御
セキュリティ キーの定期ローテーションを推奨 トークンが短命で自動更新
監査ログ 限定的 詳細

GitHub Appはトークンが短命で自動更新されるため、セキュリティ面では優れている。一方で、初期設定の複雑さやApp登録の手間がある。

今回は2つのプライベートパッケージという小規模な構成であり、SSH Deploy Keyの方が運用コストとのバランスが良いと判断した。リポジトリ数が増えた場合や、より厳密な権限管理が必要になった場合はGitHub Appへの移行を検討すべきである。

https://docs.github.com/en/apps/creating-github-apps/about-creating-github-apps/about-creating-github-apps

GitHubで編集を提案

Discussion