amtoaer

晓风残月

叹息似的渺茫,你仍要保存着那真!
github
x
telegram
steam
nintendo switch
email

为 Arch Linux 配置安全启动

最近为自己的 Arch Linux 配置了安全启动 (security boot),在此记录一下流程以及遇到的问题。

实现安全启动#

关于安全启动的实现方法,Arch Wiki内有完整的描述,但由于其采用 wiki 方式写作,对流程描述较为复杂。本节旨在描述实现安全启动的最简方法,跳过更加详细深入的概念性内容。

注:本文仅描述了为 Arch Linux 设置安全启动,关于进一步的实现与 Windows 安全启动共存,请自行阅读 Arch Wiki相应条目

生成 Key#

安全启动的实现包括四种 Key:

  • Platform Key(PK)
  • Key Exchange Key(KEK)
  • Signature Database(db)
  • Forbidden Signatures Database(dbx)

为了正常使用安全启动,我们至少需要前三种 Key。为了方便,我们可以使用脚本自动生成:

# 后文自动处理内核更新等操作的 sbupdate 工具默认使用位于/etc/efi-keys的Key。

# 为了方便,这里直接创建此目录并在该目录生成Key

mkdir /etc/efi-keys
cd !$
curl -L -O https://www.rodsbooks.com/efi-bootloaders/mkkeys.sh
chmod +x mkkeys.sh
./mkkeys.sh
<随意输入一个嵌入在key中的名字,例如"Secure Boot">

自动签名#

为了在内核、引导更新时自动签名,我们可以使用 sbupdate 工具。

安装#

通过如下命令安装:

yay -S sbupdate-git

配置#

安装后,我们需要为其写入配置,指明需要自动签名的内容。

打开 /etc/sbupdate.conf,修改配置文件,以下给出我的设置样例以及选项说明:

# Key所在的目录
KEY_DIR="/etc/efi-keys"
# EFI引导分区位置
ESP_DIR="/boot"
# 生成的单独EFI引导文件位置
OUT_DIR="EFI/Linux"
# 生成的单独EFI引导文件所携带的默认内核参数
CMDLINE_DEFAULT="loglevel=3 quiet nomce rw"
# 需要额外签名的文件,一般包括自己的启动加载器文件
# 理论上内核是自动签名的,但不知道为什么我的vmlinuz-linux-zen不行,因此我也把内核文件写在了这里
EXTRA_SIGN=('/boot/EFI/BOOT/BOOTX64.EFI' '/boot/EFI/systemd/systemd-bootx64.efi' '/boot/vmlinuz-linux-zen')

# 内核单独配置
INITRD["linux-zen"]="/boot/initramfs-linux-zen.img"
# 如果不进行内核参数的配置,默认使用上面的CMDLINE_DEFAULT
CMDLINE["linux-zen"]="root=PARTUUID=db9157b1-bed4-fa44-a715-5c1bfc8bdfb4 quiet nomce loglevel=3 rw"

以下对内核单独配置做特别说明:

sbupdate 会为每个内核生成一个直接的引导文件(位于 ${ESP_DIR}/${OUT_DIR},文件名为 ${kernel_name}-signed.efi),其中包含了内核参数和临时文件系统的配置(分别对应配置文件中的 CMDLINE [${kernel_name}] 与 INITRD [${kernel_name}])。

用户可以使用的引导方法有三种:

  1. 使用 boot loader(例如 grub/systemd-boot 等)的既有配置进行引导
  2. 直接使用该文件进行引导
  3. 使用 boot loader 调用该文件完成间接引导

用户当前使用的往往是第一种方法。在这种方法没有问题的情况下,其实是没有使用这个直接引导文件的必要的。即:

可以忽略上面的 OUT_DIR、CMDLINE_DEFAULT 和内核单独配置。

签名#

第一次配置完毕后,需要自己手动执行一下签名指令:

sudo sbupdate

在将来内核更新时,该工具会自动为其签名。

对于 systemd-boot 自动签名的特殊处理#

