SSH のパスワード認証は、普通のサーバーが持つ最大の露出面です。それに対しては Fail2ban もどんな閾値も役に立ちません。一時間に一回ずつ試す千のアドレスは決して上限に届かず、推測が可能であるかぎりずっと推測し続けます。鍵はその可能性そのものを取り除きます。hardening の一覧全体の中で、状況を質的に変える設定はこれ一つだけです。
怖いのは一点だけ、パスワードを切って自分が外に取り残されることです。以下はそれが起こり得ない順序です。
鍵
サーバー上ではなく、自分のマシンで生成します。
ssh-keygen -t ed25519 -C "work laptop"
RSA ではなく ed25519 を。短く、速く、長さの問題もありません。RSA が必要なのは、とても古い何かに届かせる必要があるときだけです。そのときは -t rsa -b 4096。
鍵にパスフレーズを設定する価値はあります。鍵ファイルはノートパソコンから盗まれ得ますし、パスフレーズが無ければそれは即座に使えてしまいます。毎回入力する必要はありません——それは ssh-agent が引き受けますし、macOS と多くのデスクトップ Linux ではすでに動いています。
パスワードがまだ効くうちなら、サーバーへのコピーはコマンド一つです。
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@203.0.113.25
ssh-copy-id が無ければ、.pub ファイルの中身をサーバーの ~/.ssh/authorized_keys に一行として追記します。権限が重要です。.ssh ディレクトリは 700、ファイルは 600、所有者はそのユーザー。それ以外だと sshd は黙ってファイルの読み込みを拒みます。これが「鍵が効かない」の最も多い原因です。
すべてを決める確認
何かを切る前に、最初の接続を閉じずに二つ目を開いてください。
ssh -o PasswordAuthentication=no user@203.0.113.25
このオプションはクライアントがパスワードへ戻ることを禁じます——つまりログインできたなら、それは鍵でできたということです。このコマンドが通るまで先へ進まないでください。そして最初の接続は最後まで開けたままに。あなたが壊しかけたものを直せるのは、それだからです。
パスワードを切ること、そして目立たない落とし穴
設定はパッケージ更新に上書きされないよう別ファイルへ置きます。ただしファイル名が重要です。
sudo tee /etc/ssh/sshd_config.d/10-hardening.conf <<'EOF'
PasswordAuthentication no
PermitRootLogin no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
MaxAuthTries 3
LogLevel VERBOSE
EOF
要点は、OpenSSH がパラメータについて採用するのは、ほぼどこでもそうであるような最後の値ではなく最初に得た値だということです。sshd_config.d のファイルはアルファベット順に読まれ、Ubuntu のクラウドイメージはそこに 50-cloud-init.conf を置きます。そしてそれには PasswordAuthentication yes が入っていることがよくあります。その状況では 90 番のあなたのファイルは何もしません。設定はできているように見えて、パスワードは効き続けます。数字の 10 はここから来ています——そちらが先に読まれるのです。
実際に何が有効になったかは、推測せずに確認できます。
sudo sshd -T | grep -Ei 'passwordauth|permitrootlogin|pubkeyauth'
このコマンドはすべての include を経た後の実効設定を表示します。ファイルの中身ではなく、これを信じてください。
続いて構文の確認と、サービスの穏やかな読み直し。
sudo sshd -t && sudo systemctl reload ssh
sshd -t は必須です。設定の打ち間違いと restart の組み合わせは、サービスを落としてあなたを外に置き去りにします。reload なら開いているセッションも切りません。
Ubuntu 24.04:ポートは思っている場所にない
最近の Ubuntu には別の落とし穴があります。そこでは sshd は systemd のソケット経由で起動されます。そのモードでは sshd_config の Port 行は何もしません——待ち受けているのはデーモンではなくソケットです。ポートを変えるなら編集すべきはこちらです。
sudo systemctl edit ssh.socket
そして ListenStream=(空の値が以前の値をリセットします)に新しいポートを書きます。それを明かす症状は、設定を変えてサービスを再起動したのにサーバーがまだ 22 で応答することです。
ポート変更のついでに言えば、防御としてそれは機能しません。スキャナはどのポートでも数分でサービスを見つけます。唯一の効果はログが静かになることです。大量の推測は 22 にしか来ないからです。それは便利ですが、安全性と混同しないでください。
そもそも誰がログインしてよいのか
有用な補足は明示的な一覧です。
AllowUsers deploy admin
一覧に無いものは鍵が確認される前に切られます。これは、あるパッケージがシェルとホームディレクトリつきのシステムユーザーを作ってしまう場合もついでに覆います。
予備の入口
一台のノートパソコンにある一つの鍵は単一障害点です。ディスクが壊れ、ノートを失えば、サーバーは永久に手の届かないものになります。妥当な最低限は:
- 別の端末からの二つ目の鍵を
authorized_keysに; - 秘密鍵の控えをパスワード管理ソフトか暗号化した USB メモリに;
- 試したことのあるプロバイダーのコンソールアクセス——VNC またはシリアル。試したというのは、少なくとも一度はそれでログインしたという意味であり、「パネルのどこかにボタンがある」ではありません。
ついでに authorized_keys にすでに何があるかも見てください——自分のユーザーの分も root の分も。そこにある他人の鍵は、どんなパスワード変更も生き延び、有効なアクセスであり続けます。
その後
パスワードの推測が無くなることはありません。ただ無意味になるだけです。ログには Failed password の行が何千と残り続けますが、そのどれ一つとして成功で終わることはできません。これから見る価値があるのは成功したログインです。どのアドレスから、どのユーザーで、何時に。見知らぬアドレスからの鍵による成功ログインは、百万回の失敗よりはるかに重要な出来事であり、そして全体の流れの中でははるかに気づきにくいものです。下のデモページが示すのはまさにその図です。