第4章 UEFI安全启动实战:在物理机上启用Secure Boot、自定义签名、常见问题排查
好,咱们进入实战环节。前面几章讲了理论,这一章我带你亲手在物理机上折腾一遍 Secure Boot。说实话,光看文档不动手,你永远记不住那些坑在哪。我自己第一次配的时候,差点把一台测试机的 BIOS 搞废掉——嗯,后来学乖了,每次改之前都先备份固件设置。
4.1 物理机启用Secure Boot的标准流程
先明确一点:不是所有主板都叫 UEFI。你得先确认你的机器用的是 UEFI 模式,而不是传统的 Legacy BIOS。怎么查?开机进 Setup 界面,或者用 efibootmgr 看一眼。
核心前提: 操作系统必须安装在 GPT 分区表上,且 ESP(EFI System Partition)分区必须存在。没有 ESP?Secure Boot 想都别想。
步骤一:进入固件设置
开机时按 Del / F2 / F12(各家厂商不一样)。找到 Secure Boot 选项,通常在「Security」或「Boot」菜单下。我见过有些主板把它藏在「Authentication」子菜单里,找得我直冒汗。
步骤二:切换为 Standard 或 Custom 模式
大部分主板默认是 Standard(标准)模式,使用厂商预置的证书。如果你想用自己的签名,必须切换到 Custom(自定义)模式。切换后,系统会提示你清除已有的 Secure Boot 数据库。
注意: 清除数据库后,如果你没有提前准备好自己的证书,系统将无法启动任何未签名的操作系统。我曾经手滑清空过,结果只能拿 U 盘进救援模式重新导入证书。
步骤三:启用 Secure Boot
把 Secure Boot 从 Disabled 改为 Enabled。保存退出,重启。如果一切正常,你会看到系统顺利进入桌面。如果卡在开机 logo 处,或者出现「Invalid signature detected」的提示——别慌,后面有排查方法。
4.2 自定义签名:从生成密钥到导入数据库
为什么要自定义签名?说白了,就是你想完全掌控自己的机器。比如你编译了一个自定义内核,或者用了第三方的驱动模块,厂商的证书不认它。这时候,你得自己当 CA(证书颁发机构)。
4.2.1 生成你自己的密钥对
我习惯用 OpenSSL 来生成。下面这套命令,我在不下十台机器上跑过,稳得很。
# 生成 Platform Key (PK)
openssl req -new -x509 -newkey rsa:2048 -subj "/CN=My Platform Key/" \
-keyout PK.key -out PK.crt -days 3650 -nodes
# 生成 Key Exchange Key (KEK)
openssl req -new -x509 -newkey rsa:2048 -subj "/CN=My KEK/" \
-keyout KEK.key -out KEK.crt -days 3650 -nodes
# 生成 Signature Database (db) 证书
openssl req -new -x509 -newkey rsa:2048 -subj "/CN=My Signature Database/" \
-keyout db.key -out db.crt -days 3650 -nodes
这里有个细节:PK 是最高权限,KEK 次之,db 最底层。你想想看,如果 PK 丢了,整台机器就废了——因为只有 PK 才能更新 PK 自己。所以,私钥一定要备份到离线存储里。
4.2.2 将证书转换为 EFI Signature List (ESL) 格式
UEFI 固件不认识 .crt 文件,它只认 ESL 格式。用 cert-to-efi-sig-list 工具转换:
cert-to-efi-sig-list -g "$(uuidgen)" PK.crt PK.esl
cert-to-efi-sig-list -g "$(uuidgen)" KEK.crt KEK.esl
cert-to-efi-sig-list -g "$(uuidgen)" db.crt db.esl
那个 -g 参数后面跟的 UUID,是用来标识这个签名列表的。你可以随便生成一个,但别重复。
4.2.3 签名并导入数据库
导入 PK 之前,得先用旧的 PK 签名新的 PK 文件。但如果你是从零开始(清空状态),这一步可以跳过。直接使用 efi-updatevar 或固件自带的工具导入。
# 使用 efi-updatevar 导入(需要在内核中启用 CONFIG_EFI_VARS)
efi-updatevar -f PK.esl PK
efi-updatevar -f KEK.esl KEK
efi-updatevar -f db.esl db
小技巧: 如果你不想装 efi-updatevar,也可以把 ESL 文件放到 FAT32 格式的 U 盘里,然后在固件设置界面手动导入。大多数专业级主板(比如 Supermicro、ASUS 的 WS 系列)都支持这个功能。
4.3 签名你的内核和引导加载器
数据库导入完了,接下来要签名实际要启动的文件。以 GRUB 和 Linux 内核为例:
# 签名 GRUB
sbsign --key db.key --cert db.crt --output /boot/efi/EFI/BOOT/grubx64.efi.signed \
/boot/efi/EFI/BOOT/grubx64.efi
# 签名内核
sbsign --key db.key --cert db.crt --output /boot/vmlinuz-linux.signed \
/boot/vmlinuz-linux
签名后,把原始文件替换成签名版本。注意,有些发行版(比如 Ubuntu)会自动处理签名,你只需要装好 shim-signed 包就行。但如果你用的是 Arch 或 Gentoo,嗯,自己动手吧。
4.4 常见问题排查
这部分是我最想跟你聊的。因为理论再漂亮,实战中总会出幺蛾子。我列几个我踩过的坑:
| 现象 | 可能原因 | 解决办法 |
|---|---|---|
| 开机显示「Invalid signature」 | 内核或 GRUB 未签名,或签名证书不在 db 中 | 检查签名状态:sbverify --cert db.crt /boot/vmlinuz |
| 导入 PK 后直接变砖 | PK 证书与 KEK/db 不匹配,或 PK 私钥丢失 | 用编程器刷回原始固件,或者短接 CMOS 跳线(部分主板支持) |
| Windows 能启动,Linux 不行 | Linux 引导加载器使用了未签名的 shim | 安装 shim-signed,并确保 shim 的证书在 db 中 |
| 更新固件后 Secure Boot 被重置 | 固件更新清空了自定义证书 | 更新前导出证书,更新后重新导入 |
4.4.1 排查工具
我常用的三板斧:
- sbverify:检查一个 EFI 文件是否被签名,以及用的是哪张证书。
- efi-readvar:查看当前固件中的 PK、KEK、db 内容。
- mokutil:管理 Machine Owner Key(MOK),适合在 shim 环境下调试。
举个例子,有一次我同事说他的内核签名了但还是启动不了。我让他跑了一下 sbverify --cert db.crt vmlinuz,结果发现签名用的证书跟 db 里存的不一样——他生成密钥时把 CN 写错了。这种问题,光看日志根本看不出来。
4.5 知识体系总览
下面这张图,把 Secure Boot 的整个信任链画清楚了。你对照着看,应该能理解为什么 PK 丢了就全完了。
4.6 避坑指南
最后,我把自己这些年攒下来的教训列成清单,你照着做,能省不少时间:
- 备份原始固件设置:在改 Secure Boot 之前,进固件界面把所有设置截图或拍照。有些主板支持导出配置文件,一定要用。
- 先测试,再量产:别在生产服务器上直接搞。找一台同型号的测试机,先跑一遍完整流程。我见过有人在生产环境导入 PK 后直接黑屏,最后只能返厂。
- 签名 shim 而不是 GRUB:如果你用 shim,只需要签名 shim 本身。shim 会验证 GRUB,GRUB 再验证内核。这样你更新 GRUB 时不用重新签名。
- 注意固件更新:厂商推送固件更新时,有时会重置 Secure Boot 数据库。更新前导出证书,更新后重新导入。我吃过这个亏,那次差点重装系统。
我的个人习惯: 每次改完 Secure Boot 设置,我都会在机器上贴一张标签,写上「Secure Boot: Custom / PK 指纹: xxxx」。这样下次别人接手时,不会一头雾水。
好了,这一章的内容就到这。你照着上面的步骤走一遍,应该能在物理机上跑通 Secure Boot。如果卡住了,回头看看排查表,八成能找到答案。