sshdハードニングの順序と検証
一言でいうと
sshdの設定を変えるときに最も重要なのは、どの値を入れるかではなく、どの順序で確認するかです。間違えると、自分自身を締め出してしまいます。
なぜ必要なのか
リモートサーバーのsshd設定を変更することは、乗っている木の枝を切ることと同じです。設定が間違っているとsshdが起動せず、起動しなければ入る方法がありません。コンソールにアクセスできないクラウドインスタンスなら、インスタンスを丸ごと作り直す必要が出るかもしれません。
そのため、手順があります。
- 現在のセッションを維持したまま、新しいターミナルをもう1つ開いておきます
- 設定ファイルを修正します
sshd -tで構文を検査します- サービスをリロードします
- 既存のセッションを閉じずに、新しいターミナルで接続を確認します
- 確認が終わったあとにだけ、既存のセッションを閉じます
3つ目と5つ目を飛ばす人が、本当に多いです。そして、そのうちの一部が明け方にデータセンターへ向かいます。
どう動くのか
検査コマンドは2つあります。
sshd -t # 문법만 검사
sshd -T | sort | head -40 # 실제 적용될 유효 설정 전체 출력
sshd -T -C user=deploy,host=10.0.3.14,addr=10.0.3.14 | grep -i 'passwordauth\|pubkey'
-tは構文だけを見ます。-Tは最終的に適用される値をすべて表示します。この違いが重要なのは、最近のディストリビューションが設定を分割するからです。
Include /etc/ssh/sshd_config.d/*.conf
同じキーが複数回現れると、sshdは最初の値を使います。そのため、Includeがファイルの前のほうにあれば断片ファイルが勝ち、後ろのほうにあれば本体が勝ちます。「確かに変更したのに効かない」の半分は、ここから来ます。-Tで確認する習慣が、この問題を根本から断ちます。
推奨設定と、各値の意味です。
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
MaxAuthTries 3
LoginGraceTime 30
ClientAliveInterval 300
ClientAliveCountMax 2
AllowGroups sshusers
X11Forwarding no
PermitEmptyPasswords no
LogLevel VERBOSE
PermitRootLoginのデフォルトはprohibit-passwordです。デフォルトの状態でも、rootのパスワードログインはすでに遮断され、鍵によるログインは許可されています。完全に遮断するにはnoです。PasswordAuthenticationのデフォルトはyesです。鍵認証に切り替えたなら、必ず明示的にnoへ変更する必要があります。KbdInteractiveAuthenticationのデフォルトもyesです。パスワードを遮断したつもりなのに、この経路で入れてしまう場合があるので、一緒にオフにします。古い名前のChallengeResponseAuthenticationは、廃止されたエイリアスです。MaxAuthTriesのデフォルトは6です。失敗がこの値の半分に達すると、そのときからログに記録されます。LoginGraceTimeのデフォルトは120秒です。ログインできなかった接続を長く維持しないように、短くするほうがよいです。LogLevel VERBOSEは、認証に使われた鍵のフィンガープリントをログに残します。監査要件があれば、事実上必須です。
Matchブロックで例外を作ります。
Match Group sftponly
ChrootDirectory /srv/sftp/%u
ForceCommand internal-sftp
AllowTcpForwarding no
Matchは、条件が合うと、次のMatchまたはファイルの末尾までの設定を上書きします。同じキーワードが複数のMatchで満たされると、最初のものだけが適用されます。順序が結果を変えるので、sshd -T -C ...で必ず検証します。
現場での姿
接続できないときの層別の診断。3つのメッセージの区別が、診断の半分です。
Connection refused→ デーモンが起動していませんConnection timed out→ 経路が塞がっていますPermission denied (publickey)→ 接続でき、認証で失敗しました
そしてssh -vvvを読むコツです。debug1: Connecting toまで進めなければ、ネットワークの問題で、Offering public keyのあとにAuthentications that can continueが繰り返されるなら、サーバーがその鍵を拒否したのです。
締め付けて、自分自身を締め出さない方法
sshdの設定を締める作業は、自分自身を外へ追い出してしまいかねない、数少ない作業の1つです。順序を守れば、その危険はなくなります。
今のセッションを絶対に切りません。sshdを再起動しても、すでに確立された接続は維持されます。ですから、そのセッションを生かしたまま、新しいウィンドウで接続を試します。通ればそのときに元のセッションを閉じ、通らなければ元のセッションで元に戻します。
sshd -t # 문법 검사. 통과해야 재시작한다
systemctl reload sshd
ssh -o BatchMode=yes user@host true # 다른 창에서
設定ファイルを2か所とも見ます。最近のディストリビューションは/etc/ssh/sshd_config.d/*.confを読み込み、先に出た値が勝ちます。本体のファイルを変更したのに効かないなら、ドロップインが先に決めているのです。
sshd -T | grep -iE 'permitrootlogin|passwordauth|pubkeyauth|port'
sshd -Tは実際に適用される値を表示します。ファイルを読むより、こちらのほうが正確です。
一度にすべてを締めません。パスワード認証をオフにする前に、全員が鍵で入れるかを先に確認します。確認せずにオフにすると、その瞬間から入れない人が出て、その事実を、その人が必要なときに知ることになります。
ポートを変えるのは、セキュリティではなくノイズの削減です。自動スキャンのログは減りますが、実際の攻撃は防げません。代わりに、ファイアウォールで接続できる接続元を制限したり、fail2banで繰り返しの失敗を遮断したりするほうが、実効があります。
本当に価値が大きい3つは、これです。
| 設定 | 効果 |
|---|---|
PasswordAuthentication no |
ブルートフォース攻撃が通用しない |
PermitRootLogin no |
アカウント名をもう1つ突き止める必要がある |
AllowGroups ssh-users |
新しいアカウントが自動でログイン権限を得ない |
コンソールへのアクセスを確保しておきます。クラウドのシリアルコンソールやIPMIで入れるかどうかを、事前に確認します。sshでしか届かないサーバーでsshdの設定を締めるのは、元に戻す道がない作業になります。
次のラボですること
drop-in設定ファイルでsshdをハードニングし、sshd -tとsshd -Tで検証します。Matchブロックを作って条件付きの適用まで確認し、最後に、鍵での接続は引き続き通り、パスワード認証は拒否されるかを、実際に試します。