为 Arch Linux 启用安全启动
物理保护数据的最后一道防线
发布于:2025/07/20
标签:GNU/Linux
参考 Arch Linux 中文维基 UEFI/安全启动#sbctl 可信平台模块 和 Arch Linux Wiki systemd-cryptenroll 以及 Bilibili UP unixchad 的视频 在Arch Linux上启用UEFI/安全启动:sbctl 编写
安全启动的作用(为什么需要安全启动?)
虽然在我们的教程里把/boot
放进了加密分区内,但总会有未加密的引导加载器(如果你按照我的教程安装的话那就是/efi
)暴露在外面
那么这时,假如有攻击者能从物理层面上接触到你的电脑,那么 TA 就有可能对我们的引导加载器做手脚,使其能够在我们下次开启电脑时获取我们的解密密钥甚至任何信息,并发送给攻击者(这被称为“邪恶女佣攻击”)
(在某些极端情况下甚至不需要物理接触,如果攻击者已经在你的设备开机时黑入,那么 TA 同样可以植入病毒)
为了应对这种情况,我们就需要安全启动了。当它被开启后,在我们启动系统前,安全启动会检查我们的引导加载器上是否存在签名、签名是否与自身保存的密钥对应,如果其中一项是否,那么就会拒绝启动,从而保证系统不被篡改
签署引导加载器
安装 sbctl
我们先安装sbctl
# pacman -S sbctl
进入 setup mode
CAUTION
请注意,开启这个模式后就可以朝 BIOS 内写入密钥了,请保证只在设置密钥时打开,否则恶意攻击者也可以向你的主板内写入 TA 的密钥
首先重启到你的 BIOS 设置,找到安全/Security
页面,把安全启动关闭并把模式设置为setup mode
并删除所有预装密钥(这部分几乎所有主板都不一样,请自行摸索,实在抱歉)(如果找不到setup mode
的选项那么删除所有密钥大概应该就能进入),然后保存并重启
重启后我们使用sbctl
检查安全启动状态
$ sbctl status
Installed: ✗ sbctl is not installed
Setup Mode: ✗ Enabled
Secure Boot: ✗ Disabled
Vendor Keys: none
如果显示如上三个✗
以及none
的话,我们就可以开始下一步了,如果不是,你可能需要回去检查一下你的 BIOS 设置
没错,是
✗
,第一个✗
代表我们还没有给引导加载器签名,第二个✗
表示开启了setup mode
,第三个✗
表示安全启动是关闭状态,这都代表不安全,但这正是我们现在需要的状态 然后none
代表我们删除了所有预装密钥,这是为了保证以后我们的 BIOS 只信任我们自己的密钥,而不是包括设备制造商或微软的
生成密钥并登记到 BIOS
使用sbctl
生成密钥
# sbctl create-keys
稍等片刻,密钥便生成好了,生成的密钥会被放在/var/lib/sbctl/
这个路径下(不需要去动,只要知道就好了) 然后我们将登记到 BIOS 中
# sbctl enroll-keys
CAUTION
如果你有使用双系统的需求或启用安全启动后系统无法启动,请使用sbctl enroll-keys -m
,这会同时登记微软的密钥
TIP
运行sbctl enroll-keys
后会马上关闭setup mode
,如果需要更改密钥或重新导入,需要到 BIOS 界面重新开启
签署文件
终于,我们正式开始签署我们的文件
首先我们重新生成一次initramfs
,这会帮我们自动签署生成的文件
# mkinitcpio -P
然后列出所有待签署的文件
# sbctl verify
Verifying file database and EFI images in /efi...
✗ /efi/EFI/BOOT/BOOTX64.EFI is not signed
✓ /efi/EFI/Linux/arch-linux-fallback.efi is signed
✓ /efi/EFI/Linux/arch-linux.efi is signed
✗ /efi/EFI/systemd/systemd-bootx64.efi is not signed
failed to verify file /efi/loader/entries.srel: /efi/loader/entries.srel: invalid pe header
failed to verify file /efi/loader/loader.conf: /efi/loader/loader.conf: invalid pe header
failed to verify file /efi/loader/random-seed: /efi/loader/random-seed: invalid pe header
如果你按照我的教程并使用systemd-boot
作为引导加载器,那么你的输出应该跟我类似,使用grub
会有所不同,但大同小异,挨个签名就好
你可能有注意到,这个列表里有一些
failed to verify
开头的文件,这代表了它不是一个需要被签署的二进制文件,可以被安全的忽略
如果你是把esp
分区挂载到了/boot
下,那么这里会列出你安装的内核(如/boot/vmlinuz-linux
),你需要一并签名
接下来,我们来挨个签署它们,使用-s
参数来追踪,使引导加载器或内核更新后能自动重新签署
# sbctl sign -s /efi/EFI/BOOT/BOOTX64.EFI
以此类推,直到所有文件被签署完毕
# sbctl verify
Verifying file database and EFI images in /efi...
✓ /efi/EFI/BOOT/BOOTX64.EFI is signed
✓ /efi/EFI/Linux/arch-linux-fallback.efi is signed
✓ /efi/EFI/Linux/arch-linux.efi is signed
✓ /efi/EFI/systemd/systemd-bootx64.efi is signed
failed to verify file /efi/loader/entries.srel: /efi/loader/entries.srel: invalid pe header
failed to verify file /efi/loader/loader.conf: /efi/loader/loader.conf: invalid pe header
failed to verify file /efi/loader/random-seed: /efi/loader/random-seed: invalid pe header
CAUTION
如果你使用systemd-boot
作为引导加载器,那么你需要关闭用于更新的systemd-boot-update.service
这个systemd
服务,转而用systemd-boot-pacman-hook
这个在aur
的软件包进行更新
(参考 Arch Linux 中文维基中 Systemd-boot#自动更新 及 UEFI/安全启动#使用pacman钩子自动签署 中的提示)
启用安全启动
再次运行sbctl status
$ sbctl status
Installed: ✓ sbctl is installed
Owner GUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Setup Mode: ✓ Disabled
Secure Boot: ✗ disabled
Vendor Keys: none
如果一切顺利,你的输出应该跟上面所示的一样了(其实在登记完密钥后就已经应该是这样了)
此时我们再进入 BIOS,开启安全启动,见证奇迹的发生
如果成功重启,再次运行sbctl status
$ sbctl status
Installed: ✓ sbctl is installed
Owner GUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Setup Mode: ✓ Disabled
Secure Boot: ✓ Enabled
Vendor Keys: none
那么恭喜你🎉,你成功为你的 Arch Linux 亲手启用了安全启动
使用 TPM 2.0 自动解密根分区
启用了安全启动后,我们就可以通过让 TPM 读取安全启动状态来自动解密根分区了,需要配合systemd-boot
使用(或者使用grub
引导 UKI 镜像)
检查 TPM 支持
首先检查 tpm 模块是否存在以及版本号
$ cat /sys/class/tpm/tpm0/device/description
TPM 2.0 Device
需要输出TPM 2.0 Device
也可以使用systemd-analyze
同时检查 TPM 2.0 和必要的软件依赖
$ systemd-analyze has-tpm2
yes
+firmware
+driver
+system
+subsystem
+libraries
+libtss2-esys.so.0
+libtss2-rc.so.0
+libtss2-mu.so.0
TIP
如果输出版本为 1.2 或没有输出的话,可能不是不支持 TPM 2.0,而是默认关闭了,可以进入 BIOS 检查是否有开启或切换版本的选项
如果支持,那么我们就可以为分区注册 TPM 了
在注册前,我们可以先看看当前已注册的解密方式
# systemd-cryptenroll /dev/sda2
SLOT TYPE
0 password
可以看到只有一个密码
也可以查看下已安装的 TPM 设备,如果有多个可以手动指定(虽然大部分人的电脑应该都只有一个)
$ systemd-cryptenroll --tpm2-device=list
PATH DEVICE DRIVER
/dev/tpmrm0 MSFT0101:00 tpm_crb
注册 TPM 到加密分区
WARNING
请在安全启动已成功启用的状态下注册!
# systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs=7 /dev/sda2
🔐 Please enter current passphrase for disk /dev/sda2: (press TAB for no echo)
New TPM2 token enrolled as key slot 1.
使用--tpm2-pcrs=7
来检测安全启动状态
输入你的解密密码,如果显示New TPM2 token enrolled as key slot 1.
就是注册成功了
NOTE
如果有多个的话,把--tpm2-device=auto
改成--tpm2-device=/dev/tpmrm0
或其他显示的路径来指定其中一个
这时再列出所有已注册的解密方式,就能看到 TPM 了
# systemd-cryptenroll /dev/sda2
SLOT TYPE
0 password
1 tpm2
启用自动解密
获取加密分区的 UUID
# blkid -s UUID -o value /dev/sda2
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
创建或编辑/etc/crypttab.initramfs
# nvim /etc/crypttab.initramfs
写入以下内容
cry0 UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx none tpm2-device=auto
NOTE
如果如果前面有指定的话,记得把这里的--tpm2-device=auto
也改成跟前面一致
再重新生成initramfs
镜像
# mkinitcpio -P
为 BIOS 设置密码
最后,在你的 BIOS 设置里设置一个管理员密码,否则攻击者同样可以轻而易举的进入你的 BIOS 关闭安全启动,那么我们做的这些事情就没有意义了