服务器只配置一次,之后便自己过日子。一个月后,一部分软件包在等待升级,证书已经逼近到期前三周,装了某个不相干的东西之后 SSH 配置里多出一行,而本该盯着登录的 jail 已经停了,却没人知道。这些都不会喊叫,只是悄悄地不再为真。
下面是十二件值得定期检查的事,附带命令。走一圈大约十五分钟。顺序从别人进来的地方,走到会自己坏掉的地方。
SSH:五行
要看的不是文件,而是生效的配置:它由 /etc/ssh/sshd_config、整个 sshd_config.d 目录以及编译时的默认值拼成。
sudo sshd -T | grep -iE 'permitrootlogin|passwordauthentication|permitemptypasswords|maxauthtries|x11forwarding'
我们希望看到:permitrootlogin no、passwordauthentication no、permitemptypasswords no、maxauthtries 在 3–4 之间,以及 x11forwarding no。前三行是门,后两行是门的合页——每次连接的尝试上限,以及服务器根本用不上的图形转发。
两点提醒,都是把自己锁在门外的简便办法。第一:在确认密钥可用之前,不要关掉密码登录和 root 登录——要在另一个会话里确认,且不关闭当前会话。如果你此刻正以 root 身份用密码登录着读这段话,那两行关在门外的恰好是你。
第二:文件的顺序。OpenSSH 取它最先遇到的那个参数值,而 sshd_config.d 里的文件按字母顺序读取。云镜像通常会在那里留下 50-cloud-init.conf,如果你把自己的文件命名成 90-hardening.conf 之类,它就会压过你的。自己的设置应放在更小的编号下——00- 或 10-。结果则用 sshd -T 检查,而不是去读文件。
防火墙:一项检查
sudo ufw status verbose
这里要记住,这份输出显示的是意图,不是结果。一条规则可以躺在列表里却什么也没关上:UFW 本身是关着的;端口由 Docker 发布的东西占着(它把自己的规则写进 UFW 下面的 iptables);或者流量根本是从别的路径到达服务器的。所以值得把规则列表与真正对外监听的东西对照一下:
sudo ss -tulpn | grep -v '127.0.0.1\|::1'
fail2ban:两项检查
服务在跑还不够,还得有一个为 SSH 工作的 jail。
sudo fail2ban-client status
sudo fail2ban-client status sshd
这里最常见的麻烦是沉默的 jail。在 Debian 12 和较新的 Ubuntu 上,/var/log/auth.log 可能根本不存在:没有安装 rsyslog,记录只活在 journald 里。使用出厂 logpath 的 jail 这时照样启动,照样报告自己处于活动状态,却永远不封任何人。治法是把它指向 systemd 日志:
printf '[sshd]\nenabled = true\nbackend = systemd\n' | sudo tee /etc/fail2ban/jail.d/sshd-systemd.local
sudo systemctl restart fail2ban
不用翻配置就能识破它的迹象:fail2ban-client status sshd 里「Currently failed」和「Total failed」停在零,而日志里明明有失败的登录。
更新:三项检查
分开看:一共有多少包在等待,其中多少与安全有关,以及内核更新之后系统是否要求重启。
sudo apt update
apt list --upgradable 2>/dev/null | grep -c -- '-security'
ls /var/run/reboot-required 2>/dev/null && echo '需要重启'
第三项检查是自动安全更新是否开着,免得前两项变成每月一次的仪式:
systemctl status unattended-upgrades --no-pager
cat /etc/apt/apt.conf.d/20auto-upgrades
那个文件的两行都应当是 1。如果没装这个包:sudo apt install unattended-upgrades && sudo dpkg-reconfigure -plow unattended-upgrades。
证书:一项检查
Let's Encrypt 证书的寿命是九十天,续期通常自己就能跑,一直跑到它不跑的那一天为止。要看的不是注册商的面板,而是服务器实际提供的东西:
echo | openssl s_client -connect localhost:443 -servername example.com 2>/dev/null | openssl x509 -noout -enddate
sudo certbot renew --dry-run
第一条命令给出为该名称提供的证书的到期日期;第二条在不等真正期限的情况下确认续期能够通过。值得把服务器承载的所有名称都走一遍,而不只是主域名:被忘掉的往往是后来加上的子域名。
磁盘:一项检查
df -h
df -i
两条命令,因为空间和文件记录是各自独立耗尽的。在大多数服务器上,后者先撞到天花板——PHP 会话或应用缓存里的数百万个小文件会让 IUse% 达到 100,而磁盘上还空着好几个 GB。关于这两种情况,我们另有一篇专文。
这份清单的问题在哪
清单是对的,但它有一个性质:需要有人记得它。每周十五分钟并不多——前提是服务器只有一台,而且还有由头。两个月风平浪静之后,这一圈就被跳过了,而 jail 停了的消息,是从别人的日志里得知的。
所以我们把这十二项检查原样收进了一个独立的免费面板——Arcivéo FREE。它一条命令即可安装,跑在你自己的服务器上,不向我们发送任何东西,也不需要注册。采集器由 cron 每五分钟运行一次,把同样的内容写进本地数据库:SSH 登录与被拒绝的连接、UFW 与 fail2ban 的状态、待安装的安全更新、证书的期限、磁盘空间。历史保留七天,界面有 34 种语言。价格为零,用于工作服务器也是如此:许可允许把面板装在自己的机器上,包括公司的机器,不允许转售,也不允许作为服务为别人的服务器运行。
免费版的技术栈很朴素:它安装并启用 UFW 和 fail2ban,此后便展示状态。ModSecurity、Suricata、AIDE 以及其余模块不在其中,那些属于付费版。但若只是想不再把每周那一圈装在脑子里,它已经够用。同样的数据在完整面板上是什么样子——见下方的演示页面。