GitHubへSSH公開鍵を追加した際に「Key already in use」と表示されるのは、鍵の名前が重複しているからではありません。同じ公開鍵が、すでに別のGitHubアカウントまたはリポジトリのDeploy keyとして登録されていることが原因です。
解決の第一歩は、既存の鍵を削除することではなく、対象の秘密鍵を指定してSSH認証を試し、現在の登録先を特定することです。応答がユーザー名ならアカウント用SSH鍵、「OWNER/REPO」の形式ならDeploy keyです。既存のCIやサーバーで使われている可能性がある場合は、鍵を移動するより、新しい鍵を発行したほうが安全です。([GitHub Docs][1])
GitHubで「Key already in use」と出たときの登録先確認
GitHubの「Key already in use」は、次のような操作で発生します。
- 別のGitHubアカウントで使っている公開鍵を追加しようとした
- Deploy keyとして登録済みの公開鍵を、個人アカウントへ追加しようとした
- あるリポジトリのDeploy keyを、別のリポジトリでも使おうとした
- 過去に設定したCI・デプロイサーバー用の鍵を再利用しようとした
特に注意したいのが、同じパソコン内に複数のSSH鍵があるケースです。
通常の接続確認である次のコマンドだけでは、ssh-agentやSSH設定ファイルに登録された別の鍵が使われることがあります。
ssh -T [email protected]
その結果、本当に調べたい鍵ではなく、普段使っている別のGitHubアカウントが表示されることがあります。
対象の鍵を特定するには、-iとIdentitiesOnly=yesを指定して診断します。
指定したSSH鍵だけでGitHubへの認証を試す
macOS、Linux、Git Bashでは、次のように実行します。
ssh -T -v -o "IdentitiesOnly=yes" -i ~/.ssh/id_ed25519 [email protected]
Windows PowerShellでは、保存場所に合わせて次のように指定できます。
ssh -T -v -o "IdentitiesOnly=yes" -i "$env:USERPROFILE\.ssh\id_ed25519" [email protected]
ファイル名が異なる場合は、id_ed25519の部分を実際の秘密鍵名に置き換えてください。
各オプションには、次の役割があります。
| オプション | 役割 |
|---|---|
-T | 対話用シェルを開かず、SSH認証だけを確認する |
-v | 使用した鍵や認証処理を詳しく表示する |
-i | 認証に使用する秘密鍵を指定する |
IdentitiesOnly=yes | ssh-agent内の別鍵ではなく、指定した鍵で診断する |
[email protected] | GitHub.comのSSH接続先 |
GitHub公式ドキュメントでも、ssh-agent内の別鍵に影響されず対象鍵を確認する方法として、IdentitiesOnly=yesの利用が案内されています。([GitHub Docs][1])
-iには公開鍵ではなく秘密鍵を指定する
GitHubの画面へ貼り付けるのは、末尾が.pubの公開鍵です。
id_ed25519.pub
一方、SSH認証時に-iで指定するのは、.pubが付いていない秘密鍵です。
id_ed25519
次の指定は誤りです。
ssh -T -i ~/.ssh/id_ed25519.pub [email protected]
秘密鍵はGitHubの入力欄へ貼り付けたり、チャットやメールで送信したりしないでください。
SSH認証の応答から登録先を判断する
コマンド実行後の応答によって、公開鍵がどこで使われているかを判断できます。
| 主な応答 | 公開鍵の登録先 | 次に確認する場所 |
|---|---|---|
Hi USERNAME! | GitHubアカウントのSSH鍵 | アカウントの「SSH and GPG keys」 |
Hi OWNER/REPO! | リポジトリのDeploy key | 対象リポジトリの「Deploy keys」 |
Permission denied (publickey) | 登録先を特定できていない | 鍵のパス、鍵ペア、権限、読み込み状況 |
| 別のユーザー名が表示される | 想定外のアカウントに登録済み | 表示されたアカウントのSSH鍵設定 |
GitHubは、アカウント用の鍵ならユーザー名、Deploy keyならリポジトリを示す形式で応答します。([GitHub Docs][1])
正常に認証できても終了コードは1になる
GitHubはSSH接続によるシェル操作を提供していません。そのため、認証成功メッセージが表示されても、ssh -Tは終了コード1で終わります。
スクリプトやターミナルで終了コードだけを見ると失敗に見えますが、次のようにユーザー名を含む成功メッセージが表示されていれば認証自体は成功しています。
Hi USERNAME! You've successfully authenticated...
GitHub公式ドキュメントでも、SSH接続テストのリモートコマンドは終了コード1になると説明されています。([GitHub Docs][2])
Hi USERNAME!と表示された場合の解決方法
ユーザー名が表示された場合、その公開鍵はGitHubアカウントのSSH認証鍵として登録されています。
現在のGitHub.comでは、一般的に次の場所から確認できます。
- GitHubへログインする
- 右上のプロフィール画像を開く
Settingsを選択するSSH and GPG keysを開く- 登録済みのSSH鍵を確認する
画面名称や配置は変更されることがありますが、アカウントのアクセス設定内にあるSSH鍵管理画面を確認します。([GitHub Docs][3])
現在のアカウントで使う鍵だった場合
表示されたユーザー名が、利用したいGitHubアカウントと一致しているなら、公開鍵を追加し直す必要はありません。
ローカルリポジトリの接続先がSSH形式になっているか確認します。
git remote -v
HTTPS形式になっている場合は、必要に応じてSSH形式へ変更します。
git remote set-url origin [email protected]:OWNER/REPO.git
その後、次のコマンドで読み取りを確認できます。
git ls-remote origin
別のアカウントへ移したい場合
公式の基本的な解決方法は、以前のアカウントから鍵を削除し、利用したいアカウントへ追加することです。以前のアカウントを管理できない場合は、新しい鍵ペアを作成します。([GitHub Docs][1])
ただし、鍵をすぐに削除するのは危険です。同じ鍵が次の用途で使われている可能性があります。
- 別のパソコンからのGit操作
- 社内サーバーからの自動取得
- CI/CDのチェックアウト処理
- バックアップ用スクリプト
- 定期実行されるデプロイ処理
利用状況を完全に把握できていない場合は、既存鍵を移動するより、対象アカウント用の新しい鍵を作成するほうが安全です。
Hi OWNER/REPO!と表示された場合の解決方法
Hi OWNER/REPO!のように、ユーザー名ではなくリポジトリ名を含む応答が表示された場合、その公開鍵はDeploy keyとして登録されています。
対象リポジトリを管理できるユーザーが、次の場所を確認します。
- 対象リポジトリを開く
Settingsを開くDeploy keysを選択する- 登録されている鍵を確認する
SettingsやDeploy keysが表示されない場合は、リポジトリ設定を管理する権限が不足している可能性があります。
同じリポジトリで使う場合
登録先が目的のリポジトリと一致しているなら、Deploy keyを追加し直す必要はありません。
サーバー側で、その秘密鍵を使用するようSSH設定を整理します。
Host github-project-a
HostName github.com
User git
IdentityFile ~/.ssh/project-a_deploy
IdentitiesOnly yes
この設定を使う場合、リポジトリの接続先は次のようになります。
git clone git@github-project-a:OWNER/REPO.git
すでにクローン済みなら、リモートURLを変更できます。
git remote set-url origin git@github-project-a:OWNER/REPO.git
別のリポジトリでも使いたい場合
GitHubのDeploy keyは、基本的に1つのリポジトリへ紐付ける認証情報です。同じDeploy keyを複数のリポジトリへ使い回すことはできません。
複数リポジトリを同じサーバーから扱う場合は、リポジトリごとに専用の鍵ペアを作成し、SSHのホスト別名で使い分けます。([GitHub Docs][4])
Host github-repo-a
HostName github.com
User git
IdentityFile ~/.ssh/repo-a_deploy
IdentitiesOnly yes
Host github-repo-b
HostName github.com
User git
IdentityFile ~/.ssh/repo-b_deploy
IdentitiesOnly yes
それぞれのリポジトリには、対応する公開鍵だけをDeploy keyとして登録します。
git clone git@github-repo-a:OWNER/REPO-A.git
git clone git@github-repo-b:OWNER/REPO-B.git
既存CIを壊さずに新しいSSH鍵へ切り替える手順
既存鍵の用途が不明な場合や、本番環境で使われている場合は、先に削除してはいけません。
次の順番で切り替えると、停止リスクを抑えられます。
新しい鍵ペアを作成する
対象リポジトリが分かるファイル名を付けます。
ssh-keygen -t ed25519 -C "github:OWNER/REPO deploy" -f ~/.ssh/repo_deploy_ed25519
既存のid_ed25519へ上書きしないよう、専用のファイル名を指定することが重要です。GitHubも、既存鍵がある場合はカスタム名で保存する方法を案内しています。([GitHub Docs][5])
作成されるファイルは次の2つです。
repo_deploy_ed25519
repo_deploy_ed25519.pub
GitHubへ登録するのは、末尾が.pubの公開鍵です。
新しい公開鍵を登録する
用途に応じて登録先を選びます。
| 用途 | 登録先 |
|---|---|
| 自分の権限で複数リポジトリを操作する | アカウントのSSH鍵 |
| サーバーから1つのリポジトリへアクセスする | 対象リポジトリのDeploy key |
| 複数リポジトリを組織的に自動操作する | GitHub Appなどを検討 |
Deploy keyは通常、読み取り専用で登録できます。デプロイ処理からGitHubへプッシュする必要がある場合だけ、書き込み権限を有効にします。GitHubは、より細かな権限管理が必要な自動化ではGitHub Appの利用も案内しています。([GitHub Docs][4])
CIやサーバー側の秘密鍵を更新する
CIサービスやサーバーのシークレット管理機能へ、新しい秘密鍵を設定します。
秘密鍵を次の場所へ直接保存してはいけません。
- Gitリポジトリ内
- ソースコード内
- 公開される環境変数一覧
- WikiやIssue
- チャットの共有チャンネル
- 操作手順書のスクリーンショット
CI側で鍵の変数名を変更した場合は、ワークフローやデプロイスクリプトの参照先も更新します。
新しい鍵で接続を確認する
対象鍵を明示して確認します。
ssh -T -v -o "IdentitiesOnly=yes" -i ~/.ssh/repo_deploy_ed25519 [email protected]
リポジトリの読み取り確認には、実際の接続設定を使って次のように実行します。
git ls-remote origin
CIの場合は、テスト用ジョブや手動実行でチェックアウト処理まで確認します。
問題がないことを確認してから旧鍵を整理する
新しい鍵への切り替えが完了し、既存処理が正常に動作することを確認してから、不要な旧鍵を削除します。
移行直後は、次の項目を確認すると安全です。
- Gitの取得が成功する
- 必要な場合はプッシュも成功する
- 定期実行ジョブが正常終了する
- 本番デプロイが新しい鍵を使っている
- 古い秘密鍵を参照する設定が残っていない
公開鍵のフィンガープリントで取り違えを防ぐ
似た名前の鍵が複数ある場合は、タイトルではなくフィンガープリントで照合します。
対象ファイルのフィンガープリントは、次のコマンドで確認できます。
ssh-keygen -lf ~/.ssh/id_ed25519.pub -E sha256
ssh-agentへ読み込まれている鍵を一覧表示する場合は、次のコマンドを使います。
ssh-add -l -E sha256
ただし、ssh-add -lに表示されるのはエージェント内の鍵です。今回調べたいファイルと一致するとは限らないため、対象の.pubファイルを直接指定した結果と照合するほうが確実です。
GitHubのSSH鍵監査でも、ローカル側とGitHub側のフィンガープリントを照合する方法が案内されています。([GitHub Docs][6])
よくある失敗と正しい対処
| 失敗しやすい操作 | 問題点 | 正しい対処 |
|---|---|---|
ssh -T [email protected]だけで確認する | ssh-agent内の別鍵が使われることがある | -iとIdentitiesOnly=yesを指定する |
-iに.pubファイルを指定する | 公開鍵では認証できない | .pubなしの秘密鍵を指定する |
| エラーが出た鍵をすぐ削除する | 既存CIやサーバーが停止する可能性がある | 利用先を特定してから削除する |
| 1つのDeploy keyを複数リポジトリで使う | GitHubに登録を拒否される | リポジトリごとに鍵を作成する |
| 鍵のタイトルだけで判断する | タイトルは自由に設定でき、重複もあり得る | SSH応答とフィンガープリントで確認する |
| 終了コード1を認証失敗と判断する | GitHubの接続テストは成功時も1で終了する | 表示された認証メッセージを確認する |
| 不要なのに書き込み権限を付ける | 漏えい時の影響が大きくなる | 読み取り専用を基本にする |
| 秘密鍵を画面共有する | 第三者にリポジトリを操作される恐れがある | 公開鍵と秘密鍵を確実に区別する |
登録先に応じた最終判断
「Key already in use」が表示されたら、次の基準で対応を決めます。
| 確認結果 | 推奨する対応 |
|---|---|
| 利用したいアカウント名が表示された | 再登録せず、その鍵を使うようSSH設定を見直す |
| 過去の自分のアカウント名が表示された | 既存用途を確認し、安全なら移動する |
| 管理できないアカウント名が表示された | 新しい鍵ペアを発行する |
| 利用したいリポジトリ名が表示された | 既存Deploy keyをそのまま使う |
| 別のリポジトリ名が表示された | 対象リポジトリ専用の新しい鍵を作る |
| 登録先や用途が分からない | 既存鍵を削除せず、新しい鍵へ切り替える |
最初に実行すべきなのは、次の診断コマンドです。
ssh -T -v -o "IdentitiesOnly=yes" -i /path/to/private_key [email protected]
応答からアカウント用SSH鍵かDeploy keyかを特定し、既存環境への影響が分からなければ新しい鍵を発行します。特に本番サーバーやCIで使っている鍵は、接続確認が完了するまで登録削除や秘密鍵の上書きを行わないことが重要です。
[1]: https://docs.github.com/en/authentication/troubleshooting-ssh/error-key-already-in-use “Error: Key already in use – GitHub Docs”
[2]: https://docs.github.com/en/authentication/connecting-to-github-with-ssh/testing-your-ssh-connection “Testing your SSH connection – GitHub Docs”
[3]: https://docs.github.com/en/articles/adding-a-new-ssh-key-to-your-github-account “Adding a new SSH key to your GitHub account – GitHub Docs”
[4]: https://docs.github.com/en/authentication/connecting-to-github-with-ssh/managing-deploy-keys “Managing deploy keys – GitHub Docs”
[5]: https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent “Generating a new SSH key and adding it to the ssh-agent – GitHub Docs”
[6]: https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/reviewing-your-ssh-keys “Reviewing your SSH keys – GitHub Docs”

コメント