令和最新版】sshcontrol使わないで!最近のGPGによるSSH認証のベスト

はじめに GnuPGユーザーがGPG鍵をSSH認証にも使おうとしたら、今までは、sshcontrol 利用するという、記事やブログの内容がほとんどだと思いますし、ChatGPTLLM使ったボットなどもこの内容を案内していますが、いつからか、このsshcontrol使う方法は推奨になっていました。 This…

公開日:

最終更新:

はじめに

GnuPGユーザーがGPG鍵をSSH認証にも使おうとしたら、今までは、sshcontrol 利用するという、記事やブログの内容がほとんどだと思いますし、ChatGPTLLM使ったボットなどもこの内容を案内していますが、いつからか、このsshcontrol使う方法は推奨になっていました。

This file is deprecated in favor of the "Use-for-ssh" attribute in the key files. (§ sshcontrol https://www.gnupg.org/documentation/manuals/gnupg/Agent-Configuration.html)

sshcontrol変わる新しい方法は GnuPG 2.3.7(2022リリース)で導入されました。つまり、もう3以上前から sshcontrol 推奨なのですが、ネット上のほとんどの記事はまだ古い方法を案内し続けています。

ここでは、それらの変更に対応した新しい方法を示します。日本語でこれが解説されてあるのはGentoo LinuxGnuPGwikiぐらいでしょうか。

そもそもなぜGPG鍵でSSH認証するのか?

SSHペアだけでも十分安全に認証できます。ではなぜわざわざGPG鍵をSSH使うのか?主な理由はいくつかあります。

  • 鍵の一元管理署名・暗号化・認証を1つのGPGマスター鍵の鍵で管理できるので、鍵がバラバラにならない

  • YubiKeyなどのハードウェアトークンとの相性GPG鍵をYubiKey格納すれば、署名もSSH認証もハードウェアトークン1つで完結する

  • 鍵の失効や有効期限の管理GPG仕組みで鍵の失効や有効期限の設定ができるので、SSH鍵のライフサイクル管理がやりやすい

  • Web of Trustとの統合GPG信頼モデルの中でSSH認証鍵も管理できる

別に今のSSH鍵で困ってないし…」という方も多いと思いますが、YubiKey買った瞬間に全部変えたくなる、というのはよくある話です。

前提

すでにsshcontrol利用していえも、い無くてもかまいません。

  • GnuPG 2.3.7以降がインストールされている(gpg --version 確認できます)

  • すでに秘密鍵や公開鍵をGPG読みこんでいる

  • 認証用の鍵(Authentication subkey)存在するもしくはマスター鍵に認証(A)ケーパビリティがある

    • 鍵は必要ではないですが、ベストとして設定せねばなりません

  • GPG SSH 接続したい先に同じ公開鍵がある

💡 認証用の鍵を持っていない場合は、gpg --expert --edit-key <鍵ID> から addkey 認証(Authentication)ケーパビリティを持つ鍵を作成できます。--expert つけないとケーパビリティの選択画面が出ないので注意してください。

手順 1:Keygrip確認する

まず、SSH接続したいGPG鍵のKeygrip確認してください。

Keygripとは?

Keygripは、GPG鍵(やその鍵)を一意に識別する40文字の16進数文字列です。鍵のID(Key ID)フィンガープリントとは別物で、GPG内部的な鍵の識別子として使われます。gpg-agent 鍵をKeygrip管理しているので、SSH用の鍵を指定するときもこのKeygrip必要になります。

方法1 gpg コマンドを使う

鍵のID鍵なども全て見る場合

GPG コマンド
gpg --list-secret-keys --keyid-format long --with-keygrip

出力例はこんな感じです:

sec ed25519/AAAA1111BBBB2222 2024-01-01 [C] [expires: 2026-01-01]
Keygrip = 1234567890ABCDEF1234567890ABCDEF12345678
uid [ultimate] Your Name <your@email.com>
ssb ed25519/CCCC3333DDDD4444 2024-01-01 [S] [expires: 2025-01-01]
Keygrip = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
ssb cv25519/EEEE5555FFFF6666 2024-01-01 [E] [expires: 2025-01-01]
Keygrip = BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
ssb ed25519/GGGG7777HHHH8888 2024-01-01 [A] [expires: 2025-01-01]
Keygrip = CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC

ここで重要なのは [A]Authentication)フラグが付いている鍵のKeygripです。上の例だと CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC ですね。[S] sign署名、[E] encryption暗号化、[C] 認証局(Certify)なので、違えないようにしてください。

