AgentForwarding - GnuPG wikiを参考にして、 gpg-agent
を ssh
先からも使えるようにしてみました。
動作確認バージョン
ローカル側:
- macOS Monterey 12.6
- Homebrew でインストールした gpg (GnuPG) 2.3.7
- OpenSSH_8.6p1, LibreSSL 3.3.6
リモート側:
- Ubuntu 22.04.1 LTS (jammy)
- gnupg 2.2.27-3ubuntu2.1
- openssh-server 1:8.9p1-3
この後の例では、リモート側のマシン名を $REMOTE
と表記しています。
ローカル側の GnuPG 設定
GnuPG (< 2.1.17)
だと extra-socket /home/<user>/.gnupg/S.gpg-agent.extra
の設定が必要だそうですが、 2.3.7 なので、何も設定を追加しなくても、 gpgconf --list-dir agent-extra-socket
で出てくる /Users/$USER/.gnupg/S.gpg-agent.extra
が存在していました。
pinentry など
今回の設定とは関係なく、 ~/.gnupg/gpg-agent.conf
には以前から以下のように pinentry
などの設定をしています。
pinentry-program /opt/homebrew/bin/pinentry-mac
default-cache-ttl 3600
max-cache-ttl 18000
このうち pinentry-program
の設定が必要なので、 入っていなければ brew install pinentry-mac
でインストールして、 ~/.gnupg/gpg-agent.conf
に設定しておきます。
default-cache-ttl
と max-cache-ttl
は好みで設定すれば良いと思います。
Pinentry Mac の設定
「Save in Keychain」のチェックボックスをオフにしておくため、 defaults
コマンドで以下の設定もしています。
% defaults write org.gpgtools.common UseKeychain NO
extra-socket とは
Pinentry Mac で普通にパスフレーズを要求されるときは 「OpenPGP の秘密鍵のロックを解除するためにパスフレーズを入力してください:」 と出ますが、 extra-socket からのリクエストのときは 「注意: リモートサイトからのリクエストです。」 と出て、 区別できるようになっています。
公開鍵のコピー
公開鍵はリモートにも入れておく必要があるようなので、 export
して import
しておきます。 --armor
をつけているのは、間違えて端末に表示してしまったときに変にならないようにするためで、なくても同じです。
(2022-10-14 追記) ownertrust
の情報も export
して import
しておきます。
% gpg --export --armor $KEY_ID | ssh $REMOTE gpg --import
% gpg --export-ownertrust | ssh $REMOTE gpg --import-ownertrust
コマンドライン指定での動作確認
サーバー側も OpenSSH >= 6.7
なので、 /etc/ssh/sshd_config
に StreamLocalBindUnlink yes
を追加すれば良いのですが、 その前にコマンドライン指定だけで動作確認をしておきます。
-R "$(ssh $REMOTE gpgconf --list-dir agent-socket):$(gpgconf --list-dir agent-extra-socket)"
でも同じですが、 後で ~/.ssh/config
に追加しやすいように -o
で動作確認しています。
リモート側は鍵を信頼する設定をしていないので確認がでますが、 y
でそのまま使います。
% ssh $REMOTE rm '$(gpgconf --list-dir agent-socket)'
% ssh -o "RemoteForward $(ssh $REMOTE gpgconf --list-dir agent-socket) $(gpgconf --list-dir agent-extra-socket)" $REMOTE
$ echo test | gpg --encrypt -r $KEY_ID --armor -o test.asc
$ gpg --decrypt test.asc
$ gpg -K
最初はうまくいかなかったので、 gpg-connect-agent reloadagent /bye
とかリモートマシンの再起動を試しましたが、 ControlMaster
を使っているなら、 ローカル側で ssh -O exit $REMOTE
を試すと良さそうです。
ローカル側の設定追加
% echo "RemoteForward $(ssh $REMOTE gpgconf --list-dir agent-socket) $(gpgconf --list-dir agent-extra-socket)"
で表示した設定を ~/.ssh/config
の Host $REMOTE
のとこに追加しておきます。
リモート側の設定追加
StreamLocalBindUnlink yes
の設定を /etc/ssh/sshd_config
の適当なところに追加しておきます。 最近は Include /etc/ssh/sshd_config.d/*.conf
があるので、 下の例では /etc/ssh/sshd_config.d/StreamLocalBindUnlink.conf
を作成しました。 追加したら、 reload
や再起動で反映させておきます。
% ssh $REMOTE
$ echo StreamLocalBindUnlink yes | sudo tee /etc/ssh/sshd_config.d/StreamLocalBindUnlink.conf > /dev/null
$ sudo systemctl reload ssh
これで ssh $REMOTE rm '$(gpgconf --list-dir agent-socket)'
をしなくても自動で作り直されて使えるようになります。
まとめ
いくつかの設定をして、Unix Socket を RemoteForward
で forwarding することで手元の gpg-agent
(と pinentry
) をリモートからも使えるようになりました。
これでリモートに秘密鍵を置かずに Pass: The Standard Unix Password Manager などが使えそうです。
次回の記事に続きます。