sshd 加固
目标
用 drop-in 配置文件对 sshd 进行加固,用 sshd -t 和 sshd -T 验证之后,实际确认密钥连接仍然可用,而密码认证会被拒绝。
为什么重要
修改远程服务器的 sshd,就像锯掉自己正坐着的树枝。所以顺序是固定的:保持会话 → 修改 → sshd -t → 重新加载 → 用新会话确认 → 最后才关闭原有会话。而且现在的发行版用 Include /etc/ssh/sshd_config.d/*.conf 把配置拆分成片段。同一个键出现多次时第一个值生效,所以“改了却没生效”很常见。养成用 sshd -T 确认最终生效值的习惯,就能从根源上杜绝这个问题。\n\n## 本实验在虚拟机中运行\n\n由于 sshd 是作为真正的 systemd 服务运行的,所以可以用 systemctl reload ssh 让它重新读取配置,并用新会话连接来确认。以前是在 Pod 中运行的,没有 systemctl,必须用 pkill sshd 直接操作进程。\n\n搭建环境时,已经提前处理好了一件事。Ubuntu 24.04 开启了 ssh.socket,在这种状态下,监听哪个端口由 systemd 决定——sshd_config 中的 Port 会被忽略。修改配置并重启后,仍然只监听 22 号端口,而且既没有错误也没有警告。为了打开实验用的 2222 端口,已经关闭了 socket 激活,并启用了 ssh.service。在真实服务器上,如果遇到“改了端口却打不开”,请先看这里。\n\n22 号端口保持不变。这是为了即使配置写错,也能留有退路——在真实服务器上,出于同样的理由,也是先打开新端口并确认,然后再关闭旧端口。
步骤
- 创建目录
/root/harden,并把当前生效的全部配置保存到/root/harden/baseline.txt。 - 创建
/etc/ssh/sshd_config.d/90-labhub.conf,并写入下列值。PasswordAuthentication no、KbdInteractiveAuthentication no、PubkeyAuthentication yes、MaxAuthTries 3、LoginGraceTime 30、X11Forwarding no、PermitEmptyPasswords no、LogLevel VERBOSE - 执行语法检查,确认通过,并把退出码以
rc=0的形式写入/root/harden/syntax.txt。 - 在最终生效值中,只挑出
passwordauthentication、kbdinteractiveauthentication、maxauthtries、logingracetime这四行,保存到/root/harden/effective.txt。 - 在同一个文件末尾添加
Match User backup块,写入ForceCommand internal-sftp和AllowTcpForwarding no。然后把该条件下的生效配置保存到/root/harden/match.txt。文件中必须能看到forcecommand internal-sftp。 - 在
/root/.ssh/authorized_keys中,给包含id_labhub密钥的那一行,在最前面加上restrict,pty,from="127.0.0.0/8"选项。(必须重新开启 pty,shell 连接才能保持。) - 重新启动 sshd,然后确认两件事。
- 密钥连接仍然成功 → 把结果保存到
/root/harden/still-works.txt - 只请求密码认证时会被拒绝 → 把该错误输出保存到
/root/harden/password-denied.txt
- 密钥连接仍然成功 → 把结果保存到
- 把
/root/harden/checklist.txt写成下面这 5 行。值以sshd -T的输出为准。passwordauthentication=no/kbdinteractiveauthentication=no/pubkeyauthentication=yes/maxauthtries=3/logingracetime=30
参考
sshd -t是语法检查,sshd -T输出生效配置,sshd -T -C user=backup,host=x,addr=127.0.0.1是按条件的生效配置。- sshd 以
pkill -x sshd; sleep 1; /usr/sbin/sshd的形式重新启动。实验环境中的 sshd 已经配置好了 2222 端口。 - 确认密码认证被拒绝,用
ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no -p 2222 root@127.0.0.1 true。请保存失败信息。 - 常见错误 1:在第 6 步只加了
restrict,没有重新开启pty,导致 shell 连接失效。 - 常见错误 2:在第 7 步只杀掉了 sshd 而没有重新启动,导致之后的步骤全部失败。
记录当前生效配置
创建目录 /root/harden,并把当前生效的全部配置保存到 /root/harden/baseline.txt。
sshd 有输出全部最终生效值的扩展测试模式。它与语法检查是不同的选项。
编写 drop-in 配置
创建 /etc/ssh/sshd_config.d/90-labhub.conf,并写入下列值。
PasswordAuthentication no、KbdInteractiveAuthentication no、PubkeyAuthentication yes、MaxAuthTries 3、LoginGraceTime 30、X11Forwarding no、PermitEmptyPasswords no、LogLevel VERBOSE
在 sshd_config.d 之下创建 .conf 文件。文件名前面的数字决定读取顺序。
语法检查通过
执行语法检查,确认通过,并把退出码以 rc=0 的形式写入 /root/harden/syntax.txt。
只检查语法的选项在成功时不会输出任何内容。请以退出码来判断。
确认生效值
在最终生效值中,只挑出 passwordauthentication、kbdinteractiveauthentication、maxauthtries、logingracetime 这四行,保存到 /root/harden/effective.txt。
扩展测试模式的输出,键全部是小写。请只挑出需要的四个。
Match 块的条件生效
在同一个文件末尾添加 Match User backup 块,写入 ForceCommand internal-sftp 和 AllowTcpForwarding no。然后把该条件下的生效配置保存到 /root/harden/match.txt。文件中必须能看到 forcecommand internal-sftp。
扩展测试模式有指定连接条件的选项。user、host、addr 三个值用逗号连接。
强化 authorized_keys 选项
在 /root/.ssh/authorized_keys 中,给包含 id_labhub 密钥的那一行,在最前面加上 restrict,pty,from="127.0.0.0/8" 选项。(必须重新开启 pty,shell 连接才能保持。)
要同时使用限制来源的选项和关闭全部功能的选项。必须允许回环网段,连接才能保持。
先确认一件事: 这一步要处理 ~/.ssh/id_labhub 密钥。该密钥是在上一个实验(SSH 密钥认证)中创建的,由于每次实验都会启动一个新的环境,所以这里并没有它。请用 ls ~/.ssh 确认,如果没有,就先创建。
ssh-keygen -t ed25519 -N '' -f ~/.ssh/id_labhub
cat ~/.ssh/id_labhub.pub >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
重启后的实际验证
重新启动 sshd,然后确认两件事。
- 密钥连接仍然成功 → 把结果保存到
/root/harden/still-works.txt - 只请求密码认证时会被拒绝 → 把该错误输出保存到
/root/harden/password-denied.txt
要让配置生效,必须重新启动 sshd。这个环境中没有 systemctl,所以请直接操作进程。
加固检查清单
把 /root/harden/checklist.txt 写成下面这 5 行。值以 sshd -T 的输出为准。
passwordauthentication=no / kbdinteractiveauthentication=no / pubkeyauthentication=yes / maxauthtries=3 / logingracetime=30
值直接从 sshd -T 的输出中取用即可。请统一为小写。