TMP解锁LUKS

-
-
2025-12-13

 通过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

步骤总览

  1. 确认磁盘加密与分区布局(root 使用 LUKS)。
  2. 安装依赖:systemd-cryptenroll、systemd-boot(或 GRUB)、dracut/mkinitcpio、tpm2-tools。
  3. 为 LUKS 卷注册 TPM 解锁密钥(systemd-cryptenroll)。
  4. 在 initramfs/UKI 中启用 systemd-cryptsetup 自动解锁逻辑。
  5. 配置内核命令行:指定加密设备与映射名。
  6. 重建 initramfs/UKI,更新引导项。
  7. 测试与回退策略。

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+117
  • 不绑定 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]
  • 如 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 绑定场景的更新流程:

  1. 系统更新:sudo pacman -Syu
  2. 自动重建 UKI(hook 触发)
  3. 重启,使用密码解锁(TPM 解锁会因 PCR 变化失败)
  4. 重新 enroll TPM:sudo systemd-cryptenroll /dev/nvme0n1p2 --wipe-slot=tpm2 --tpm2-device=auto --tpm2-pcrs=7
  5. 再次重启验证 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/nvme0n1p2
cryptsetup luksUUID /dev/nvme0n1p2
确认 LUKS UUID与 rd.luks.name/crypttab 一致(不要用 PARTUUID)
cat /etc/kernel/cmdlinerd.luks.name=<LUKS_UUID>=cryptrootroot=/dev/mapper/cryptroot映射名一致
grep '^HOOKS' /etc/mkinitcpio.conf包含 systemdsd-encrypt缺失则补全并重建 initramfs/UKI
ls -l /boot/EFI/Linux/arch-linux.efi
bootctl status
UKI 文件存在且时间戳最新;引导项可识别mkinitcpio 预设 -U 自动生成或手动 ukify
journalctl -b -u systemd-cryptsetup@cryptroot.service看到成功解锁日志或提示密码确认 sd-encrypt 流程工作
ls -ld /boot
ls -l /boot/loader/random-seed
/boot 权限 700;random-seed 权限 600 且属主 root:root不符则修复权限以消除 bootctl 警告
(故障排查)systemd.debug-shell=1 内核参数在 tty9 获取 debug shell 进一步诊断

参考

“您的支持是我持续分享的动力”

微信收款码
微信
支付宝收款码
支付宝


目录