鍵のID見なくても良い場合

gpg -k --with-keygrip

いずれにせよ、 --with-keygrip 必要ですね。

方法2 gpg-connect-agent 使う

gpg-connect-agent 'keyinfo --list' /bye

出力はこんな感じです:

S KEYINFO <KEYGRIP> D - - - P - - -
S KEYINFO <KEYGRIP> D - - - P - - -
...
OK

こちらはKeygrip羅列なので、どれが認証用かはこれだけでは分かりません。方法1と併用するのがおすすめです。

手順 2:gpg-agentSSH認証にわれるようにする

シェルの設定を行います。この手順自体はsshcontrol 使われていた方なら設定をしなくても良いはずです。初めての方は以下の手順を踏んでください。

2-1. gpg-agent.confSSHサポートを有効化する

~/.gnupg/gpg-agent.conf 以下の行を追加します:

enable-ssh-support

これで gpg-agent SSHエージェントとしても動作するようになります。

2-2. シェルの環境変数を設定する

.bashrc.zshrcあるいはお使いのシェルの設定ファイルに以下を追加してください:

# GPGTTY認識できるようにする
export GPG_TTY="$(tty)"

# SSHgpg-agent使うようにソケットを指定する
export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket)

# gpg-agent起動する(すでに起動していれば何もしない)
gpgconf --launch gpg-agent

GPG_TTY 設定は地味に大事です。これがないとパスフレーズの入力プロンプト(pinentry)正しいターミナルに表示されず、認証がハングすることがあります。

SSH_AUTH_SOCK gpg-agent SSHソケットに向けることで、ssh コマンドが ssh-agent 代わりに gpg-agent 使うようになります。

2-3. gpg-agent起動する

設定を反映させるため、gpg-agent 起動します:

gpgconf --kill gpg-agent
gpgconf --launch gpg-agent

もしくは、新しいターミナルを開き直せばOKです。

手順 3:gpg-agentSSH接続に使って良い鍵を教える

ここがsshcontrol代わる新しい方法のキモです。gpg-connect-agent 使って、対象の鍵にUse-for-ssh属性を付与します。

gpg-connect-agent 'keyattr <KEYGRIP> Use-for-ssh: true' /bye

<KEYGRIP> 部分を、手順1で確認した認証鍵の[A]Keygrip置き換えてください。

設定できたか確認する

gpg-connect-agent 'keyattr <登録したKEYGRIP> Use-for-ssh: ' /bye

入力して、

D true
OK

出たらセットアップ終了です。

登録を解除したい場合

逆に、SSH認証から鍵を外したい場合は false 指定します:

gpg-connect-agent 'keyattr <KEYGRIP> Use-for-ssh: false' /bye

ssh-add -L 確認する

gpg-agent 正しくSSH鍵を提供しているか、SSH側からも確認できます:

ssh-add -L

登録した鍵のSSH公開鍵が表示されれば成功です。The agent has no identities. 出た場合は、手順2のシェル設定や gpg-agent 起動を見直してください。

SSH公開鍵をエクスポートする

