posts
VPSのSSHを点検したら、パスワードログインが有効のままで、使っていない鍵も残っていた
自動デプロイ用の秘密鍵をGitHubに上げてしまった件の後片付けで、このブログのGitHubリポジトリが公開(Public)になっていたことが分かりました(→ 秘密鍵をGitHubに上げてしまった話)。漏れた鍵が本当に使えなくなっているかを確かめるついでに、サーバーのSSHをひととおり点検しました。
結果はこうでした。
- 漏れた鍵は、ちゃんと使えない状態になっていた
- 第5回で止めたはずのパスワードログインが、有効のままだった
- 今はもう使っていない古いPCの鍵が、登録されたまま残っていた
「設定したつもり」と「実際に効いている設定」は違う、ということを思い知った点検でした。同じ構成でVPSを動かしている人は、一度確かめてみてください。
点検したこと
| 確かめること | 使ったコマンド(サーバーで打つ) | 結果 |
|---|---|---|
| パスワードでログインできないか | sshd -T | grep passwordauthentication |
yes だった → 直した |
| 登録されている鍵は何本か | ssh-keygen -lf ~/.ssh/authorized_keys |
3本。うち1本は今のPCに無い鍵 |
| どの鍵で何回ログインされたか | journalctl -u ssh |
知らない人の鍵は無かった |
| 更新が残っていないか | ログインしたときの表示 | 「再起動が必要です」と出ていた |
1. パスワードログインは本当に止まっているか
PowerShellで打って「認識されません」と言われた
最初、確認のコマンドを手元のPCのPowerShellで打ってしまい、こう言われました。
sshd : 用語 'sshd' は、コマンドレット、関数、スクリプト ファイル、
または操作可能なプログラムの名前として認識されません。
sshd は、サーバー(Ubuntu)の中で動いているSSHのプログラムです。手元のWindowsには入っていません。サーバーの設定を調べるコマンドは、ssh root@... でサーバーに入ってから打つ必要があります。今どちらにいるかは、行の先頭で見分けられます。
| 行の先頭 | 今いる場所 |
|---|---|
PS C:\Users\...> |
自分のPC(PowerShell) |
root@...:~# |
サーバーの中 |
sshd -T で「今効いている設定」を見る
サーバーに入って打ち直すと、こう出ました。
sshd -T | grep passwordauthentication
passwordauthentication yes
sshd -T は、設定ファイルを全部読み込んだうえで「実際に使われる値」を表示するコマンドです。ここが yes ということは、パスワードを知っていれば、誰でもrootでログインできる状態だったということです。
第5回の手順で、/etc/ssh/sshd_config の PasswordAuthentication は no にしていました。それなのに yes でした。
なぜ yes のままだったのか
Ubuntu 24.04の /etc/ssh/sshd_config は、先頭で /etc/ssh/sshd_config.d/ の中のファイルを読み込みます。そして同じ項目が何回も書かれていると、最初に読んだ値が使われます。
/etc/ssh/sshd_config
├ 先頭: Include /etc/ssh/sshd_config.d/*.conf ← ここを先に読む
│ (クラウドの初期設定のファイルに yes が書かれていることがある)
└ 後ろ: PasswordAuthentication no ← 後から読むので負ける
クラウドのVPSでは、サーバーを作るときの初期設定用のファイルが sshd_config.d の中に置かれ、そこに PasswordAuthentication yes が入っていることがあります。そうすると、本体の設定ファイルを no にしても、先に読まれた yes が勝ちます。
じつはこれ、第5回の注意点に「Ubuntu 24.04では sshd_config.d の方が優先されることがある」と自分で書いていました。書いておきながら、自分のサーバーで sshd -T を打って確かめていなかった、というのが正直なところです。
今回はまとめて直してしまったので、どのファイルに yes が書かれていたかまでは記録していません。直す前に確かめるなら、このコマンドで分かります。
grep -rn PasswordAuthentication /etc/ssh/sshd_config /etc/ssh/sshd_config.d/
直し方
サーバーで、1行ずつ打ちました。
sed -i 's/^\s*PasswordAuthentication\s\+yes/PasswordAuthentication no/' /etc/ssh/sshd_config /etc/ssh/sshd_config.d/*.conf
本体と sshd_config.d の中の、PasswordAuthentication yes と書かれた行を全部 no に書き換えます。
sshd -t && systemctl restart ssh
sshd -t(小文字の t)は、設定ファイルに書き間違いがないかの確認です。問題がなければ何も表示されず、そのままSSHを再起動します。
sshd -T | grep passwordauthentication
passwordauthentication no
no になりました。最後に、今の画面は閉じずに、新しいPowerShellを開いて ssh root@... で入れるかを確かめました。鍵で入れたので完了です。万が一入れなくても、元の画面がつながっていれば直せます。
パスワードが有効だと何が困るのか
インターネットにつながっているサーバーには、世界中から自動でパスワードを試してくるプログラムがひっきりなしにやって来ます。長いパスワードならすぐには破られませんが、パスワードログインを止めてしまえば、そもそも試す入口がなくなります。
どれくらい試されているかは、このコマンドで数えられます。
journalctl -u ssh --no-pager | grep -c "Failed password"
2. 登録されている鍵を棚卸しする
サーバーに登録されている鍵の「指紋」を出す
~/.ssh/authorized_keys は、「この鍵を持っている人はログインしてよい」という一覧です。鍵の中身は長いので、短い指紋(フィンガープリント)に変えて見比べます。
ssh-keygen -lf ~/.ssh/authorized_keys | awk '{print NR": "$2}'
1: SHA256:aaaa…(略)
2: SHA256:bbbb…(略)
3: SHA256:cccc…(略)
3本登録されていました(実際の指紋は伏せています)。
手元のPCの鍵と見比べる
次に、自分のPCのPowerShellで、手元にある鍵の指紋を全部出しました。
Get-ChildItem $env:USERPROFILE\.ssh\*.pub | ForEach-Object { ssh-keygen -lf $_.FullName }
結果はこうでした。
| サーバーの鍵 | 正体 |
|---|---|
| 2 | 今のPCの鍵(自分がログインするとき用) |
| 3 | 今の自動デプロイ用の鍵(GitHub Actions用) |
| 1 | 今のPCには無い鍵 |
そして、GitHubに漏れた古い鍵の指紋は、3本のどれとも一致しませんでした。漏れた鍵は、もう使えないことが確認できました。
正体の分からない1本を、ログで調べる
1番の鍵が誰のものか分からないので、ログイン記録を調べました。まず、どの鍵で何回ログインされたかを数えます。
journalctl -u ssh --no-pager | grep -o "Accepted publickey.*" | grep -o "SHA256:[A-Za-z0-9+/]*" | sort | uniq -c
| 鍵 | ログイン回数 |
|---|---|
| 2(今のPC) | 46回 |
| 3(今のデプロイ用) | 84回 |
| 1(正体不明) | 36回 |
| 漏れた古いデプロイ用の鍵(登録済みではない) | 56回 |
知らない指紋は出てきませんでした。もし誰かが漏れた鍵で入り込み、自分の鍵を勝手に追加していたら、ここに見覚えのない指紋が出てくるはずです。
続いて、1番の鍵がいつ使われたかを、日付ごとに数えました。
journalctl -u ssh --no-pager -o short-iso | grep "SHA256:aaaa…" | cut -c1-10 | sort | uniq -c
10 2026-08-28
2 2026-08-31
9 2026-09-05
4 2026-09-07
4 2026-09-08
6 2026-09-09
1 2026-09-12
最初に使われた8月28日は、ConoHaでSSHがつながらずハマって、鍵でログインする方式に切り替えた日です。9月上旬は、記事を手作業で公開していた時期。最後は9月12日で、それ以降は一度も使われていません。
当時は今と別のPCで作業していたので、1番はそのPCで作った、自分の古い鍵だと判断しました。
使っていない鍵は消す
自分の鍵だとしても、もう使わないPCの鍵が登録されたままだと、そのPCをなくしたり中を見られたりしたときに、サーバーへの入口になります。使っていないなら消すのが安全です。
cp ~/.ssh/authorized_keys ~/.ssh/authorized_keys.bak
まず、今の状態をコピーして取っておきます(元に戻せるように)。
grep -E "今のPCの鍵のコメント|github-actions" ~/.ssh/authorized_keys.bak > ~/.ssh/authorized_keys
authorized_keys の各行の最後には、鍵を作ったときのコメント(PC名や、自分で付けた名前)が付いています。残したい2本のコメントだけを指定して、その行だけを残しました。
ssh-keygen -lf ~/.ssh/authorized_keys | awk '{print NR": "$2}'
残したい2本だけが出れば成功です。うまくいかなかったときは、取っておいたコピーで戻せます。
cp ~/.ssh/authorized_keys.bak ~/.ssh/authorized_keys
ここでも、今の画面は閉じずに、別の画面で鍵ログインができることを確かめてから閉じました。
3. 更新と再起動
サーバーに入るたびに、こんな表示が出ていました。
53 updates can be applied immediately.
*** System restart required ***
セキュリティの更新が、入ったまま反映されていない状態です。点検の最後に、更新して再起動しました。
apt update && apt upgrade -y
systemctl reboot
再起動のあいだ(1〜2分)はサイトが見られなくなるので、アクセスの少ない時間にやるのがおすすめです。
同じ画面に New release '26.04.1 LTS' available. という、OSを丸ごと新しくする案内も出ていましたが、こちらはやっていません。設定ファイルが入れ替わってサイトが止まることがあるので、時間があるときに、バックアップを取ってから試すつもりです。
これからは月に1回点検する
今回、「設定したつもり」のまま1か月以上たっていました。月に1回、次の4つを確かめることにしました。
sshd -T | grep passwordauthenticationがnoになっているかssh-keygen -lf ~/.ssh/authorized_keysに、知らない鍵が無いかjournalctl -u sshのログイン回数に、知らない指紋が無いか- ログインしたときに、更新や再起動のお知らせが出ていないか
学んだこと
| つまずいたこと | 原因 | 学んだこと |
|---|---|---|
sshd が認識されない |
サーバーのコマンドをPCのPowerShellで打っていた | 行の先頭を見て、今どこにいるかを確かめる |
| パスワードログインが有効のままだった | sshd_config.d の中の yes が、本体の no より優先されていた |
設定したら sshd -T で「実際に効いている値」を確かめる |
| 知らない鍵が登録されていた | 昔のPCの鍵を消し忘れていた | 指紋とログイン記録で1本ずつ正体を確かめ、使わない鍵は消す |
| 更新が反映されていなかった | 再起動していなかった | 「System restart required」が出たら、早めに再起動する |
結果的に、外から入られた形跡は見つかりませんでした。それでも、パスワードログインが開いたままの状態が1か月以上続いていたのは、正直ひやっとしました。「設定した」で終わらせずに「効いているか確かめる」までを1セットにするようにしています。
あわせて読みたい
- 自動デプロイ用の秘密鍵をGitHubに上げてしまったので、鍵を作り直した話 — この点検のきっかけになった出来事
- 【第5回】環境づくり編 — SSH・ufw・Nginx・Hugoを準備する — 鍵でのログインと、パスワードログインを止める手順
- ConoHa VPSでSSH接続できずハマった話(セキュリティグループとufw、2つの関所) — SSHまわりでハマった、もう1つの記録