写在前面:
- 请注意备份重要数据,以免操作发生意外!
- 该过程经过本人在实机上测试通过。
- 建议在全新安装飞牛OS后就执行该操作,已有的系统(尤其是已经安装并正在使用某些DKMS驱动时)增加安全启动支持可能会出现异常。
- 虽然我对将来可能的更新系统、安装其他DKMS驱动时的操作做了兜底,以尽可能保证安全启动在这些操作后一直可用,但仍不能十分确保一些非常规的操作会破坏信任链,导致安全启动失效,从而无法启动机器。如果出现这种情况,可以尝试关闭安全启动来恢复。
部署指南
一、理解信任链
UEFI 固件(内置 Microsoft 证书)
↓ 验证(Microsoft 已签名)
shimx64.efi ← 微软背书,信任链入口
↓ 验证(MOK 数据库)
grubx64.efi ← 用你的 MOK 签名
↓ 验证(MOK 数据库)
vmlinuz-* ← 用你的 MOK 签名
↓ 验证(MOK 数据库)
*.ko 内核模块 ← 用你的 MOK 签名
二、安装必要工具
sudo apt update
sudo apt install shim-signed grub-efi-amd64-signed sbsigntool mokutil dkms
三、部署 shim 到 ESP
fnOS 虽然安装了 shim 软件包,但没有自动部署到 EFI 系统分区,需要手动复制:
# 部署 shim 和 MokManager
sudo cp /usr/lib/shim/shimx64.efi.signed /boot/efi/EFI/debian/shimx64.efi
sudo cp /usr/lib/shim/mmx64.efi.signed /boot/efi/EFI/debian/mmx64.efi
# 更新 fallback 引导(部分固件只认 BOOTX64.EFI)
sudo cp /usr/lib/shim/shimx64.efi.signed /boot/efi/EFI/BOOT/BOOTX64.EFI
# 确认文件到位
ls -lh /boot/efi/EFI/debian/
ls -lh /boot/efi/EFI/BOOT/
四、修正 EFI 引导项指向 shim
# 删除原有引导项(原来直接指向** GRUB)
sudo efibootmgr --bootnum $(efibootmgr -v | grep -i "debian" | grep -oP 'Boot\K[0-9A-F]+') --delete-bootnum
# 创建新引导项指向 shimx64.efi
# ESP 在 /dev/nvme0n1p1,所以 --disk /dev/nvme0n1 --part 1
sudo efibootmgr \
--create \
--disk /dev/nvme0n1 \
--part 1 \
--label "fnOS Secure Boot" \
--loader "\\EFI\\debian\\shimx64.efi"
# 确认 BootOrder 第一项指向新引导项
sudo efibootmgr -v
预期结果:
BootOrder: 0004,...
Boot0004* fnOS Secure Boot .../File(\EFI\debian\shimx64.efi)
五、生成 MOK 密钥对
sudo mkdir -p /var/lib/shim-signed/mok
sudo chmod 700 /var/lib/shim-signed/mok
# 生成 RSA-4096 私钥 + 自签名证书
sudo openssl req -newkey rsa:4096 -nodes \
-keyout /var/lib/shim-signed/mok/MOK.key \
-new -x509 -sha256 -days 3650 \
-subj "/CN=fnOS Secure Boot MOK/" \
-out /var/lib/shim-signed/mok/MOK.crt
# 转换为 DER 格式(UEFI 固件需要)
sudo openssl x509 \
-in /var/lib/shim-signed/mok/MOK.crt \
-outform DER \
-out /var/lib/shim-signed/mok/MOK.cer
# 锁定私钥权限
sudo chmod 600 /var/lib/shim-signed/mok/MOK.key
# 确认三个文件都在
sudo ls -lh /var/lib/shim-signed/mok/
六、对内核和 GRUB 签名
重启回系统后:
KVER=$(uname -r)
MOK_KEY="/var/lib/shim-signed/mok/MOK.key"
MOK_CERT="/var/lib/shim-signed/mok/MOK.crt"
# 签名内核
sudo sbsign --key "$MOK_KEY" --cert "$MOK_CERT" \
--output /boot/vmlinuz-${KVER}.signed \
/boot/vmlinuz-${KVER}
sudo mv /boot/vmlinuz-${KVER}.signed /boot/vmlinuz-${KVER}
# 签名 GRUB
sudo sbsign --key "$MOK_KEY" --cert "$MOK_CERT" \
--output /boot/efi/EFI/debian/grubx64.efi.signed \
/boot/efi/EFI/debian/grubx64.efi
sudo mv /boot/efi/EFI/debian/grubx64.efi.signed \
/boot/efi/EFI/debian/grubx64.efi
# 验证签名
sudo sbverify --cert "$MOK_CERT" /boot/vmlinuz-${KVER} && echo "✓ 内核签名 OK"
sudo sbverify --cert "$MOK_CERT" /boot/efi/EFI/debian/grubx64.efi && echo "✓ GRUB 签名 OK"
七、部署自动签名脚本
确保 fnOS 升级内核或 GRUB 后自动重新签名,无需人工干预:
sudo nano /etc/kernel/postinst.d/zz-fnos-secure-boot
#!/bin/bash
# /etc/kernel/postinst.d/zz-fnos-secure-boot
# 内核升级、GRUB 更新后自动签名
set -euo pipefail
MOK_KEY="/var/lib/shim-signed/mok/MOK.key"
MOK_CERT="/var/lib/shim-signed/mok/MOK.crt"
LOG="/var/log/secure-boot-sign.log"
GRUB_EFI="/boot/efi/EFI/debian/grubx64.efi"
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG"; }
sign_if_unsigned() {
local TARGET="$1"
local LABEL="$2"
if sbverify --cert "$MOK_CERT" "$TARGET" &>/dev/null; then
log "✓ ${LABEL} 已有有效签名,跳过"
else
log "签名 ${LABEL}..."
sbsign --key "$MOK_KEY" --cert "$MOK_CERT" \
--output "${TARGET}.signed" "$TARGET" \
&& mv "${TARGET}.signed" "$TARGET" \
&& log "✓ ${LABEL} 签名成功" \
|| { log "ERROR: ${LABEL} 签名失败"; rm -f "${TARGET}.signed"; return 1; }
fi
}
# 签名新内核
KERNEL_VERSION="${1:-}"
if [[ -n "$KERNEL_VERSION" && -f "/boot/vmlinuz-${KERNEL_VERSION}" ]]; then
sign_if_unsigned "/boot/vmlinuz-${KERNEL_VERSION}" "内核 ${KERNEL_VERSION}"
fi
# 检查并签名 GRUB(防止 fnOS 更新覆盖)
[[ -f "$GRUB_EFI" ]] && sign_if_unsigned "$GRUB_EFI" "grubx64.efi"
# 同步 BOOTX64.EFI 保持与 shim 一致
SHIM_SRC="/usr/lib/shim/shimx64.efi.signed"
SHIM_DST="/boot/efi/EFI/BOOT/BOOTX64.EFI"
if [[ -f "$SHIM_SRC" ]] && ! diff -q "$SHIM_SRC" "$SHIM_DST" &>/dev/null; then
cp "$SHIM_SRC" "$SHIM_DST"
log "✓ BOOTX64.EFI 已同步更新"
fi
sudo chmod +x /etc/kernel/postinst.d/zz-fnos-secure-boot
APT 层兜底 hook,覆盖 fnOS 非标准更新路径:
sudo tee /etc/apt/apt.conf.d/99-secure-boot-sign > /dev/null << 'EOF'
DPkg::Post-Invoke {
"/etc/kernel/postinst.d/zz-fnos-secure-boot '' 2>&1 | tee -a /var/log/secure-boot-sign.log";
};
EOF
八、配置 DKMS 模块自动签名
sudo tee /etc/dkms/sign_helper.sh > /dev/null << 'EOF'
#!/bin/bash
# DKMS 编译后自动签名内核模块
KERNEL_VER="$1"
MODULE_PATH="$2"
MOK_KEY="/var/lib/shim-signed/mok/MOK.key"
MOK_CERT="/var/lib/shim-signed/mok/MOK.crt"
LOG="/var/log/secure-boot-sign.log"
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] DKMS: $*" >> "$LOG"; }
SIGN_FILE="/lib/modules/${KERNEL_VER}/build/scripts/sign-file"
if [[ -x "$SIGN_FILE" ]]; then
"$SIGN_FILE" sha256 "$MOK_KEY" "$MOK_CERT" "$MODULE_PATH" \
&& log "✓ 模块签名成功: $(basename $MODULE_PATH)"
else
sbsign --key "$MOK_KEY" --cert "$MOK_CERT" \
--output "${MODULE_PATH}.signed" "$MODULE_PATH" \
&& mv "${MODULE_PATH}.signed" "$MODULE_PATH" \
&& log "✓ 模块签名成功(sbsign): $(basename $MODULE_PATH)"
fi
EOF
sudo chmod +x /etc/dkms/sign_helper.sh
# 启用 DKMS 全局签名
echo 'sign_tool="/etc/dkms/sign_helper.sh"' | sudo tee -a /etc/dkms/framework.conf
如果系统中已经安装了某些DKMS驱动(如i915-sriov-dkms),此时请卸载重新安装这些驱动,以触发签名操作,否则这些驱动可能无法使用。
九、将证书注册到 UEFI NVRAM
# 写入待确认队列(需要设置一个临时密码,重启时用一次)
sudo mokutil --import /var/lib/shim-signed/mok/MOK.cer
重启,进入 UEFI,开启安全启动,保存退出,再次重启后在蓝色 MokManager 界面操作:
Enroll MOK
→ View key 0(确认显示 CN=fnOS Secure Boot MOK)
→ Continue
→ 输入刚才设置的临时密码
→ Reboot
启动后验证:
# 验证安全启动已激活
sudo mokutil --sb-state
# 期望输出:SecureBoot enabled
# 验证内核认可安全启动
sudo dmesg | grep -i "secure boot"
# 查看已注册证书
sudo mokutil --list-enrolled | grep "fnOS"
# 查看签名日志
sudo tail -20 /var/log/secure-boot-sign.log