对于其他引导方法,可能上面配置方法已经足够,但如果你使用 systemd-boot 作为 boot loader,可能还需要进一步的配置。

hooks 执行顺序的处理#

关于这种情况的解释:

一般情况下,我们只需要在更新内核、systemd 时使用 pacman hook 更新签名,但在使用 systemd-boot 的情况下,我们同样需要在更新 systemd 时更新引导(即sudo bootctl update,该命令会替换 /boot/EFI/BOOT/BOOTX64.EFI 和 /boot/EFI/systemd/systemd-bootx64.efi 到最新版本),因此这时 hooks 的执行顺序成为了一个很大的问题 —— 我们需要确保引导的更新先于签名过程。

想必使用 systemd-boot 的用户应该了解使用 pacman hook 进行自动更新的方式(参见systemd boot - 自动更新)。在文档中给出的方法有两种:

  1. 安装 systemd-boot-pacman-hook(本质是下载了 systemd-boot.hook)
  2. 自己手动在 /etc/pacman.d/hooks/100-systemd-boot.hook 写入所给内容。

我们可以看到,sbupdate 自带的用于更新签名的 hook 名称为 95-sbupdate.hook,而根据alpm-hooks 文档所言:

Hooks are run in alphabetical order of their file name, where the ordering ignores the suffix.
钩子按其文件名的字母顺序运行,该顺序忽略后缀。

按照该规则,无论是方法 1 得到的 system-boot.hook 还是方法 2 写入的 100-systemd-boot.hook,都无法满足先于签名 hook 执行的需求。我的解决方法是使用方法 2,但将文件名修改为 90-systemd-boot.hook,使其满足顺序需求。

额外签名 boot loader 的处理#

我们已经解决了第一个障碍,不过不要急,这里还有一个问题。

我们把需要额外签名的 boot loader 文件写在了 sbupdate 的 EXTRA_SIGN 里,但注意到在 95-sbupdate.hook 中,更新签名使用的命令是/usr/bin/sbupdate -k,通过查看 sbupdate 源码66-72 行195-205 行可以得知,-k 参数表明 sbupdate 是被 hook 调用的,而为了安全原因,使用 hook 调用 sbupdate 会跳过 EXTRA_SIGN 中的内容,这显然不是我们期望的。

解决方法也很简单,打开 /usr/share/libalpm/hooks/95-sbupdate.hook,将 - k 参数去除即可。

写入 Key 到 Bios#

完成上面的步骤后,已经万事具备,只欠东风了,最后我们只需要将 Key 写入到 Bios。

删除既有 Key#

Bios 默认会自带微软 Key,为了写入我们自己的 Key,需要将原有的 Key 删除。

在这一步骤中,需要进入 Bios,找到安全启动的证书管理选项,在里面选择删除即可。

写入新的 Key#

利用sbsigntools简化 Key 的写入过程。

首先我们需要一个这样的目录:

/etc/secureboot/keys
├── db
├── dbx
├── KEK
└── PK

执行如下命令进行创建:

mkdir -p /etc/secureboot/keys/{db,dbx,KEK,PK}

接着将之前位于/etc/efi-keys*.auth文件拷贝到对应的目录(没有 dbx 是正常的)。

最后需要执行如下命令:

sbkeysync --verbose
sbkeysync --verbose --pk

如果有幸没有报错,恭喜你,已经完成了 Arch Linux 的安全启动配置,这就到 Bios 中开启安全启动选项并启动吧!

结语#

在本文中,我罗列出了自己为本机配置安全启动做的所有操作。尽管如此,我并不能保证读者们能够复现我的成功步骤。

如果你在执行文章中的某些步骤时出现差错,推荐阅读 Arch Wiki 的原文。原文中包括了同一步骤的多种实现方式,且给出了详细的错误处理,比该文更具有代表性。

参考#

  1. security boot - Arch Wiki
  2. systemd boot - Arch Wiki
  3. sbupdate Readme.md - GitHub
加载中...
此文章数据所有权由区块链加密技术和智能合约保障仅归创作者所有。