通过TPM解锁LUKS※
操作系统:Arch Linux
前提:已开启 Unified Kernel Image (UKI) 或可选,普通 initramfs 亦可(推荐 UKI 以配合 Secure Boot/TPM)。
前置要求检查※
# 1. 确认 TPM 2.0 可用(优先 /dev/tpmrm0,支持资源管理器,并发更安全)
ls /dev/tpm* # 应显示 /dev/tpm0 和 /dev/tpmrm0
journalctl -k --grep=tpm
# 2. 确认 LUKS 版本(必须为 LUKS2)
sudo cryptsetup luksDump /dev/nvme0n1p2 | grep "Version"
# 3. 确认 systemd 版本(建议 ≥ 250,最佳 ≥ 255 以使用 pcrlock 等新特性)
systemd --version
步骤总览※
- 确认磁盘加密与分区布局(root 使用 LUKS)。
- 安装依赖:systemd-cryptenroll、systemd-boot(或 GRUB)、dracut/mkinitcpio、tpm2-tools。
- 为 LUKS 卷注册 TPM 解锁密钥(systemd-cryptenroll)。
- 在 initramfs/UKI 中启用 systemd-cryptsetup 自动解锁逻辑。
- 配置内核命令行:指定加密设备与映射名。
- 重建 initramfs/UKI,更新引导项。
- 测试与回退策略。
1. 确认目标设备※
# 找到加密分区(示例)
lsblk -o NAME,TYPE,MOUNTPOINT,UUID
blkid
# 假设加密设备为 /dev/nvme0n1p2,LUKS UUID 为 <CRYPT_UUID>
cryptsetup luksUUID /dev/nvme0n1p2 # 获取 LUKS 头的 UUID
# 说明:blkid 显示的 UUID=... TYPE="crypto_LUKS" 就是 LUKS UUID,用于 rd.luks.name/crypttab
# 不要使用分区的 PARTUUID(如 f4f6...1684)来替代 LUKS UUID
2. 安装依赖※
sudo pacman -S --needed systemd tpm2-tools cryptsetup
# 使用 systemd-boot:bootctl 由 systemd 提供,无需单独安装包
# 在 EFI 模式下安装到 ESP(默认 /boot 或 /efi,按你的挂载点):
sudo bootctl install
# 或者使用 GRUB:
sudo pacman -S --needed grub efibootmgr
3. 通过 TPM 注册 LUKS 密钥※
为 LUKS2 卷添加基于 TPM 的 keyslot。
# 推荐:在较新 systemd 中使用 --tpm2-device=auto(自动选择 /dev/tpmrm0)
sudo systemd-cryptenroll /dev/nvme0n1p2 --tpm2-device=auto
# 绑定 PCR(提升完整性保证,更新需重新注册)
# 常用:PCR 7(Secure Boot)+ PCR 11(UKI 测量)
sudo systemd-cryptenroll /dev/nvme0n1p2 --tpm2-device=auto --tpm2-pcrs=7+11
# 可选:启用 PIN(增加实体安全;留意输入尝试次数与速率限制)
sudo systemd-cryptenroll /dev/nvme0n1p2 --tpm2-device=auto --tpm2-with-pin --tpm2-pcrs=7+11
# 查看结果(应看到 systemd-tpm2 token)
sudo cryptsetup luksDump /dev/nvme0n1p2
# 验证 TPM 解锁(关键自检)
sudo systemd-cryptenroll /dev/nvme0n1p2 --tpm2-device=auto --unlock-tpm2
# 回退与重注册:
# - PCR 变化、Secure Boot 状态变更、UKI 更新后若解锁失败:
# 使用密码解锁 -> 擦除旧 tpm2 槽并重新注册
sudo systemd-cryptenroll /dev/nvme0n1p2 --wipe-slot=tpm2
sudo systemd-cryptenroll /dev/nvme0n1p2 --tpm2-device=auto --tpm2-pcrs=7+11
PCR 选择说明:(参考:TPM PCR Registry)
- PCR 0-7: UEFI 固件和 Secure Boot 配置
- PCR 11: 统一内核镜像(UKI)测量值(内容或命令行改变会影响)
- 推荐组合:
7+11或7 - 不绑定 PCR: 灵活但安全性最低,适合测试环境
4. 启用 systemd 自动解锁※
使用 systemd-cryptsetup-generator 时,可通过内核参数与 /etc/crypttab.initramfs 或加密 UUID 自动识别。
# 方式A:crypttab(适用于 mkinitcpio 或 dracut 生成的 initramfs)
sudo sh -c 'cat >/etc/crypttab.initramfs' << EOF
cryptroot UUID=<CRYPT_UUID> none luks,discard
EOF
# 方式B:纯内核参数(systemd-stable,更简洁)
# 在内核 cmdline 中添加(示例):
# rd.luks.name=<CRYPT_UUID>=cryptroot rd.luks.options=discard
5. 配置内核命令行※
# 对于 systemd-boot(UKI 或常规):
# 编辑 /etc/kernel/cmdline 或 /etc/default/bootloader/cmdline(视你的设置而定)
# 若使用 systemd + sd-encrypt(推荐,与本指南一致),示例:
rd.luks.name=e84c20b1-5675-4d3d-9d44-c14e58cf4630=cryptroot
root=/dev/mapper/cryptroot rw rootfstype=btrfs rootflags=subvol=@
# 可选:rd.luks.options=discard
# 说明:root= 要与映射名一致,上例 rd.luks.name 映射为 cryptroot,因此 root=/dev/mapper/cryptroot
# 仅当仍使用传统 encrypt 钩子时才用 cryptdevice=PARTUUID=...:root
# 且 root=/dev/mapper/root;若切换到 sd-encrypt,请改为 rd.luks.name 并同步 root 映射名。
6. 重建 initramfs/UKI 并更新引导※
# mkinitcpio
sudo sed -i 's/^HOOKS=.*/HOOKS=(systemd autodetect modconf block keyboard sd-encrypt filesystems)/' /etc/mkinitcpio.conf
sudo mkinitcpio -P # 若 preset 含 -U,会自动用 /usr/lib/kernel/uki.conf + ukify 生成 /boot/EFI/Linux/arch-linux.efi
# 若 preset 已自动生成 UKI,则无需手动运行 ukify。
# dracut(替代方案)
sudo dracut --force
7. 测试与回退※
# 先不重启,验证 TPM 与 tpm2-tools工作
tpm2_getrandom 8
# 验证 TPM 解锁(关键测试!)
sudo systemd-cryptenroll /dev/nvme0n1p2 --tpm2-device=auto --unlock-tpm2
# 生成救援盘(强烈建议)
# 保留可用的密码 keyslot,避免仅依赖 TPM
# 可准备一个 Live USB(archiso)以便失败后恢复
# 重启测试:若 TPM 解锁失败,应仍可提示密码输入。
故障排查要点※
- 确认 LUKS 卷为 LUKS2;TPM 仅在 systemd-cryptenroll 下对 LUKS2 支持最佳。
- 确认 initramfs 包含 sd-encrypt(mkinitcpio 的 systemd HOOK)或 dracut 对应模块。
- 确认内核参数包含 rd.luks.name=UUID=cryptroot 与 root=/dev/mapper/cryptroot。
- 若绑定 PCR,更新内核/UKI/bootloader 后可能需重新 enroll。
- Secure Boot 下需保证签名链一致,否则 PCR 不匹配导致解锁失败。
- 若使用 systemd-boot:确保以 UEFI 模式启动,ESP 已正确挂载,bootctl install 成功。
- bootctl 警告 random-seed 权限:
- 修复挂载点权限:sudo chmod 700 /boot
- 修复随机种子文件:sudo chown root:root /boot/loader/random-seed && sudo chmod 600 /boot/loader/random-seed
- 说明:该警告不影响安装成功,但建议修复以避免潜在安全风险。
- systemd-cryptenroll 报 “option '--tpm2' is ambiguous”:
- 说明:你的 systemd 版本不支持裸
--tpm2开关。 - 改用:
systemd-cryptenroll <dev> --tpm2-device=auto [--tpm2-pcrs=...] [--tpm2-with-pin]
- 说明:你的 systemd 版本不支持裸
- 如 mkinitcpio preset 已含 -U,UKI 由 mkinitcpio 自动生成至 /boot/EFI/Linux/arch-linux.efi,无需重复手动 ukify。
- TPM 解锁失败常见原因:
- PCR 值变化:更新内核、bootloader、固件后 PCR 重新测量
- Secure Boot 状态改变:关闭/开启 Secure Boot 会改变 PCR 7
- TPM 被锁定:BIOS 中 TPM 状态改变(Clear/Disabled)
- 内核参数改变:影响 PCR 11(UKI 场景)
- emergency shell 密码回退:如启动时 TPM 解锁失败且没有提示密码,检查:
- initramfs 是否包含 systemd 和 sd-encrypt(不是 encrypt)
- 内核参数是否正确使用 rd.luks.name(不是 cryptdevice)
- 使用
systemd.debug-shell=1内核参数可在 tty9 获取 debug shell
Pacman 更新与 TPM 解锁注意※
内核、systemd、bootloader 更新会改变 UKI/EFI,若绑定 PCR 可能导致 TPM 解锁失效;保留密码 keyslot 可回退,重启后用密码解锁再重新 systemd-cryptenroll。
# 建议添加 pacman hook 自动重建 initramfs/UKI 并更新 systemd-boot
# 基于关键文件路径触发,覆盖内核、initramfs 生成器、systemd、固件等组件
sudo mkdir -p /etc/pacman.d/hooks
sudo tee /etc/pacman.d/hooks/99-regenerate-uki.hook >/dev/null <<'EOF'
# 更新重建统一内核映像(UKI)并更新 systemd-boot 引导项
[Trigger]
Operation = Install
Operation = Upgrade
Type = Path
Target = usr/lib/modules/*/vmlinuz
Target = usr/lib/initcpio/*
Target = usr/lib/systemd/*
Target = usr/lib/firmware/*
Target = etc/mkinitcpio.conf
Target = etc/mkinitcpio.d/*
[Action]
Description = Rebuild initramfs/UKI and update systemd-boot after critical file changes
When = PostTransaction
Exec = /usr/bin/sh -c 'mkinitcpio -P && bootctl update'
NeedsTargets
EOF
PCR 绑定场景的更新流程:
- 系统更新:
sudo pacman -Syu - 自动重建 UKI(hook 触发)
- 重启,使用密码解锁(TPM 解锁会因 PCR 变化失败)
- 重新 enroll TPM:
sudo systemd-cryptenroll /dev/nvme0n1p2 --wipe-slot=tpm2 --tpm2-device=auto --tpm2-pcrs=7 - 再次重启验证 TPM 解锁
高级选项※
使用 TPM2-TOTP 进行双因素验证※
# 需要 tpm2-totp 包
sudo pacman -S tpm2-totp
# 初始化 TOTP(会显示二维码,用手机扫描)
sudo tpm2-totp init
# 结合 TOTP 的 LUKS 解锁(需自定义脚本集成)
# 参考:https://wiki.archlinux.org/title/Dm-crypt/Specialties#TPM_and_TOTP
使用 systemd-pcrlock 锁定 PCR 策略※
# systemd ≥ 255 支持
# 锁定当前 PCR 配置,防止回滚攻击
sudo systemd-pcrlock make-policy
sudo systemd-cryptenroll /dev/nvme0n1p2 --tpm2-device=auto --tpm2-pcrlock=/var/lib/systemd/pcrlock.json
CheckList※
可使用脚本检查,但也不保证完全可靠 : P
| 指令 | 期望结果 | 判断依据 |
|---|---|---|
systemd --version | ≥ 250(最佳 ≥ 255) | 新特性如 pcrlock、更稳定的 TPM 集成 |
ls /dev/tpm0 /dev/tpmrm0 | 两者存在(优先 tpmrm0) | 资源管理器设备可用,提升并发与安全 |
tpm2_getrandom 8 | 输出随机字节 | TPM 工作正常 |
cryptsetup luksDump /dev/nvme0n1p2 | 存在 TPM2 token,且保留密码 keyslot | 可回退用密码解锁 |
sudo systemd-cryptenroll /dev/nvme0n1p2 --tpm2-device=auto --unlock-tpm2 | 无需密码即可解锁 | 验证 TPM 解锁路径可用 |
blkid /dev/nvme0n1p2cryptsetup luksUUID /dev/nvme0n1p2 | 确认 LUKS UUID | 与 rd.luks.name/crypttab 一致(不要用 PARTUUID) |
cat /etc/kernel/cmdline | 含 rd.luks.name=<LUKS_UUID>=cryptroot 与 root=/dev/mapper/cryptroot | 映射名一致 |
grep '^HOOKS' /etc/mkinitcpio.conf | 包含 systemd 与 sd-encrypt | 缺失则补全并重建 initramfs/UKI |
ls -l /boot/EFI/Linux/arch-linux.efibootctl status | UKI 文件存在且时间戳最新;引导项可识别 | mkinitcpio 预设 -U 自动生成或手动 ukify |
journalctl -b -u systemd-cryptsetup@cryptroot.service | 看到成功解锁日志或提示密码 | 确认 sd-encrypt 流程工作 |
ls -ld /bootls -l /boot/loader/random-seed | /boot 权限 700;random-seed 权限 600 且属主 root:root | 不符则修复权限以消除 bootctl 警告 |
| (故障排查) | systemd.debug-shell=1 内核参数 | 在 tty9 获取 debug shell 进一步诊断 |
参考※
- 官方文档
- systemd-cryptenroll(1) - 系统加密密钥管理
- systemd-cryptsetup-generator(8) - 加密设备单元生成器
- cryptsetup(8) - LUKS 管理工具
- bootctl(1) - systemd-boot 管理
- mkinitcpio(8) - 初始化 RAM 磁盘创建工具
- ArchWiki
- 技术规范