SSH接続先(GitHubサーバーの ~/.ssh/authorized_keys登録する公開鍵は、以下のコマンドでエクスポートできます:

gpg --export-ssh-key <メールアドレスまたはID>

出力は ssh-ed25519 AAAA... user@email.com ようなSSH公開鍵のフォーマットになっているので、そのまま authorized_keys 貼り付けたり、GitHub設定画面に登録したりできます。

もう一つの方法として、ssh-add -L 出力をそのまま使うこともできます。こちらも同じSSH公開フォーマットです。

手順 4:接続してみる

例えばGitHubすでに今回登録したSSH公開鍵を登録して、接続できるようにしている場合は

ssh -T git@github.com

接続できます。

うまくいけば、こんなメッセージが返ってきます:

Hi <ユーザー名>! You've successfully authenticated, but GitHub does not provide shell access.

パスフレーズ付きの鍵の場合は、ここで pinentry ダイアログが出てパスフレーズの入力を求められます。正しく入力すれば認証が通ります。

これで終了です!お疲れさまでした。

sshcontrol からの移行

sshcontrol には、鍵のKeygrip書かれているはずなので、それを一行ずつ手順 3実行すれば良いはずです。

~/.gnupg/sshcontrol 中身はこんな感じになっているはずです:

# 認証鍵のKeygrip
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC 0

先頭のKeygrip部分を使って、一つずつ keyattr コマンドを実行してください。

複数の鍵がある場合は、スクリプトを組んでもいいでしょう。例えばこんな感じです:

#!/bin/bash
# sshcontrolから移行するスクリプト
while IFS= read -r line; do
# コメント行と行をスキップ
[[ "$line" =~ ^#.*$ || -z "$line" ]] && continue
# Keygrip取り出す(最初のフィールド)
keygrip=$(echo "$line" | awk '{print $1}')
echo "Registering keygrip: $keygrip"
gpg-connect-agent "keyattr $keygrip Use-for-ssh: true" /bye
done < ~/.gnupg/sshcontrol

移行が完了したら、sshcontrol ファイルは削除してしまっても問題ありません。念のためバックアップを取ってから消すと安心ですね。

トラブルシューティング

ssh-add -L」で「The agent has no identities.」出る

これは ssh gpg-agent SSHソケットを見つけられていないか、gpg-agent SSHサポートを有効にしていない場合に起こります。

  1. echo $SSH_AUTH_SOCK で、パスが /run/user/<UID>/gnupg/S.gpg-agent.ssh ようなgpg-agentソケットを指しているか確認してください。もし /tmp/ssh-... ようなパスになっていたら、ssh-agent 使われてしまっています。

  2. ~/.gnupg/gpg-agent.conf enable-ssh-support 入っているか確認してください。

  3. gpg-agent 起動してみてください:

gpgconf --kill gpg-agent
gpgconf --launch gpg-agent

SSH接続時に「sign_and_send_pubkey: signing failed」出る

gpg-agent パスフレーズを聞くためのpinentryプログラムが正しく動いていない可能性があります。

  1. GPG_TTY 正しく設定されているか確認:

echo $GPG_TTY

何も出力されない、またはターミナルのデバイスパスでない場合は export GPG_TTY="$(tty)" 実行してください。

  1. gpg-agent TTY情報を更新させる:

gpg-connect-agent updatestartuptty /bye

SSH通るが、なぜか別の鍵が使われている

gpg-agent 複数のSSH鍵を提供している場合、SSH最初にマッチした鍵を使います。ssh -v 接続時のデバッグ出力を確認すると、どの鍵が試行されているか分かります:

ssh -vT git@github.com

Offering public key 行を見ると、どの鍵が使われているか確認できます。意図しない鍵が使われている場合は、~/.ssh/config IdentityFile 指定するか、不要な鍵の Use-for-ssh false にしてください。

pinentryダイアログが出ない / ハングする

リモート接続(tmuxscreen経由、SSH越しなど)で作業している場合にきやすいです。

  1. gpg-connect-agent updatestartuptty /bye 実行して、現在のTTYgpg-agent 教えてください。

  2. gpg-agent.conf pinentry-program 正しいpinentryバイナリを指しているか確認してください。CUI使いたいなら pinentry-cursesGUIなら pinentry-macmacOS)pinentry-gnome3Linux)などです。

それでもダメなとき

ssh -T git@github.com

接続して、公開鍵の認証が出来ない場合は、シェルの設定の内容をもう一度確認したり、シェルからインタープリタ的に設定した後、シェルを閉じないでそのまま接続を行ってください。

また、以下のようなリセットコマンドもあります。

gpg-connect-agent reloadagent /bye

gpg-connect-agent updatestartuptty /bye

どちらも OK 帰ってきたらリセット完了です。

最終手段として、gpg-agent ログを有効にして原因を調べることもできます。~/.gnupg/gpg-agent.conf 以下を追加してください:

debug-level advanced
log-file ~/.gnupg/gpg-agent.log

gpg-agent 起動後、SSH接続を試みて、ログファイルの内容を確認してください。

わりに

読みいただきありがとうございました。近日中に、GPGから入門し、さらにSSH鍵など、様々な応用までカバーするための記事を公開する予定です。

参考