← シリーズに戻る

SSHの鍵認証でパスワードを消す4手順

Part 2 / 6 SSH接続の5方式を7軸比較(4方式実測)

パスワードを鍵に置き換える作業は4手順です。順番が決まっていて、入れ替えると自分が締め出されます。

鍵を作る、公開鍵をサーバーに置く、鍵だけで入れることを確かめる、それからパスワード認証を止める。3番目を飛ばして4番目をやると、次のログインから誰も入れません。

4手順を左から右へ並べた図。1 鍵を作る (ssh-keygen -t ed25519、秘密鍵と公開鍵の2ファイルができる)、2 公開鍵をサーバーに置く (ssh-copy-id、authorized_keys に追記し権限も直す)、3 鍵だけで入れることを確かめる (-o BatchMode=yes、ここを通るまで次に進まない。強調)、4 パスワード認証を止める (sshd -t、構文チェックを通してから reload)。手順2から赤い点線が下へ分かれ、「3 を飛ばして 4 をやる」→「次のログインから誰も入れない」→「別の経路から戻す (コンソール、クラウドのシリアルコンソール、コンテナなら docker exec)」と続く。下に「作業中の別セッションを開いたままにしておくと、この事故から自力で戻れる」

1. 鍵を作る

ssh-keygen -t ed25519 -C 'deploy@lab'

出来上がるのは2ファイルです。権限に差が付いているのが要点です。

-rw------- .ssh/lab        秘密鍵。自分だけが読める
-rw-r--r-- .ssh/lab.pub    公開鍵。誰に見せてもいい

公開鍵の中身はこの1行で、これをサーバーへ持っていきます。

ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIM7Pe6a2aRPUOdFf3CDF/hdYFY7Ctg75o7iDmRFoLnYa deploy@lab

末尾のコメントは動作に関係しませんが、authorized_keys に何行も並んだときにどの鍵を消せばいいかを決める唯一の手がかりになります。機械名と用途を入れておきます。

2. 公開鍵をサーバーに置く

ssh-copy-id は公開鍵を ~/.ssh/authorized_keys に追記して、ディレクトリとファイルの権限も直します。

ssh-copy-id -i ~/.ssh/lab.pub deploy@lab-target

手で置く場合も、やることは追記と権限です。sshd は既定 (StrictModes yes) で、authorized_keys とそこへ至る .ssh・ホームディレクトリに他人が書き込める権限が付いているか、所有者が本人 (か root) でないと、その鍵を無視します。グループが書き込める場合は OS で分かれます。本家の OpenSSH (Alpine で確認) はそれだけで無視し、Debian 系は追加パッチで緩めてあって、グループに自分以外の利用者が居るときだけ無視します。.ssh を 700、authorized_keys を 600 にしておけば、どちらでも確実です。無視されてもクライアント側にはエラーが出ず、理由はサーバーのログにしか残らないので、原因が分かりにくい失敗になります。

3. 鍵だけで入れることを確かめる

ここが飛ばされやすい手順です。BatchMode=yes を付けると、パスワードを聞かれる余地が無くなります。

ssh -i ~/.ssh/lab -o BatchMode=yes deploy@lab-target 'whoami; hostname'
鍵で入れた: deploy@3b66cc2d143e

これが返ったら、鍵だけで入れることが確定しました。ここを通るまで次の手順に進みません。

権限を緩めるとどうなるか

秘密鍵を 644 にして同じコマンドを打つと、こうなります。

@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @
Permissions 0644 for '.ssh/lab' are too open.
deploy@lab-target: Permission denied (publickey,password).

クライアント側が鍵を読むことを拒否しています。サーバーは何も悪くありません。鍵をコピーして持ち回ると権限が崩れるので、chmod 600 は転送のたびに確認します。

サーバー側の条件 (手順2) と並べると、権限が崩れたときにエラーが出る側が違います。

鍵の置き場と権限を手元とサーバーに分けた図。手元には ~/.ssh/lab (600、秘密鍵。-rw------- 自分だけが読める) と ~/.ssh/lab.pub (644、公開鍵。-rw-r--r-- 誰に見せてもいい) があり、公開鍵の1行がサーバーの authorized_keys へ追記される。サーバーには ~/.ssh/ (700) の中に authorized_keys (600)。sshd の既定 (StrictModes yes) では、authorized_keys・.ssh・ホームディレクトリが、他人が書き込めるか所有者が本人 (か root) でないとき、またはグループが書き込めるとき (Debian 系はグループに自分以外の利用者が居るときだけ) にその鍵を無視する。下の囲みは、手元側が「秘密鍵を 644 にすると、手元にエラーが出る (UNPROTECTED PRIVATE KEY FILE!)」、サーバー側が「無視されても、手元にはエラーが出ない。理由はサーバーのログにしか残らない」

4. パスワード認証を止める

ここまで来てはじめて、サーバー側を触ります。

# サーバー上で
printf 'PasswordAuthentication no\nKbdInteractiveAuthentication no\n' \
  > /etc/ssh/sshd_config.d/99-nopassword.conf
sshd -t && systemctl reload ssh

sshd -t は設定の構文チェックです。壊れた設定で reload すると sshd が上がってこないので、必ず先に通します。

反映は sshd -T で確認します。設定ファイルの中身より、sshd が最終的に何を採用したかを出力させるほうが確実です。

pubkeyauthentication yes
passwordauthentication no
kbdinteractiveauthentication no

止めた前後で何が変わったか

パスワードで入ろうとすると拒否されます。

deploy@lab-target: Permission denied (publickey).

ssh -vv で読む接続の5段階を実測の章で見た5段階の最後、括弧の中から password が消えました。パスワードが違うのではなく、選択肢として提示されていません。 同じ状態で鍵を使えば、そのまま入れます。

鍵なら入れる: deploy@3b66cc2d143e

パスワード認証を止めた前後を左右に並べた図。止める前の拒否メッセージは Permission denied (publickey,password) で、括弧の中は publickey と password の2つ。止めた後 (sshd -T が passwordauthentication no) は Permission denied (publickey) で、password が消えている。鍵で入るのはどちらも入れる (止めた後は deploy@3b66cc2d143e)。パスワードで入るのは、止める前は選択肢として提示され、止めた後は選択肢に出てこない。下に「パスワードが違うのではなく、選択肢として提示されていない」

鍵が増えたときに何が起きるか

ここまでは人が1人、機械が1台の話です。人数 × 台数に比例して authorized_keys の行が増えます。

問題は追加ではなく削除の側に出ます。人が抜けたとき、その人の公開鍵が載っている authorized_keys を全台から探して消す必要があり、消し忘れた1台が残ります。コメント欄を埋めておくのはこのためですが、手作業であることは変わりません。

この手間を減らす方向が2つあります。1つは踏み台を置いて、奥の機械へ届く入口を1台に絞ることです。奥の機械へ踏み台からしか届かないなら、人を外すときは踏み台の authorized_keys を直せば入口が閉じます。組み方はssh -J と config の差を踏み台で実測の章で扱いました。ただし奥の機械の authorized_keys には鍵が残るので、削除の手間そのものは消えません。もう1つは authorized_keys 自体を持たない方法で、Tailscale SSHと鍵ゼロ運用の3制約の章で扱います。