在 Arch Linux 下启用安全启动并自动签名
Ubuntu 的系统别的不说,安全启动「Secure Boot」整起来是真的容易 —— 默认内置预签名的 shim
引导,安装时打个勾就可以自动处理好繁琐的签名步骤了。Fedora 也内置了类似的预签名引导。
※ 使用的系统并非严格意义上的 Arch Linux,而是其衍生版 EndeavourOS。
安全启动是什么 #
微软提出的一个保护引导程序完整性的“标准”,即任何从 UEFI 引导的系统都应通过“签名”来保持信任,从而达成安全启动。该项目从诞生开始就一直饱受争议…
如果不是为了方便双启动 Windows 111 也不至于这么折腾。
Arch Linux 百科 #
Arch Linux 百科对应的条目内确实应有尽有,但是… 安全启动的一些坑没有说出来,而我傻傻的踩上去了。
我现在的这台主机使用的主板是华擎的 X570 Phantom Gaming 4。事后只能说果真够妖。
密钥迷云 #
一开始我是照着「3.1 Using your own keys」来操作的。来来回回折腾了好几次都在使用工具写出 EFI 密钥设定失败,仔细阅读后发现需要先进入设置模式才可以;于是进入 BIOS 设定把预设的密钥数据库清空了。
重启进入系统,一切正常;继续尝试写入,依旧出错。百思不得其解,只想着一会重启后手动进 BIOS 里手动更新设置好了。只是重启后…
无法启动了!屏幕无输出,键盘也无反映。
拆开主机外壳一看,启动诊断灯亮了 - 非常迷惑的「VGA」和「Boot」指示灯…
网上搜索一番,没得出什么结论;官方手册里也就这么一句废话:
Post Status Checker (PSC) diagnoses the computer when users power on the machine. It emits a red light to indicate whether the CPU, memory, VGA or storage is dysfunctional. The lights go off if the four mentioned above are functioning normally.
PSC 可以在用户启动设备时对电脑进行诊断。他可以通过亮红灯来表示处理器、内存、视频输出或储存设备无法正常工作。若无灯亮起则表示这四项检测通过。
后来想了想,既然是改 BIOS 出问题了,那我重置一下吧…
于是把主机拆开。照着网上找的教程翘走 CMOS 电池(好像不是必须的?),然后短接清除 CMOS 跳线。跳线帽也不知道去哪找,最后找了一条两头凹形接口的线套了上去。
就这样来来回回折腾一晚上,终于又能启动了…
此时已经有点想放弃了,但是又随手一翻看到后面的「Using a signed boot loader」一看… 这不就是我念念不忘的 Ubuntu 所使用的方案吗!
全信用链 vs 机器信用链 #
正常的安全启动的信任链是这样的:
「平台密钥(Platform Key,PK,由主板厂商签发)」→「交叉认证签名(Key Exchange Key,KEK,认证微软的签名根)」→「签名数据库(Signature Database,具体的签名)」
刚才看的 3.1 方案则如此,从平台密钥开始全部签发一遍,并交叉授权微软的签名以允许启动带有微软签名的 Windows 引导程序。
微软不能为 GPL 协议的项目签名2,因此 shim
、preloader
这类项目就诞生了 - 由微软预签名因而可以直接启动,然后用户手动授权指定的 efi 镜像或「机器密钥」让所有使用该密钥签名的引导与内核能正常启动。
设定机器密钥 #
照着百科「3.2.2.1.2 shim with key」一路继续即可。完成后再对引导与内核签名。
但还是不能正常启动;错误信息提示禁止引导:「prohibited by secure boot policy」。
最后一路爬文发现这个错误是 grub 无法正常加载所需要的模块,需要在安装的时候填写需要打包(?)的模块,并在启动时预加载… 于是又用脚本来从 grub2 的配置文件提取用到的模块:
sudo cat /boot/grub/grub.cfg | awk '/insmod/ { print $2 }' | sort | uniq
加到参数里再尝试,还是一样的错误,估计还是需要声明更多的模块,但根本不知道去哪找这个参数,还试过枚举所有可用的模块文件来构建 grub 引导:
MODULES="$(ls /usr/lib/grub/x86_64-efi/ | grep -E '\.mod$' | cut -d. -f1)"
也不是不能用,但是界面不仅很丑还很慢… 估计是打包到一些兼容/调试模式用的模块了。
最后在一篇教学文章中找到了一个相对带有部分注解的模块列表:
# GRUB doesn't allow loading new modules from disk when secure boot is in
# effect, therefore pre-load the required modules.
MODULES=
MODULES="$MODULES part_gpt fat ext2" # partition and file systems for EFI
MODULES="$MODULES configfile" # source command
MODULES="$MODULES verify gcry_sha512 gcry_rsa" # signature verification
# ... 后略
这篇文章也有些年头了,比如 verify
和 linuxefi
模块已经找不到了。
于是我照着这个列表缝缝补补了一番,最后整合了个签名脚本在 grub 更新后自动执行:
#!/bin/sh
#MODULES="$(ls /usr/lib/grub/x86_64-efi/ | grep -E '\.mod$' | cut -d. -f1)"
# GRUB doesn't allow loading new modules from disk when secure boot is in
# effect, therefore pre-load the required modules.
MODULES=
MODULES="$MODULES part_gpt fat ext2" # partition and file systems for EFI
MODULES="$MODULES configfile" # source command
MODULES="$MODULES crypto" # signature verification? no idea.
MODULES="$MODULES echo normal linux" # boot linux
MODULES="$MODULES all_video efi_gop efi_uga font" # video output
MODULES="$MODULES search search_fs_uuid" # search --fs-uuid
MODULES="$MODULES reboot sleep" # sleep, reboot
MODULES="$MODULES tpm" # Added per Arch Linux wiki
MODULES="$MODULES gettext gfxmenu gfxterm gzio" # <-- Used in grub.cfg,
MODULES="$MODULES part_gpt part_msdos png" # <-- via "insmod" command
MODULES="$MODULES probe test true" # Indirect dependency to some of the commands
MODULES="$MODULES chain" # Chainload Windows bootloader, not sure if needed.
# what could go wrong?
# Regenerate grub bootloader
grub-install \
--no-nvram \
--target=x86_64-efi \
--efi-directory=/boot/efi \
--modules="$MODULES" \
--sbat /usr/share/grub/sbat.csv
mok_sign() {
# sign if not already done so.
if ! /usr/bin/sbverify --list "$1" 2>/dev/null | /usr/bin/grep -q "signature certificates"; then
printf 'Signing %s...' "$1"
sbsign --key /etc/efi-keys/mok/MOK.key --cert /etc/efi-keys/mok/MOK.crt --output "$1" "$1"
else
printf 'Skip sign: %s\n' "$1"
fi
}
mok_sign /boot/efi/EFI/endeavouros/grubx64.efi
事后检查一下 sbctl status
的环境检测:
$ sbctl status
Installed: ✗ sbctl is not installed
Setup Mode: ✓ Disabled
Secure Boot: ✓ Enabled
Vendor Keys: microsoft
Grub vs rEFInd #
rEFInd 需要签名的文件少,理论上来说用起来会更方便。
但是我每次通过 shim
引导 rEFInd 都提示引导镜像的签名不对,遂放弃。
后记 #
手动配置安全引导真麻烦。要是以后还需要重装 Linux 的话,还是用 Ubuntu 系列的发行版算了。
手上有个笔记本实现的安全引导是个残缺版,需要手动将入口镜像加入到数据库 - 但因为该实现不会对后续加载的镜像进行验证,因而让我产生了配置安全引导很简单的错觉。