2023年5月初,我的Homelab发生了一次严重的运维事故。撰文以回忆和记述这次事故的前因后果同经验教训。
Homelab: 硬件概述
我的homelab在2023年5月时仅包含一台充当服务器的电脑和若干网络设备。这台电脑采用了许多生产和购买于不同时代的硬件。其主板已经使用了长达11年。1
老旧的硬件带来无尽的问题,主要集中在这块主板。
2018年时许,这块主板的用于存储BIOS(UEFI固件)的EEPROM损坏,在经过临时解决方案后在2020年通过更换芯片最终解决。2
更严重的是,这个主板的许多连接器严重地氧化了,包括DRAM插槽和PCIe插槽。3这些不能正常工作的连接器,让事故雪上加霜。(后文详述)
此外,事故发生时我并不在家,一般通过回家的VPN访问家中Homelab所托管的服务。然而这部电脑没有配备任何形式的带外管理(OOB Management) ——这台电脑的主板是一般台式机的主板,而非服务器主板,不具备BMC,故无法提供IPMI;它也不是商用机的主板,并不支持Intel vPro的主动管理技术(AMT);我也没有购买以PiKVM为代表的IP-KVM实现。没有带外管理,也堵死了另一条应对本次事故的可能方案。
事发
2023年5月4日,我例行更新Homelab中的服务器(运转Arch Linux)上的软件。pacman
提示道一些软件包有新的配置文件,然而我本地的对应的配置文件有修改过,不是发行版提供的旧版本,故未进行直接覆盖,而是以.pacnew
后缀保存。形如:
warning: /etc/sudoers installed as /etc/sudoers.pacnew
这种问题我时常遇到,我一般的处置方法是,用diff
(或图形化的meld
,如果有桌面环境)比较其差异并合并之。然而,这次我误删除了一个.pacnew
文件,这个文件属于PAM, (Pluggable Authentication Modules) 是系统的关键组件。在现时(2024年5月)用pacman
检视此包,可见我的服务器上许多关键组件(systemd
, polkit
, sudo
, openssh
)依赖它。
leo@Nebulas:~
$ pacman -Qi pam
Name : pam
Version : 1.6.1-2
Description : PAM (Pluggable Authentication Modules) library
Architecture : x86_64
URL : http://linux-pam.org
Licenses : GPL-2.0-only
Groups : None
Provides : libpam.so=0-64 libpamc.so=0-64 libpam_misc.so=0-64
Depends On : glibc libtirpc pambase audit libaudit.so=1-64 libxcrypt
libcrypt.so=2-64 libnsl
Optional Deps : None
Required By : kbd libcap libpwquality openssh polkit qemu-img qemu-system-aarch64
qemu-system-riscv qemu-system-x86 screen shadow sudo systemd
util-linux
Optional For : None
Conflicts With : None
Replaces : None
Installed Size : 3.20 MiB
Packager : Tobias Powalowski <tpowa@archlinux.org>
Build Date : Thu 11 Apr 2024 08:47:57 AM UTC
Install Date : Thu 11 Apr 2024 10:26:02 AM UTC
Install Reason : Installed as a dependency for another package
Install Script : No
Validated By : Signature
理论上我有更高明的办法找到这个配置文件的新版本,比如将pacman cache里的这个包的新版本解压缩并提取对应文件。但我不知怎么,想到将这个包完全卸载再重新安装来使这个配置文件重新被创建。
我起初尝试用pacman -R pam
来卸载,但由于依赖问题,pacman
不允许我这样做。于是我又尝试pacman -Rdd pam
来让pacman
忽略任何依赖关系而强行卸载。
这次卸载成功了,但问题也很快出现了——当我再运转pacman -S --asdeps pam
时,sudo
却无法使用了,提示缺少一些库——正是pam
包所提供的。我又尝试另起一个SSH会话连接到服务器,发现无法连接,出现鉴权失败相关的错误——这意味着,如果我现有的这个SSH会话断开,我将甚至无法连接到这个服务器了。
后来我又做了多种尝试,包括解开pam
包提取相关.so
文件并LD_PRELOAD
等,皆未有成功修复。而在将服务器关机后,我仍不死心,电话联系母亲请求帮忙再开机后,却发现主机甚至无法ping通了——大概是因为systemd
也依赖PAM,因而systemd
的init
无法运转起来吧… (回家后我排除故障时证实了这个猜想,后文详述)
事态恶化
到此,我仍没有意识到事态严重——这个故障大概用archiso
启动后,挂载主机的rootfs并用pacstrap
重新安装pam
包便可解决了。正巧我有一个自己修改的archiso
,其默认启用了sshd.service
并包含我的SSH公钥,一旦这个修改的archiso
能成功启动,我便能透过SSH连接上去,完成上述操作。
我于是又请求我母亲帮助将一个U盘插入我的另一个可以用SSH连接的Raspberry Pi 4以烧写archiso
,再请求她将主机连接到这个U盘,键盘和家里的电视,以启动archiso
。但不曾想,电视无论如何都无法识别到HDMI信号,甚至我又请求母亲为该主机安装一块”亮机显卡”并将电视接到该显卡上,仍不能看到任何画面。这大概时因为这块主板上的HDMI接口和PCIe接口都氧化严重导致的。
到这时我才有些慌了,不过幸运的是我将在不久的五月中旬回家,到时便可亲自排除故障。
解决
回家后我反复插拔”亮机显卡”多次,终于得以看到其输出的显示画面——开机时,systemd init
无法初始化并进入rescue shell
,原因正是缺失的PAM库。随后我便用U盘启动archiso并按上一章节所述方法完成修复,系统重新正常运转;经检验,文件未有损毁。算是不幸中的万幸了。
原因与教训
这起运维事故涉及多重原因,其中一些制造了事故,另一些让状况更糟
- 我不应该进行”忽略依赖关系而卸载” (
pacman -Rdd
)这样的危险操作——更糟糕的是,尽管我知道这是一个危险的和应被避免的操作,我还是曾多次这样做——也许先前几次卸载的不是什么关键的软件包,便没有造成严重后果,我也因此更加松懈安全意识。这是事故发生的直接原因和首要原因。 - 其次地,没有带外管理机制迫使我麻烦母亲帮忙实施带内操作。
- 再次地,严重老化的硬件和氧化腐蚀的连接器令带内操作变得难以实现。
经以上分析,我采取相关应对措施如下:
- 强化安全与合规操作之意识,杜绝冒险操作和反模式。(anti-pattern)
- 活用drop-in configuration4以尽可能避免修改发行版提供的配置文件
- 更换老旧硬件,以带有BMC的服务器主板等替代。BMC可提供IPMI供带外管理用。
后记
2024年1月某日夜,我的两台服务器(2023年5月底,新购硬件以替代旧有的一台,2023年12月,新加购一台)中有一台因不正确地修改systemd-boot
配置(与GVT-g相关的kernel cmdline)而无法引导启动。现时,两台服务器皆有IPMI可用,我便用IPMI加载archiso
在约10分钟里完成了修复。
- 该系统的机箱,电源,散热器,硬盘和阵列卡(RAID Controller)系近年购买。但主板和内存则购买于11年前的2012年3月,分别是华硕P8Z77-V LK,2条三星的4GiB DDR3 1600MHz (non-ECC)和2条十铨的4GiB DDR3 1600MHz (non-ECC),共计16GiB内存。 ↩︎
- EEPROM损坏造成了Intel ME固件损毁,iGPU不可用,后来使用AMIBCP强行烧写暂时解决了这个问题。在我的技术博客(现已关闭)中有一篇文章记录了这个事件。后来相同问题再次发生,尝试用编程器烧写固件,烧写后无法通过校验。更换EEPROM芯片并重新烧写后问题解决。 ↩︎
- 2022年9月这台电脑的内存接触不良,突然死机,强制重启后无法运转。反复插拔内存数次后侥幸恢复正常(可能是反复插拔磨去了插槽的触点和/或金手指上的氧化层),感谢坚强的日志式文件系统,数据安然无恙,没有因为异常卸载而损毁。 ↩︎
- 例如,当需要修改SSH服务器的设置时,不要直接修改
/etc/ssh/sshd_config
,而是将修改置于/etc/ssh/sshd_config/01-security-hardening.conf
↩︎
linux操作需谨慎 我手里也有好几台机器 测试更新完没有问题 才会在新机器上使用
先测试在应用于生产环境确实是一个好方法。当然,严格避免违规操作的意识也是不可缺少。