Gentoo系统中启用SecureBoot

自用一台 Lenovo Thinkpad X13 机器,打算给自己装 Windows 和 Linux 的双系统。为了安全,我打算安装 Gentoo Linux 的同时启用SecureBoot来保证启动的安全。

Gentoo系统的安装

  1. 安装 Gentoo Linux 之前,需要先关闭 BIOS 中的SecureBoot选项,因为 Gentoo 官方的安装镜像并不直接支持SecureBoot,必须关闭之后才能正常引导。
  2. 参考官方的WIKI来安装 Gentoo 系统,需要注意两点:
    • 需要使用带systemd的 Profile,同时安装 BootLoader 的时候使用 systemd-boot 作为引导
    • 确保能正常在非SecureBoot情况下正常进入系统之后,才可以进行之后的配置

Gentoo使用SecureBoot的原理(可跳过)

Gentoo 等 Linux 系统想要使用SecureBoot机制,通用的办法是手动使用类似sbctl工具去修改 UEFI Firmware 证书配置等,并且对kernelinitramfs等签名来实现SecureBoot引导(具体步骤可参考 Gentoo Wiki - SecureBoot)。但是这一种方法有两个明显的问题,第一是比较复杂而且风险很大,出错的话容易导致 UEFI Firmware 整个出错,甚至无法开机等。第二是修改使用自签名的证书,没办法支持 Windows 和 Linux 的同时启动。

而通过预签名的shim的方式则相对简单得多,预签名shim是 Ubuntu 社区提供的,经过 Microsoft 签名的引导器,可以直接通过SecureBoot。通过向shim添加信任的证书,再通过证书链方式签名kernelinitramfs,可以更简单的使用SecureBoot。同时因为shim作为独立的引导器,并不会和 Windows 自带的引导冲突,所以可以轻松的实现双系统。

使用shim来启用SecureBoot

安装配置shim

1
emerge --ask sys-boot/shim sys-boot/mokutil sys-boot/efibootmgr
1
bootctl install --no-variables
1
cp /usr/share/shim/BOOTX64.EFI /efi/EFI/systemd/shimx64.efi
1
cp /usr/share/shim/mmx64.efi /efi/EFI/systemd/mmx64.efi

最后使用efibootmgr手动添加引导项。注意需要把/dev/boot-diskboot-partition-id替换成自己对应的 boot 分区。比如我自己 boot 分区的是/dev/nvme0n1p1,所以对应/dev/nvme0n1盘第1分区。

1
2
3
4
5
efibootmgr --create --disk /dev/boot-disk \
--part boot-partition-id \
--loader '\EFI\systemd\shimx64.efi' \
--label 'Systemd-boot via Shim' \
--unicode '\EFI\systemd\systemd-bootx64.efi'

此时,重启并在不启用SecureBoot的情况下,通过Systemd-boot via Shim启动项来进入系统,此时shim安装完成。

配置SecureBoot证书

接下来,需要创建我们自己的证书,并且添加进入shim的信任链中,之后再通过这个证书签名内核。

创建证书

1
2
3
4
# 注意,可以根据自己的实际情况适当修改参数,特别是`--subj`,可以对应修改`CN`以便于更方便区分证书。
openssl req -newkey rsa:2048 -nodes -keyout MOK.key \
-new -x509 -sha256 -days 3650 \
-subj "/CN=my Machine Owner Key/" -out MOK.crt

因为shim需要证书是 PEM 格式,所以需要将生成才证书转换为 PEM。

1
openssl x509 -outform DER -in MOK.crt -out MOK.der

使用mokutil管理证书

shim的证书可以使用mokutil来管理,常用的mokutil命令包括:

1
2
3
4
5
6
7
8
9
10
# 列出已经导入的证书
mokutil --list-enrolled
# 导入 MOK.der 证书
mokutil --import <certificate path>
# 删除对应hash值的证书,可以通过list-enrolled来看到证书hash值
mokutil --delete-hash <hash to remove from above command>
# 删除某个特定证书
mokutil --delete <certificate path>
# 列出已经删除的证书
mokutil --list-delete
  1. 通过下面的命令导入MOK.der证书:
    1
    2
    # 可能会让你输入密码,这个密码仅用于重启后确认
    mokutil --import MOK.der
  2. 重启电脑并通过shim引导启动,此时选择Enroll Key选项来添加证书。
  3. 添加完成重启进入系统之后,可以通过mokutil --list-enrolled,检查是否添加成功。

修改make.confpackage.use

完成添加证书之后,需要修改/etc/portage/make.conf来实现自动使用证书来签名内核。

1
2
3
4
5
6
# Path to MOK.key
SECUREBOOT_SIGN_KEY="..."
# Path to MOK.crt
SECUREBOOT_SIGN_CERT="..."
# Add 'secureboot' to USE
USE = "secureboot"

原则上,kernel,initramfsmodule都需要使用证书签名之后才可以在shim中使用,但是这相对来说比较麻烦,此时,我们使用 UKI (Unified kernel image),会更加方便,只需要对生成的合并 Image 签名即可以在shim中正常引导。所以,我使用dracutinstallkernel来自动生成 UKI,并且自动签名。

  1. 修改/etc/portage/package.use/installkernel文件,添加 USE flag
    1
    sys-kernel/installkernel dracut systemd-boot uki
  2. 安装dracutinstallkernel
    1
    emerge -a sys-kernel/installkernel sys-kernel/dracut
  3. 修改/usr/lib/kernel/install.conf
    1
    2
    3
    layout=uki
    initrd_generator=dracut
    uki_generator=dracut
  4. 修改/etc/dracut.conf来启用自动签名
    1
    2
    3
    4
    # Path to MOK.crt
    uefi_secureboot_cert="..."
    # Path to MOK.key
    uefi_secureboot_key="..."
  5. 重新配置 kenerl,如果是手动编译的,可以使用make install重新配置。如果通过 package 安装,可以通过emerge --config gentoo-kernel{,-bin}来重新配置 kernel。
  6. 在不启用SecureBoot的条件下重启电脑,如果能正常进入Linux,则可以开启SecureBoot来测试是否正常。