裸金属物理机安全加固实战:一次未签名内核模块导致panic的深度排查笔记

事故现场:新网卡驱动秒崩系统

凌晨3点,监控告警:某台裸金属物理机(IP: 10.88.12.77)心跳丢失,业务全挂。登录BMC后看到黑底白字的panic堆栈——Kernel panic - not syncing: loading out-of-tree module taints kernel. 模块名:ixgbe_custom。管理员在2小时前刚刚编译安装了一款第三方网卡驱动,以为是提升吞吐量的神兵,结果成了自杀炸弹。

根因定位:签名缺失 + 内核配置漏洞

裸金属物理机相比虚拟化实例,直接操作硬件时更容易触碰到内核模块边界。这台机器的内核在编译时关闭了MODULE_SIG_FORCE(允许强制加载未签名模块),但开启了MODULE_SIG(签名检查)。当加载的模块被标记为“taited”(被污染)时,内核会触发panic,因为安全策略module.sig_enforce被设置为1(通过grub参数传入)。实际检查/proc/cmdline

cat /proc/cmdline
BOOT_IMAGE=/vmlinuz-5.10.0-amd64 root=/dev/sda1 ro console=tty0 module.sig_enforce=1

结果:module.sig_enforce强制了签名,但模块未签名,内核直接panic。

加固三板斧:从签名到强制策略

1. 创建并签署内核模块

使用openssl生成自签名X.509证书,并注册到MOK(Machine Owner Key)数据库:

# 生成密钥和证书
openssl req -new -x509 -newkey rsa:2048 -keyout MOK.priv -outform DER -out MOK.der -days 3650 -subj "/CN=My Module Signer/"
# 注册到MOK
sudo mokutil --import MOK.der
# 重启后根据提示设置密码完成注册
sudo reboot

注册完成后,对模块签名:

sudo /usr/src/kernels/$(uname -r)/scripts/sign-file sha256 ./MOK.priv ./MOK.der ixgbe_custom.ko

验证签名:

modinfo ixgbe_custom.ko | grep sig
sig_id: PKCS#7  
signer: My Module Signer

2. 固化内核签名强制策略

/etc/default/grub中添加module.sig_enforce=1并锁定grub:

GRUB_CMDLINE_LINUX="module.sig_enforce=1"
# 额外加固:禁止grub参数被未授权修改
sudo grub2-setpassword
sudo grub2-mkconfig -o /boot/grub2/grub.cfg

3. 配合Secure Boot 和 BMC锁定

裸金属物理机的硬件级防线比软件更有效。我们使用的轻云互联裸金属服务器在BIOS中默认已开启UEFI Secure Boot,且BMC管理网口通过VLAN隔离,仅允许内网IP访问。这使得从固件层到启动链的签名验证成为闭环。检查Secure Boot状态:

mokutil --sb-state
SecureBoot enabled

若需临时维护,可用物理访问或BMC串口解锁,但日常必须开启。

纵深加固:不止模块签名

这次panic也暴露了其他安全基线的缺失。趁此机会,我们补完裸金属物理机的标配加固项:

  • 禁用USB Storageecho "install usb-storage /bin/false" > /etc/modprobe.d/block-usb.conf
  • 锁定内核模块名单/etc/modprobe.d/blacklist.conf 中添加 blacklist r8169 等不必要网卡驱动。
  • 强制审计:加载auditd并监控init_module系统调用:
auditctl -w /sbin/insmod -p x -k module_load
auditctl -a always,exit -F arch=b64 -S init_module -k kernel_module

同时启用sysdig实时捕获异常模块加载行为:

sysdig -c module_loads

经验总结

裸金属物理机安全加固的核心在于“硬件信任链 + 内核强制策略”。不要迷信“物理机安全天然好”——硬件漏洞(如BMC)和内核模块污染都是真实攻击面。签名机制只是基础,更需要配合 Secure Boot、模块黑名单、以及系统调用监控。如果你在运维中遇到类似 panic,先检查/var/log/messagesTAINT标记,再用mokutil --list-enrolled查看已注册MOK。轻云互联裸金属服务器自带的SECURE BOOT + TPM 2.0 能大幅降低这类低端错误,但运维人员仍需亲自验证合规性。

最后,随手贴一条日常巡检命令:

for mod in $(lsmod | awk 'NR>1{print $1}'); do
  path=$(modinfo -n $mod 2>/dev/null)
  if [ -f "$path" ] && ! modinfo $mod | grep -q 'sig_id:'; then
    echo "Unsigned module: $mod ($path)"
  fi
done

这条脚本曾在我们的集群中找到3个未签名模块,其中一个是“误操作”放入的恶意驱动。裸金属物理机的安全,终究靠的是每层加固的冗余,而非单点依赖。