Portal:MicroOS/FDE
全盘加密 (FDE)
MicroOS 和 Tumbleweed 现在使用基于 systemd 的全盘加密镜像,适用于遵循启动加载程序规范 (BLS[1]) 的启动加载程序。
systemd-boot 启动加载程序以引入此规范而闻名,其中启动加载程序条目不是 EFI 分区 (类型#1) 中的小型配置文件,或者最近的 PE 包,它将 kernel、initrd 和命令行等元数据聚合在一个称为统一内核镜像或 UKI (类型#2) 的单个文件中。
最近,openSUSE 从 Fedora 移植了将在 GRUB2 中启用 BLS 类型#1 条目的补丁。其他启动加载程序,如 zipl (s390x) 或 Petitboot (PowerPC) 也支持 BLS,并且由于 systemd-boot 和 GRUB2 在 arm64 中受支持,因此 BLS 涵盖了我们关心的所有架构。
新的 MicroOS[2] 和 Tumbleweed[3] 镜像提出了一种基于 systemd 的全盘加密架构,该架构依赖于具有遵循 BLS 的启动加载程序。
使用 systemd,我们可以注册传统的密码,以及基于 TPM2 或 FIDO2 密钥的自动解锁。在 TPM2 的情况下,自动解锁仅在系统处于良好已知状态 (健康状态) 时发生,由测量启动[4] 确定,其中包括所有固件、安全启动证书、启动加载程序、kernel、initrd 和命令行。这意味着如果启动链中的某些内容已被更改 (例如,如果 initrd 不是我们在安装期间使用的那个),则 TPM2 将检测到更改并拒绝提供密码以解锁 LUKS2 设备,并会要求输入密码。
安装
这些镜像作为 qcow2 镜像部署给 KVM。它们可以通过 libvirt 在 QEMU 中运行,例如。运行它们的最直接方法是使用 virt-manager 或 virt-install 创建一个具有 UEFI 和 TPM2 的机器。
首先,从这里下载 sdboot 镜像 [8]。使用 libvirt 运行镜像的最简单命令如下
virt-install --name microos-sdboot \ --ram 2048 \ --boot uefi \ --tpm backend.type=emulator,backend.version=2.0,model=tpm-tis \ --import --file ./openSUSE-MicroOS.x86_64-kvm-and-xen-sdboot.qcow2 \ --osinfo opensuse-factory
请注意 --boot uefi 选项以启用 UEFI 和 -tpm 标志以启用模拟软件 tpm。虚拟机启动时会自动启动 virt-viewer。在首次启动期间,系统会询问您是否要加密当前设备,并在首次启动结束时,jeos-firstboot 将继续进行注册。
系统生成了一个很长的恢复密钥。需要安全地保存此密钥 (使用手机扫描二维码以快速访问密钥)。此密钥用于访问 LUKS2 rootfs 设备。
菜单将提供注册 TPM2 (如果检测到) 选项,并带有或不带有额外的 PIN。使用 TPM2,如果系统处于良好状态 (请参阅 [4] 中的测量启动),我们可以自动解锁设备。如果注册了 PIN,则在验证系统后会要求输入 PIN。如果两者匹配,则将释放解锁 LUKS2 密钥设备的密钥,并且启动过程将继续。
如果在注册过程中检测到 FIDO2 密钥,菜单将提供注册它的选项。并非所有 FIDO2 密钥都可以注册,它们需要支持 hmac-secret 扩展。要查看我们的密钥是否支持它,一种选择是查看它是否可以列出
systemd-cryptenroll --fido2-device=auto "$DEV"
可选地,我们可以注册根密码或新密码。
恢复密钥也用作 TPM2 与 systemd-pcrlock (默认选项) 注册时使用的恢复 PIN。不要将恢复 PIN 与为 TPM2 + PIN 注册选项创建的 PIN 混淆。当预测失败并且我们需要注册新的预测时,将使用恢复 PIN,而无需修改所有加密设备的 LUKS2 标头,这需要进行繁琐的重新注册过程。
现在可以正常操作系统了。在更改启动链中某些组件的更新之后,将生成新的 TPM2 预测,因此下一次重新启动仍然会将系统视为健康状态,并且不会要求密码来打开 LUKS2 设备。
您可以通过运行以下命令来检查系统是否正在使用全盘加密 (将 /dev/vda3 替换为您的磁盘,如果不同)
systemd-cryptenroll /dev/vda3
该命令将显示所有密钥槽,包括 fido2 和 tpm (如果一切正常)。
使用 YaST 安装
如今,YaST2 完全支持使用 BLS 启动加载程序 (Tumbleweed 的默认 grub2-bls 和 MicroOS 的 systemd-boot) 以及通过 systemd 进行用户空间全盘加密的系统安装。
简而言之
对于 openSUSE MicroOS 和 Tumbleweed,安装步骤几乎相同
- 使用 YaST2 引导或专家分区程序为每个分区选择“基于 systemd 的全盘加密”
- 设置密码并选择 argon2id 密钥派生函数
- 可选地,选择 TPM2、TPM2+PIN 或 FIDO2 密钥作为身份验证
- 检查是否选择了 grub2-bls 作为启动加载程序
- 忽略一些投诉 (bsc#1244755)
就这样了,真的。
MicroOS 和 Tumbleweed 的详细说明
由于 YaST2 已经支持这种安装方式,因此整个过程直接而简单。
首先需要下载 MicroOS DVD 镜像[7] 或 Tumbleweed 镜像。请记住,为了正确安装,我们需要一个带有 TPM2 的 UEFI 系统。
启动正常安装,并在 建议 分区中选择 专家分区程序 / 从当前建议开始。
在 专家分区程序 中,我们可以开始删除两个 GRUB2 子卷:@/boot/grub2/i386-pc 和 @/boot/grub2/x86_64-efi,如果存在 (MicroOS) @/boot/writable。这将在未来自动完成。
在 MicroOS 中,您将看到两个分区,一个包含 rootfs,另一个用于 /var,但在 Tumbleweed 中,您将拥有 rootfs 和 swap。选择一个,按 编辑.. 按钮并启用 加密设备 复选框。
在下一个窗口中,选择的 加密方法 应为 基于 systemd 的全盘加密。填写加密密码,并在 基于密码的密钥派生函数 中选择 Argon2id。最后,在 身份验证 框中设置 TPM2 或 TPM2+PIN。后者将使用 TPM2 来验证系统的健康状况,但要解锁设备,需要输入 PIN 或密码。为了简单起见,将设置为解锁 LUKS2 设备的相同密码,但以后可以在终端中更改它。
忽略有关 LUKS2 和 GRUB2 支持的警告。自动选择的启动加载程序将是 grub2-bls 或 systemd-boot,具体取决于发行版,并且此警告不适用。
加密 /var 或 swap 后,专家分区程序 屏幕会将所有分区标记为加密,并且 grub2 子卷将不再存在。
返回 建议分区 屏幕,YaST2 将显示使用 TPM2 的设备,并且最终屏幕 安装设置 将显示 grub2-bls 作为选定的启动加载程序。
安装后,系统将重新启动,并在终端中检查所有分区是否已加密以及是否正在使用 TPM2。例如,在我的 VM 中
localhost:~ # lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS sr0 11:0 1 1024M 0 rom vda 253:0 0 20G 0 disk ├─vda1 253:1 0 512M 0 part /boot/efi ├─vda2 253:2 0 8.2G 0 part │ └─cr_root 254:1 0 8.2G 0 crypt /usr/local │ /srv │ /opt │ /home │ /.snapshots │ /root │ / └─vda3 253:3 0 11.3G 0 part └─cr_var 254:0 0 11.3G 0 crypt /var
localhost:~ # systemd-cryptenroll /dev/vda2
SLOT TYPE
0 password
1 tpm2
localhost:~ # systemd-cryptenroll /dev/vda3
SLOT TYPE
0 password
1 tpm2
不使用 YaST 安装
如果已经有一个带有 LUKS2 设备的系统,我们可以手动注册设备以使用 TPM2。
sdbootutil enroll --ask-pin --method=tpm2
方法也可以是 tpm2+pin 和 fido2。我们可以验证注册。
localhost:~ # systemd-cryptenroll /dev/vda2
SLOT TYPE
0 password
1 tpm2
localhost:~ # systemd-cryptenroll /dev/vda3
SLOT TYPE
0 password
1 tpm2
localhost:~ # cat /etc/default/fde-tools
localhost:~ # ls /boot/efi/EFI/systemd/*.json
如果列出的 json 文件是 pcrlock.json,我们通过 systemd-pcrlock 注册了系统,但由于并非所有 TPM2 都支持 NVIndex 策略,因此我们可能会找到 tpm2-pcr-signature.json。这意味着我们正在使用 pcr-oracle 和签名策略。
从 GRUB2-EFI 迁移
如果我们正在使用传统的 GRUB2 并且想要迁移到 grub2-bls 或 systemd-boot,通常无法做到。主要原因是 ESP 的大小。默认情况下是 256Mb,但我们需要大约 1Gb (MicroOS 的 512Mb 应该可以)。如果您设法在不破坏系统的情况下扩大分区,例如使用 gparted 或 KDE 分区管理器,那么我们可以进行迁移!
首先检查我们是否可以正确地 ESP 分区,该分区具有 vfat 文件系统,并且足够大。
# Check that there is a ESP of type "vfat" and is at least 512Mb / 1GB findmnt /boot/efi -o fstype -n df "$(findmnt /boot/efi -o source -n)"
BLS 启动加载程序将从 /etc/kernel 读取内核 cmdline 和条目令牌。
mkdir /etc/kernel # For Tumbleweed use "opensuse-tumbleweed" echo "opensuse-microos" > /etc/kernel/entry-token # Read the cmdline from "cat /proc/cmdline", and remove "root=" or # "BOOT_IMAGE=" entries echo "quiet systemd.show_status=yes console=ttyS0,11520 console=tty0 security=selinux selinux=1" > /etc/kernel/cmdline # In Tumbleweed we can use other cmdlines like: # "rw quiet systemd.show_status=1 console=ttyS0,11520 console=tty0 security=selinux selinux=1" # "splash=silent quiet security=selinux selinux=1 mitigations=off" > /etc/kernel/cmdline
在安装新的启动加载程序之前,我们需要编辑 /etc/sysconfig/bootloader 并更改 LOADER_TYPE 和其他字段,具体取决于启动加载程序。
# If we will use grub2-bls: # LOADER_TYPE="grub2-bls" # or if we use systemd-boot: # LOADER_TYPE="systemd-boot" # If SECURE_BOOT is "yes", be sure that shim is installed # Also check that: # UPDATE_NVRAM="no" vim /etc/sysconfig/bootloader
现在我们可以删除 GRUB2 并安装新的启动加载程序。
zypper rm grub2-common zypper in sdbootutil grub2-x86_64-efi-bls # If we use systemd-boot: # zypper in sdbootutil systemd-boot
我们应该删除旧启动加载程序的一些残留物,并清理 ESP。还有一些子卷可以删除。
rm -fr /boot/.vmlinuz* /boot/System.map* \
/boot/config* /boot/initrd* \
/boot/sysctl.conf* /boot/vmlinuz* \
/boot/grub2 /boot/efi/*
rm /etc/default/grub.*
# Remove the GRUB2 subvolumes
umount /boot/grub2/x86_64-efi
umount /boot/grub2/i386-pc
btrfs subvolume list /
# ...
# ID 263 gen 301 top level 256 path @/boot/grub2/x86_64-efi
# ID 264 gen 88 top level 256 path @/boot/grub2/i386-pc
# ...
btrfs subvolume delete --subvolid <first id from above> /
btrfs subvolume delete --subvolid <second id from above> /
# Remove both subvolumes from fstab
vim /etc/fstab
我们现在准备好将启动加载程序安装到 ESP 中。
sdbootutil install sdbootutil add-all-kernels
最后,我们可以清除旧的 EFI 启动条目。
efibootmgr # ... # Boot0004* openSUSE Boot Manager (grub2-bls) HD(1,GPT,79453660-ce11-4ac9-ab92-ed60cc14e163,0x800,0x1db800)/File(\EFI\opensuse\shim.efi) # Boot0005* opensuse-secureboot HD(1,GPT,79453660-ce11-4ac9-ab92-ed60cc14e163,0x800,0x1db800)/File(\EFI\opensuse\shim.efi) # ... efibootmgr -B -b 5
并重新启动。
工作原理
关于这内部工作原理的某种详细描述可以在 openSUSE wiki[5] 和初始公告[6] 中找到。
以下是简短版本。
如前所述,测量启动[4] 是一个评估系统健康状况的过程。当机器启动时,在一些初始化之后,固件的组件将检查是否存在 TPM2 设备。这个多方面的设备可以用作某些测量中“信任根”,这些测量可以在系统中进行。
这意味着固件可以计算启动过程的下一个组件的哈希值,并以加密方式扩展 TPM2 内部的内部寄存器,称为 PCR,以注册计算的哈希值。扩展操作只是将计算的哈希值与当前寄存器值附加起来,然后再次计算复合值的哈希值。这将是新寄存器的值。
此操作使得无法将特定值写入其中一个寄存器,并且最终值只能通过复制用于扩展寄存器的值的序列来重现。这意味着如果由于某种原因其中一个值不同,则 PCR 的最终值将与预期值非常不同。
这是测量启动的核心。启动链的每个组件 (UEFI 固件中的多个步骤、shim 启动加载程序、启动加载程序本身、kernel 和 initrd) 将加载链中的下一步,计算内存块 (或数据) 的哈希值,并按照公共规范扩展其中一个 PCR。TPM2 内部寄存器的最终值代表系统的状态。
TPM2 可用于加密 (密封) 一些数据,例如密码,基于期望的寄存器值,以便如果寄存器匹配某些值,则 TPM2 可以解密 (在行话中解封) 数据。这意味着我们可以使用 TPM2 来存储 LUKS2 设备的密钥,并且只有当此系统处于良好状态时,该密钥才会返回给系统。
systemd-cryptsetup 生成器在 initrd 中会非常早地读取 /etc/crypttab,并为每个加密设备生成一个适配的 systemd-cryptsetup 服务。该服务将检查 LUKS2 设备是否可以使用当前策略打开,如果所有匹配都通过,则会执行打开操作。为了避免冒名顶替设备,此服务(如果通过 /etc/crypttab 中的 tpm2-measure-pcr=yes 配置)将读取设备的卷密钥并扩展 PCR 15。要读取此密钥,设备需要先打开,这意味着 TPM2 验证必须先发生,并且 PCR 15 不能参与策略。有一个名为 measure-pcr-validator 的服务,它在 initrd 的 switch root 之前执行,将验证此 PCR 15,如果验证失败,它将停止(冻结)系统,以避免访问错误的设备。可以使用 measure-pcr-validator.ignore=yes 在 cmdline 中避免此停止。
这是无需在每次启动后请求密码的 FDE 的基础,并且 systemd 以及 systemd-cryptenroll 和其他工具承诺提供此功能。推荐的 systemd 方法需要通过 dm-verity 和 UKI 为内核使用只读设备。但是,openSUSE MicroOS 和 Tumbleweed 项目创建了一组工具,该架构实例化了此发行版,但适应了当前状态(分离的 kernel 和 initrd,基于 btrfs 快照的事务等)
使用的新工具是
- disk-encryption-tool
- sdbootutil
- dracut-pcr-signature
disk-encryption-tool 仅存在于基于镜像的发行版中,将在首次启动时负责加密镜像。这样做将保证为每个系统生成一个新的主密钥,并且不会在镜像中存储与某些恢复密码共享的 LUKS2 密钥槽。此工具还将使用 jeos-firstboot 进行初始注册,使用 systemd-cryptenroll 和下一个工具 sdbootutil。
传统 GRUB2 中的启动条目管理与遵循 BLS 的引导加载程序使用的启动条目管理非常不同。当生成新的快照时,需要将新的内核从 rootfs 复制到 ESP(UEFI 所需的 FAT32 分区,在 openSUSE 中位于 '/boot/efi')中的特定位置。如果需要,需要重新生成一个新的 initrd,或者重用旧的 initrd。并且需要创建一个启动条目,一个小的配置文件,用于链接 kernel、initrd 和指向正确的 btrfs 子卷的 cmdline。所有这些管理都由 sdbootutil 完成。
此外,需要进行新的预测才能在不使用密码的情况下启动新的快照。此预测是一种考虑不同 PCR 值组合的策略。sdbootutil 也会使用 systemd-pcrlock 或 pcr-oracle 生成这些预测,具体取决于在注册期间自动选择的策略类型。
该预测包括 TPM2 策略以及将测量不同加密磁盘的卷密钥的预期 PCR 15 值。此外,sdbootutil 还在相同的 ESP 中提供验证器服务,该服务将检查此 PCR #15 值。
默认情况下,选择 systemd-pcrlock 生成的 NVIndex 类型的策略,但也可以通过 pcr-oracle 生成签名策略,本文档稍后将解释如何迁移。建议坚持使用 NVIndex 策略,并将策略存储在 TPM2 内部。这种类型的策略需要使用之前提到的恢复 PIN 来生成来自预测错误的系统的新的预测,并使用恢复密码来解锁设备。
最后,dracut-pcr-signature 是一个小的 dracut 模块,用于在 initrd 中,它会将策略和预期的 PCR #15 值从 ESP 复制到内存中的 initrd 中,以便 systemd-cryptsetup 可以使用 TPM2 策略来解封 LUKS2 密码。
所有这些组件协同工作。disk-encryption-tool 将执行磁盘的初始加密以及不同密码和安全设备的注册,以进行自动解密。sdbootutil 将负责日常引导加载程序条目管理,确保为下一次启动生成新的预测,始终在新的组件(如 kernel 等)之前进行测量。最后,通过 dracut-pcr-signature,我们保证 TPM2 策略在 initrd 可以解锁设备之前可用,这样就不需要在磁盘上的 initrd 上进行修改。
Combustion
我们可以通过 Combustion 进行注册,跳过 jeos-firstboot 交互式模块。
该过程分为两个阶段。在第一阶段,我们将配置 disk-encryption-tool-dracut 服务(从 initrd 运行)在 Combustion 的 --prepare 阶段,创建一个未加密的凭据,这将强制磁盘加密而无需等待超时。加密将在 initrd 阶段的非常晚期发生,就在 Ignition 和 Combustion 完成时。
在第二阶段,我们将创建一个加密的凭据集,以与第二个服务 sdbootutil-enroll 通信,该服务将在首次启动期间执行,并使用 TPM2 进行注册。
#!/bin/bash
# combustion: network prepare
# script generated with https://opensuse.github.io/fuel-ignition/
if [ "${1-}" = "--prepare" ]; then
# We set disk-encryption-tool-dracut.encryption credential to
# "force". This will make disk-encryption-tool-dracut force the
# encryption, ignoring that Combusion configured the system, and
# will skip the permission countdown
#
# After the encryption the recovery key is registered in the
# kernel keyring %user:cryptenroll
mkdir -p /run/credstore
echo "force" > /run/credstore/disk-encryption-tool-dracut.encrypt
exit 0
fi
# Redirect output to the console
exec > >(exec tee -a /dev/tty0) 2>&1
# Create a valid machine-id, as this will be required to create later
# the host secret
systemd-machine-id-setup
# We want to persist the host secret key created via systemd-cred
# (/var/lib/systemd/credential.secret)
mount /var
mkdir -p /etc/credstore.encrypted
credential="$(mktemp disk-encryption-tool.XXXXXXXXXX)"
# Enroll recovery key
echo "1" > "$credential"
systemd-creds encrypt --name=sdbootutil-enroll.rk "$credential" \
/etc/credstore.encrypted/sdbootutil-enroll.rk
# Enroll extra password
echo "SECRET_PASSWORD" > "$credential"
systemd-creds encrypt --name=sdbootutil-enroll.pw "$credential" \
/etc/credstore.encrypted/sdbootutil-enroll.pw
# # Enroll TPM2 with secret PIN
# echo "SECRET_PIN" > "$credential"
# systemd-creds encrypt --name=sdbootutil-enroll.tpm2+pin "$credential" \
# /etc/credstore.encrypted/sdbootutil-enroll.tpm2+pin
# Enroll TPM2
echo "1" > "$credential"
systemd-creds encrypt --name=sdbootutil-enroll.tpm2 "$credential" \
/etc/credstore.encrypted/sdbootutil-enroll.tpm2
# # Enroll FIDO2
# echo "1" > "$credential"
# systemd-creds encrypt --name=sdbootutil-enroll.fido2 "$credential" \
# /etc/credstore.encrypted/sdbootutil-enroll.fido2
shred -u "$credential"
# Umount back /var to not confuse tukit later
umount /var
# Leave a marker
echo "Configured with combustion" > /etc/issue.d/combustion
# Close outputs and wait for tee to finish.
exec 1>&- 2>&-; wait;
故障排除
调试跟踪日志记录(可选)
为了帮助诊断问题,sdbootutil 可以将详细的 shell 跟踪输出到一个专用的日志文件。此功能默认关闭,仅当存在特定的日志文件时才激活。
它做了什么
启用后,sdbootutil 脚本执行的每个 shell 命令都会被跟踪到 /var/log/sdbootutil.log。每行都带有时间戳,并带有脚本名称、行号和函数注释,使其易于跟踪执行路径。
如何启用
创建日志文件(以 root 身份),并在运行要调试的操作(例如,注册、更新预测等)之前 确保具有限制性权限,例如使用
touch /var/log/sdbootutil.log chmod 600 /var/log/sdbootutil.log
如何验证它是否有效
运行操作(例如,sdbootutil update-predictions)并观察日志
tail -f /var/log/sdbootutil.log
您应该看到以 + 开头并包含时间戳、脚本名称、行和函数的行。
如何禁用
删除或重命名文件。仅当文件存在时才激活跟踪。
捕获的内容
sdbootutil 和相关辅助脚本的 shell 跟踪(正在执行的命令)
时间戳和源代码上下文(文件、行、函数)
未捕获的内容
其他程序的正常 stdout/stderr(这些仍然会进入它们通常的目的地)
内核/dracut/systemd 调试输出(例如,rd.debug、systemd.log_level=debug)——单独使用这些来获取 initrd/早期启动的详细信息
安全注意事项
命令参数和环境变量值可能会出现在跟踪中。将 /var/log/sdbootutil.log 视为敏感数据。如果在启用调试的情况下输入密码或卷密钥,它们将被捕获。
仅在需要时启用跟踪,因为它可能会导致长时间启用时产生大型日志文件。
限制
非常早期的 initrd 阶段可能不会在此处记录;更喜欢 dracut/journald 调试。
跟踪仅影响 sdbootutil 脚本。它不会更改其他服务的全局日志记录。
LUKS2 密钥槽
列出系统中注册的密钥槽。
DEV=/dev/vda3 systemd-cryptenroll "$DEV"
应该列出至少一个“recovery”和一个“tpm2”密钥。如果根密码也在注册期间注册,则也会显示一个“password”密钥。
要删除未使用的槽,请使用 --wipe-slot=,要注册新的“password”或“recovery”密钥,请使用 --password 或 --recovery-key 参数。任何更改都需要输入其中一个密码。
PCRs
如果使用 systemd-pcrlock,则跟踪的 PCR 位于 /etc/sysconfig/fde-tools 中。
可以使用 systemd-pcrlock 检查这些寄存器的当前值。由于直到 systemd v257 才将其标记为实验性的,因此它位于 /usr/lib/systemd 中。
可以使用相同的工具检查事件日志。对于每个 PCR 扩展,事件日志中都有一条记录,记录 PCR 索引、扩展的值和描述扩展目的的一些元数据。也可以使用相同的 systemd-pcrlock 工具检查此信息。
PCR #15
为了避免一种攻击,该攻击将用具有相同 UUID 或设备名称的恶意设备替换加密设备,如果 /etc/crypttab 中的设备选项中存在 tpm2-measure-pcr=yes,则 systemd-cryptsetup 可以使用设备卷密钥扩展 PCR #15。
此扩展发生在设备打开(并且应用了 TPM2 策略)之后,因为只能使用与其中一个密钥槽关联的密码检索卷密钥。这意味着 PCR #15 不能参与 TPM2 策略。
由 sdbootutil update-predictions 在 /var/lib/sdbootutil 和 ESP 中创建并签名的 PCR #15 预测文件,如果文件丢失或自上次更新以来 /etc/crypttab 已更改。
默认情况下,每次命令 update-predictions 时都不会更新此文件,因为这需要用户交互才能请求恢复设备卷密钥的密码。
如果主密钥已更改,我们可以通过 sdbootutil update-preditions --measure-pcr 强制重新创建文件
measure-pcr-validator 服务将验证预测文件的签名,并将其与当前 PCR #15 值进行比较。这在所有参与 initrd 的加密设备都以固定顺序打开后完成,以保证最终值始终相同。
如果预测失败,系统将在 switch root 发生之前停止(冻结),并且 rogue 设备中的程序没有机会控制。在检查设备安全且存在错误预测后,我们可以通过在 cmdline 中添加 measure-pcr-validator.ignore=yes 来跳过停止,以继续启动过程并修复问题。
策略
当使用 pcrlock 时,会生成一系列 JSON 文件来表示在启动期间测量的不同组件。它们存储在 /var/lib/pcrlock.d 中,并由 sdbootutil 编排。
这些组件可以将多个测量组合到一个文件中,表示隐式 AND 操作。一个组件可以有多个变体,表示 OR 操作。
systemd-pcrlock 将尝试将当前的事件日志与呈现的组件中的不同哈希对齐,如果存在匹配,它将在 systemd-pcrlock 表中的一列中呈现。
请注意,如果事件日志中没有与某个条目关联的组件,则我们无法制定包含此 PCR 的策略。
当创建新策略时,systemd-pcrlock 的输出可能会有些令人困惑。例如,如果无法将 PCR 预测包含在策略中(因为当前的组件哈希与事件日志中的哈希不匹配,因此无法映射),则策略将在此次排除此 PCR 创建。
为了增加详细程度,建议以这种方式执行 sdbootutil
SYSTEMD_LOG_LEVEL=debug sdbootutil update-predictions
生成的策略(好吧,策略元数据,因为实际的策略位于 TPM2 内部)存在于两个地方。规范的是在 /var/lib/systemd/pcrlock.json 中。一份副本会复制到 ESP 中,即 /boot/efi/EFI/{systemd,opensuse}/pcrlock.json,以便稍后可以被 dracut-pcr-signature 找到。
如果重新启动后要求输入恢复密码(或者如果我们注册了一个额外的密码,则输入第二个密码),我们可以调试不匹配的原因。
使用 systemd-pcrlock 表,我们可以在“component”列中找到没有为我们跟踪的 PCR 分配的行。此表还显示预期的哈希值,因此我们可以通过检查 /var/lib/systemd/pcrlock.d 中注册的组件来找到不匹配的哈希值。
例如,如果看到 PCR#4(boot-loader-code)对于名为“efi-boot-services-application”的最后一个事件缺少组件,并且在描述列中看到内核的路径,我们知道失败的组件是内核,组件文件是“650-kernel-efi-application”。
在进行重新注册(下一节)之前,我们需要了解这种不匹配是预测代码中的错误,我们忘记在手动更改 ESP 中的内核后更新预测,还是有人篡改了内核,从而危及系统!
重新注册
当预测系统失败时,我们需要为新的测量值生成新的策略,并替换存储在 TPM2 中的策略。为此,我们需要与恢复密钥匹配的恢复 PIN(在注册期间生成的用于手动解锁 LUKS2 设备的漫长的密码)
在 Tumbleweed 的 QEMU 下使用 FDE 时,如果 PCR 0 用于密封 LUKs2 密钥(这是默认配置),则 OVMF 或 QEMU 本身的更新可能需要重新注册。这是因为主机更改了用于启动 VM 的固件,现在新的固件在启动后为 PCR 0 生成不同的值。
我们可以通过输入 PIN 强制重新注册
sdbootutil --ask-pin update-predictions
环境变量 PIN 也可以使用
PIN=... sdbootutil update-predictions
完全重新注册(丢失恢复 PIN)
如果由于某种原因我们丢失了恢复 PIN,那么我们需要手动进行重新注册。当然,我们需要拥有一些密码或 FIDO2 密钥才能访问系统并解锁设备,否则无能为力!
# Add a LUKS password sdbootutil enroll --ask-pw --method=password # alternative: Add or Replace a LUKS recovery key sdbootutil enroll --method=recovery-key # NOTE: Adding a new access method is only needed if no other access has been configured so far!
# Remove the current TPM policy and unenroll the devices sdbootutil unenroll --method=tpm2
# Make a new policy and enroll all devices PIN=<selected recovery PIN> sdbootutil enroll --method=tpm2
最后两个命令等效于
# Remove the old policy from the TPM2 and from the system /usr/lib/systemd/systemd-pcrlock remove-policy
# Drop the "tpm2" keyslot from the LUKS2 each device systemd-cryptenroll --wipe=tpm2 $DEV
# Generate predictions and policy, and register it in the TPM2's NVRAM PIN=... sdbootutil update-predictions
# For each device, we update the LUKS2 header creating a new keyslot systemd-cryptenroll --tpm2-device=auto $DEV
请注意,重新注册需要为所有设备完成。
“启动选项恢复”蓝屏
如果从新镜像启动,将显示一个带有 5 秒倒计时的蓝屏,然后将正常重新启动。此屏幕来自 fallback.efi(shim 包),它正在为镜像注册第一个 EFI 启动条目。这可能会令人困惑,但这不是错误。下一次启动将直接进入新的条目,并且不会再次显示该镜像。
更多信息请参见 fallback README
迁移
我们可以使用以下命令从 NVIndex(pcrlock)迁移到签名策略(pcr-oracle)
# Remove the policy from the TPM2 and from the system /usr/lib/systemd/systemd-pcrlock remove-policy
# Remove systemd-experimental package (reboot, as sdbootutil should # not find systemd-pcrlock) transactional-update pkg rm systemd-experimental
# Remove .pcrlock files with components and variants rm -fr /var/lib/pcrlock.d
# Remove pcrlock.json in /var and ESP rm /var/lib/systemd/pcrlock.json rm /boot/efi/EFI/systemd/pcrlock.json
# Generate a RSA key pair
pcr-oracle \
--rsa-generate-key \
--private-key /etc/systemd/tpm2-pcr-private-key.pem \
--public-key /etc/systemd/tpm2-pcr-public-key.pem \
store-public-key
# Drop the "tpm2" keyslot from the LUKS2 device systemd-cryptenroll --wipe-slot=tpm2 $DEV
# Enroll the private key systemd-cryptenroll \ --tpm2-device=auto \ --tpm2-public-key=/etc/systemd/tpm2-pcr-public-key.pem \ --tpm2-public-key-pcrs=0,2,4,9 \ $DEV
# Generate new predictions with pcr-oracle sdbootutil update-predictions
要迁移回来
# Install systemd-experimental (reboot, as sdbootutil should find # systemd-pcrlock) transactional-update pkg in systemd-experimental
# Remove public and private keys fron /etc and public from ESP rm /etc/systemd/tpm2-pcr-private-key.pem rm /etc/systemd/tpm2-pcr-public-key.pem rm /boot/efi/EFI/systemd/tpm2-pcr-public-key.pem
# Remove signed policy from /etc and ESP rm /etc/systemd/tpm2-pcr-signature.json rm /boot/efi/EFI/systemd/tpm2-pcr-signature.json
# Drop the "tpm2" keyslot from the LUKS2 device systemd-cryptenroll --wipe-slot=tpm2 $DEV
# Generate predictions and policy, and register it in the TPM2's NVRAM sdbootutil update-predictions
# Enroll the keyslot in the LUKS2 device. Will ask for the recovery # password systemd-cryptenroll \ --tpm2-device=auto \ --tpm2-pcrlock=/var/lib/systemd/pcrlock.json \ $DEV
资源
[1] Boot Loader Specification: https://uapi-group.org/specifications/specs/boot_loader_specification/
[2] MicroOS image: https://build.opensuse.org/package/show/openSUSE:Factory/openSUSE-MicroOS
[3] Tumbleweed image: https://build.opensuse.org/package/show/openSUSE:Factory/kiwi-templates-Minimal
[4] Measured boot: https://en.opensuse.net.cn/Portal:MicroOS/RemoteAttestation#Measured_boot
[5] Systemd FDE: https://en.opensuse.net.cn/Systemd-fde
[6] Systemd-boot and Full Disk Encryption in Tumbleweed and MicroOS: https://news.opensuse.net.cn/2023/12/20/systemd-fde/
[7] MicroOS installer: https://get.opensuse.net.cn/microos/
[8] MicroOS sdboot 镜像:https://download.opensuse.org/tumbleweed/appliances/openSUSE-MicroOS.x86_64-kvm-and-xen-sdboot.qcow2






