GRUB与LUKS加密启动故障排除指南

本文详细记录了在GRUB无法从LUKS加密分区启动时的解决方案,包括手动使用cryptomount命令挂载LUKS卷、配置GRUB_ENABLE_CRYPTODISK参数,以及通过initramfs集成密钥文件避免重复输入密码的方法。

GRUB与LUKS

昨天我遇到了一个问题:GRUB从ext4格式的/boot/grub启动,但/boot目录位于我的LUKS LVM根分区内,这意味着GRUB无法加载initramfs和内核。

幸运的是,GRUB确实知道如何挂载LUKS卷(和LVM卷),但我找到的所有说明都谈论的是提前设置(“在/etc/default/grub中添加GRUB_ENABLE_CRYPTODISK=y”),而不是在启动失败时正确的GRUB手动命令是什么。

以下是我的笔记,以防我再次需要这样做,因为使用GRUB的cryptomount命令有一个特定的注意事项(如下所述)。

可用设备包括原始磁盘(hd0)、/boot/grub分区(hd0,msdos1)和LUKS卷(hd0,msdos5):

1
2
grub> ls
(hd0) (hd0,msdos1) (hd0,msdos5)

使用cryptomount打开LUKS卷(但不要使用括号!据说使用括号可以工作,但之后无法使用生成的(crypto0)):

1
2
3
4
grub> insmod luks
grub> cryptomount hd0,msdos5
Enter password...
Slot 0 opened.

然后可以加载LVM,它将看到LUKS卷内部:

1
2
3
grub> insmod lvm
grub> ls
(crypto0) (hd0) (hd0,msdos1) (hd0,msdos5) (lvm/rootvg-rootlv)

然后我可以正常启动:

1
grub> configfile $prefix/grub.cfg

启动后,我在/etc/default/grub中添加了GRUB_ENABLE_CRYPTODISK=y并运行了update-grub。之后我可以正常启动,尽管会被提示两次输入LUKS密码(一次由GRUB,另一次由initramfs)。

为了避免这种情况,可以添加第二个LUKS密码,该密码包含在initramfs的文件中,如这里所述,也适用于Ubuntu和Debian。快速总结如下:

创建密钥文件并将其添加到LUKS:

1
2
3
4
# dd bs=512 count=4 if=/dev/urandom of=/crypto_keyfile.bin
# chmod 0400 /crypto_keyfile.bin
# cryptsetup luksAddKey /dev/sda5 /crypto_keyfile.bin
*输入原始密码*

调整/etc/crypttab以包含通过/bin/cat传递文件:

1
sda5_crypt UUID=4aa5da72-8da6-11e7-8ac9-001cc008534d /crypto_keyfile.bin luks,keyscript=/bin/cat

添加一个initramfs钩子以将密钥文件复制到initramfs中,防止非root用户读取initramfs,并触发重建:

1
2
3
4
5
6
7
8
9
# cat > /etc/initramfs-tools/hooks/crypto_keyfile <<EOF
#!/bin/bash
if [ "$1" = "prereqs" ] ; then
    cp /crypto_keyfile.bin "${DESTDIR}"
fi
EOF
# chmod a+x /etc/initramfs-tools/hooks/crypto_keyfile
# chmod 0700 /boot
# update-initramfs -u

这样做有一个缺点,即在启动后LUKS密码会“明文”存在,但如果有人拥有root权限,他们可以直接获取你的dm-crypt加密密钥:

1
2
# dmsetup table --showkeys sda5_crypt
0 155797496 crypt aes-cbc-essiv:sha256 e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 8:5 2056

当然,如果你担心Evil Maid攻击,你需要一个真正的静态信任根,而不是从未经验证的/boot分区进行全盘加密密码提示。:)

© 2017, Kees Cook。本作品采用知识共享署名-相同方式共享4.0国际许可协议进行许可。

评论 (6)

Ben Hutchings — 2017年8月30日下午2:30
initramfs钩子脚本不正确;需要检查特殊情况$1 = prereqs。

kees — 2017年8月30日下午2:42
啊,说得好。我想现在正确了,谢谢!

claudex — 2017年8月30日晚上11:24
非常感谢。我从未遇到过需要这些信息的情况,但它本可以节省我一些时间。

Tr4sK — 2017年11月12日晚上9:42
太好了,终于有人拥有使其工作所需的一切!

patrick — 2018年2月20日上午7:57
initramfs有时可以通过简单地gzip -d | cpio -idvm /boot/initrd*来检查。GRUB可以访问这些文件。任何USB启动也可以。所以你的密钥是明文的,对任何人都可用。除非你以某种方式锁定initramfs。你做到了吗?

Mem — 2018年3月6日上午5:26
保护密钥文件的一个更复杂的方法是:
– 将/boot与大的LVM分区分离,放在一个单独的LUKS分区中。
– 将crypto_keyfile.bin放在/boot/crypto_keyfile.bin中,并相应地更新钩子脚本。
– 在运行系统中将/boot分区设置为“noauto”,仅在更新内核、ramdisk等时挂载/boot
优点是(只要/boot未挂载)你永远不会在运行系统中暴露启动内核或密钥文件等。如果有人获得root访问权限,他们必须知道“GRUB密码”才能获取密钥文件或干扰你的启动环境。
免责声明:我尚未测试此方法,但这是我计划在下一台安装的机器上使用的。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计