GPG 鍵を SSH 越しにフォワードする
GPG 鍵を SSH に使う とか YubiKey に GPG 鍵を入れる とかやっていると、秘密鍵は SSH クライアントマシンに刺さっている YubiKey に入っていて、SSH 先のマシンは GPG 鍵が使えなくて不便、なんてことが起きるのでどうにかしたい。
ここに回答あり。
https://wiki.gnupg.org/AgentForwarding
基本設定
とりあえずサーバ側
たぶん gpg-agent が起動している前提かな?
StreamLocalBindUnlink yes および AllowAgentForwarding yes を /etc/ssh/sshd_config に追記し (あるいは /etc/ssh/sshd_config.d/適当な名前.conf に入れる。こっちの方がいいかも) sshd 設定を sudo systemctl reload sshd で再読み込み。。
続いて gpgconf --list-dir agent-socket を実行して結果をメモっておく。
でもってクライアント側。
gpgconf --list-dir agent-extra-socket して結果をメモっておく。サーバ側とは引数が似て非なるので注意。
そして ~/.ssh/config に以下を設定。
code:config
Host gpgtunnel
HostName server.domain
RemoteForward サーバ側で調べたやつ クライアント側で調べたやつ
で、ssh gpgtunnel すればいい。
テストとしては、適当に git commit でもして署名がされることを確認したらいい。
推奨: ローカルポートフォワーディング経由で使う
最後の方に書いた。
トラブルシューティング
鍵が信頼されてない
こんなエラーが出る場合。
code:text
gpg: 9D162A9E537F0DCB: There is no assurance this key belongs to the named user
gpg: stdin: encryption failed: Unusable public key
クライアント側から以下を打てば OK。
code:shell
$ gpg --export-ownertrust | ssh ${host} gpg --import-ownertrust
SSH forward されてない
ローカルポートフォワーディングで多分色々解決できる。最後の方に書いたのでそちらを参照。
GPG ってよりは SSH の問題だけど。
git commit できたが git push で Permission denied (publickey) が出てしまう。
~/.ssh/config に ForwardAgent yes 入れてるけどだめだな。
原因は 2 つあった。
まず、/etc/ssh/sshd_config に AllowAgentForwarding yes を入れてなかった。凡ミス。
つづいて SSH 先で ssh-agent を有効にしていた。これはオフにしないと行けない。
あれ、まだおかしいぞ
結論としては以下を行って SSH 再接続したら直った。
code:shell
$ gpg-connect-agent reloadagent /bye
$ rm /run/user/1000/gnupg/S.gpg-agent
https://www.ecliptik.com/Forwarding-gpg-agent-over-SSH/ によれば StreamLocalBindUnlink yes が上手く仕事をしなくて stale な socket を使いまわそうとしてしまうことが、たまに起きるらしい。
この作業によって stale な socket を完全に破棄してやることで上手くいくようになった。
簡易に行う方法
reloadagent は不要っぽい。なのでこんなワンライナーで接続してやればいい。
code:shell
ssh ${host} 'rm /run/user/1000/gnupg/S.gpg-agent'; ssh ${host}
その他の問題
普段使いの Fish だと「そんな秘密鍵はない」と怒られて、素 Bash にしたら起きなくなった。Fish の config の中で何かやらかしてる可能性あり。
上記のワンライナーで接続したら問題なくできた。
それから、wezterm ssh した場合もダメっぽい予感。
ついでに、複数端末から SSH すると 2 つ目以降がダメになる予感。
単一の端末で SSH し、そこで tmux セッションを貼れば擬似的に複数から使える。
まあセッション保持で tmux はよく使うのでこれ自体は別に構わない。
と、このように案外まだまだ課題はある。
とくに wezterm ssh が便利っぽいのに使えないのはイマイチ。
ちなみに通常の SSH と同じように rm してから wezterm ssh するのも試したが駄目だった。
これについてはとりあえず tmux でいいか。
なお tmux を使う場合、https://qiita.com/ssh0/items/a9956a74bff8254a606a を踏まえつつ、SSH 接続時のみ tmux を自動起動 (or 既存 tmux セッションを再利用)というのを仕込んでおくと楽になりそうだ。
おっと、Tramp も駄目。
Magit でのgit pull はできたが git commit に失敗したので、これはおそらく SSH 鍵の forward は成功しているが GPG 鍵の forward に失敗しているということだろう。
あとこれは試していないが、JetBrains Gateway を使う場合も同じ理屈で commit には失敗するのではないだろうか。
ちなみに SSH 経由接続にすると、今回の重要要素である ~/.ssh/config の RemoteForward が記述されていると「パースに失敗した!」となる。
回避策の考察
単純なのは
まあ何をするかにもよるのだが、ファイル操作だけだったら Tramp とかしてないで sshfs でマウントしてしまうのが楽。
Tramp より速いし、これならそもそも鍵の forward 自体が不要になる。
ちなみに sshfs する際には -o follow_symlinks オプションを忘れずに。これがないとシンボリックリンクを正しく辿れなくなるため。
しかしSSH 先ホストでプロセスを起動しないといけない場合は sshfs ではどうにもならいので素 SSH を用いることになる。
JetBrains Gateway については、git commit だけ SSH または sshfs (+ Magit) 上で行い、あとは JetBrains Gateway でやるという手はある。ちなみに tig は個人的に慣れなかったので使ってないが、今後出番があったりして。
今まで JetBrains IDE 上で「やっていこなかった」Git コマンドは複数あるので、それが 1 つ増えるだけではある。が、commit こそ IDE 上で一番頻繁にやるし結構それは面倒だなあ。
まあ SourceTree とか GitKraken とかの Git クライアントを使うのとノリは同じだよね。自分の場合はツールを増やしすぎないようにするために Magit が有力だとは思う。
ちなみにソースコードを sshfs でマウントするのであれば以下を .gitconfig に追加して GHQ のパスを追加しておくのがいいだろう。
code:.gitconfig
ghq
root = /path/to/sshfs/.ghq
root = /path/to/sshfs/go/src
ローカルポートフォワーディングで快適に
まずはこれ。
code:shell
ssh ${host} -L 20022:localhost:22
↑にあるゴミ掃除も同時にやると完璧。
code:shell
ssh ${host} 'rm /run/user/1000/gnupg/S.gpg-agent'; ssh ${host} -L 20022:localhost:22
で、JetBtrains Gateway からは localhost:20022 に接続すればいい。
これで GPG 鍵がフォワードされた状態で使えるので、git commit とかやりたい放題。やったね!
さらなる利点として、複数端末からの接続も可能となる。wezterm ssh がようやく使える!!
参考になりそうなもの
https://blog.n-z.jp/blog/2022-10-05-gpg-agent-forwarding.html
https://blog.n-z.jp/blog/2022-10-14-gpg-agent-forwarding
#Linux