Intro
以前常用していた5年前のノートPC (NEC PC)が、バッテリーとSSDの交換を経て快適によみがえった。
ついでにそのPC内のWSL環境も一新しておこうと考えた。
その詳細は別の記事に記すが、その際にGPGの鍵でSSH接続しようとして大変苦労したので、その記録を残す。
はじめからryeやgpgを前提にした構成にするだけでなく、
shellもzsh (prezto、powerlevel10k)に変更するなどしている。
TL; DR
- gpgをインストールし、GPGの主鍵とSub鍵を作成する
- GPGのSub鍵からSSH接続用の公開鍵を出力する
- gpg-agentをssh-agentとして利用する
- ssh-agentに従来の秘密鍵とGPGの認証用鍵を登録する
- 不具合に適切に対処する
GPGとは
GPG (Gnu Privacy Guard) は、OpenPGPの実装であり、データの暗号化や署名を行うためのツールである。
細かい説明は省くが、公開鍵暗号方式によって、署名(S)・証明(C)・認証(A)・暗号化(E)の3つの機能を提供する。
つまり、安全にデータの暗号化、本人証明、改竄検知、SSH接続などができる。
GPGについては、ここの記事が大変詳しく、かつ網羅的だ。素晴らしい。
GPG で始める暗号・署名ライフ
SSH with GPG
上記の記事にも紹介されているが、GPG鍵をSSH接続に利用することができる。
その際の手順と詰まった点を記す。
GPGのinstall, GPG鍵の作成
1 2 3 4
| sudo apt install install gnupg gpg --full-gen-key --expert
|
(上記の記事を参考に) GPGのMaster鍵を作成する。
以前に作成したものがあるならそれを利用する。
GPG Sub鍵の作成
安全のため、GPGのMaster鍵をそのまま用いることは推奨されない。
(上記の記事を参考に) GPGのSub鍵を作成する。
その際、暗号化・署名・認証のそれぞれ3つの機能を持つSub鍵を作成できる。
ここまで来ると、ファイルの暗号化や署名もできるようになる。
また、各サービスとの連携や、サービスへの公開鍵の登録も行おう。
(記事「ファイルの暗号化」「ファイルへの署名」「公開鍵の公開」節)
特に、Gitへの署名は重要だ。
(記事「Gitコミットへの署名」節)
公開鍵の出力
参考記事: OpenSSH の認証鍵を GunPG で作成・管理する
こちらの記事でもSub鍵の生成の説明が行われている。
その続きでは、GPGの鍵から公開鍵を生成する。
(公開鍵はGPGのMaster鍵でもSub鍵でも共通である)
1
| gpg --export-ssh-key NAME > ~/.ssh/gpg_ssh_key.pub
|
NAMEは鍵の識別子であり、以下のいずれかを用いる。
- 鍵のID
- 鍵に紐づいたメールアドレス
- 鍵に紐づいた名前
これはgpg --list-keys
で確認できる。
1 2 3 4 5 6 7 8
| ❯ gpg --list-keys /home/USERNAME/.gnupg/pubring.kbx ----------------------------- pub rsa2048/ABCD1234EF567890 2021-01-01 [SC] ABCD1234EF5678901234567890ABCDEF12345678 uid [ultimate] Your Name <[email protected]> sub rsa2048/12345678ABCDEF12 2021-01-01 [E] sub rsa2048/87654321FEDCBA98 2021-01-01 [A]
|
上記の場合は、ABCD1234EF5678901234567890ABCDEF12345678
やYour Name
、[email protected]
がNAMEとして使える。
ここで出力した公開鍵は、いつものSSHの公開鍵のように、サーバーに登録する。
すなわちscpなどでサーバーに送り、~/.ssh/authorized_keys
に追記する。
1
| cat ~/.ssh/gpg_ssh_key.pub >> ~/.ssh/authorized_keys
|
gpg-agentをssh-agentに利用する
恥ずかしながら、ここに来るまで筆者はssh-agentすら用いていなかった (~/.ssh/configまでの管理で済ませていた)。
なので、ssh-agentとgpg-agentの両方の勉強をすることになった。
まずはgpg-agentがssh-agentとして機能するように設定する。
~/.gnupg/gpg-agent.conf~/.bashrc1 2
| export GPG_TTY=$(tty) export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket)
|
これで、gpg-agentがssh-agentとして機能するようになる。
agentへの秘密鍵の登録
ssh-agent (実態はgpg-agent) に従来の秘密鍵とGPGの認証用鍵を登録する。
1 2 3 4 5 6 7
| ssh-add ~/.ssh/id_ed25519
ssh-add -L
ssh-ed25519 ABCDEDFJFIAJOFPW598da1787818f7e81f7815185 name@PC
|
さらにGPGの認証用鍵も登録する。keygrip
付きでGPG鍵の情報を表示する。
1 2 3 4 5 6 7 8 9
| gpg --list-keys --with-keygrip NAME
pub rsa2048/ABCD1234EF567890 2021-01-01 [SC] ABCD1234EF5678901234567890ABCDEF12345678 uid [ultimate] Your Name <[email protected]> sub rsa2048/12345678ABCDEF12 2021-01-01 [E] Keygrip = ABCD1234EF567890123456789A7CB7F9E05C8192 sub rsa2048/87654321FEDCBA98 2021-01-01 [A] Keygrip = F5C774ABCD1234EF567890123456789FAFAFAC8E
|
そのうち認証(A)のkeygripをコピーして、~/.gnupg/sshcontrol
に追記する。
1 2 3 4 5
|
echo F5C774ABCD1234EF567890123456789FAFAFAC8E 0 >> ~/.gnupg/sshcontrol
|
その後、改めてssh-add -L
とすると、GPG鍵も登録されていることが確認できる。
1 2 3 4
| ssh-add -L
ssh-ed25519 ABCDEDFJFIAJOFPW598da1787818f7e81f7815185 name@PC ssh-ed25519 89959ABCDEDFJFIAJOFPW598da1787818f7e81f78 (none)
|
詰まった点
公開鍵の出力
実は公開鍵の出力にはいくつか方法があり、そのいずれでも構わない。
ただ、不具合が出た際に選択肢が多い分、無駄に公開鍵の出力部分を疑うことになってしまった。
(重要) GPG鍵の認証エラー
1 2 3 4 5 6 7 8 9 10
|
ssh HOSTNAME
kex_exchange_identification: read: Connection reset by peer Connection reset by xxx.xxx.x.xxx port xxxx
sign_and_send_pubkey: signing failed for ED25519 "/home/USERNAME/.ssh/id_ed25519" from agent: agent refused operation ([email protected]) Password:
|
おそらく、GPG鍵のフレーズ入力に一度裏で失敗し、その状態が残り続けたものと思われる。
gpg-agentをssh-agentとして用いている限り、GPG認証鍵を用いない場合でも、公開鍵認証ができなくなる。
これには大変苦しめられた。
1 2 3 4 5 6 7 8 9 10
|
sudo apt install pinentry-gtk2
echo UPDATESTARTUPTTY | gpg-connect-agent
eval "$(ssh-agent -s)"
|
上記を入力するとフレーズを入力する画面になるなどして、解決する。
(引用元: StackExchange)
ちなみに、gpg-agentの再起動では直らなかった。 罪深い……。
1 2
| gpgconf --kill gpg-agent gpgconf --launch gpg-agent
|
GPG認証鍵の登録
GPG鍵でSSH接続しようという記事は多いのだが、なぜかGPG認証鍵をgpg-agentに登録するくだりが触れられていない記事が多かった (あるいは、僕が見逃してしまいがちだった)。
gpg-agentをssh-agentとして利用している時点で、GPG側の鍵を自動的に登録してくれると思っていたが、そうではなかったようだ。
手順がわかればなんてことはなかったのだが……。
ssh接続におけるssh-agentやgpg-agentの挙動を調べるうえでは、Dockerが大変役に立った。
軽くて簡単で再現性のある仮想環境最高すぎる。
Dockerfile1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| FROM ubuntu:latest
RUN apt-get update && apt-get install -y openssh-server \ && mkdir -p /var/run/sshd \ && echo 'root:YOUR_PASSWORD' | chpasswd \ && sed -i 's/#PasswordAuthentication yes/PasswordAuthentication yes/g' /etc/ssh/sshd_config \ && sed -i 's/#PubkeyAuthentication yes/PubkeyAuthentication yes/g' /etc/ssh/sshd_config \ && sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config
COPY ./data /data
RUN mkdir -p /root/.ssh \ && chmod 700 /root/.ssh \ && cat /data/*.pub > /root/.ssh/authorized_keys \ && chmod 644 /root/.ssh/authorized_keys
EXPOSE 22 CMD ["/usr/sbin/sshd", "-D"]
|
docker-compose.yml1 2 3 4 5
| services: app: build: . ports: - 2222:22
|
1 2 3 4
| docker compose down --remove-orphans && \ docker compose build app && \ docker compose run --rm --service-ports -d app
|
コンテナ内外でのport接続を行う場合は、docker-compose.yml
のports
の設定に加えて--service-ports
オプションが必要。
さらに、終了する場合は--remove-orphans
オプションをつける必要がある。
まとめ
GPG鍵を用いたSSH接続は、セキュリティを高めるためにも有用だ。
しかし、その設定にはgpg-agentやssh-agentの設定が必要で、また、その設定には躓きやすい点が多い。
この記事が読者の一助になれば幸いだ。