0

通过这篇文章,我正在与社区分享一个解决方案。

我在由多个加密设备组成的 ZFS 池上安装了 Gentoo 系统。如本文所述,它通常在启动时被解密。在/etc/default/grub我添加到内核行的文件中:

RUB_CMDLINE_LINUX="dozfs crypt_roots=UUID=aaaaaaaa crypt_roots=UUID=bbbbbbbb ..."

其中aaaaaaaabbbbbbbb代表加密卷的 UUID-s,如 中所列/dev/disk/by-uuid,但有一个不便之处:每个卷必须输入一次密码。我使用全盘加密和 8 个加密卷,每次启动时需要输入9 个密码,即使我对所有卷使用相同的密码。好麻烦!

是否可以使用单个密码条目解密所有卷?

我的 initramfs 是通过sys-kernel/genkernel-next-69.

4

1 回答 1

0

我为 genkernel 提供了一个补丁,允许使用单个密码解密多个卷(将文件另存为/tmp/genkernel_multicrypt.patch):

diff --git a/defaults/initrd.d/00-crypt-multicrypt.sh b/defaults/initrd.d/00-crypt-multicrypt.sh
new file mode 100755
index 0000000..848f06a
--- /dev/null
+++ b/defaults/initrd.d/00-crypt-multicrypt.sh
@@ -0,0 +1,88 @@
+#!/bin/sh
+
+MULTICRYPT_MAX_TRIES=4
+
+multicrypt_all_volumes_mapped()
+{
+    local k=0
+
+    while true; do
+        eval local voltype='"${MULTICRYPT_type'${k}'}"'
+        k=$(( k+1 ))
+
+        [ -n "$voltype" ] || return 0
+
+        local m=0
+        while true; do
+            eval local vol='"${MULTICRYPT_'${voltype}${m}'}"'
+            [ -n "$vol" ] || break
+            [ -e "/dev/mapper/${voltype}${m}" ] || return 1
+            m=$(( m+1 ))
+        done
+    done
+
+    return 0
+}
+
+multicrypt_open_volumes()
+{
+    local pass="$1"; shift
+
+    local k=0
+
+    while true; do
+        eval local voltype='"${MULTICRYPT_type'${k}'}"'
+        k=$(( k+1 ))
+
+        [ -n "$voltype" ] || return 0
+
+        local m=0
+        while true; do
+            local volname="${voltype}${m}"
+
+            eval local vol='"${MULTICRYPT_'${volname}'}"'
+            [ -n "$vol" ] || break
+
+            echo Decrypting vol ${volname} ${vol} ...
+            echo -n "$pass" | ${CRYPTSETUP_BIN} luksOpen /dev/disk/by-uuid/${vol} "${volname}" -d - || return 1
+            
+            m=$(( m+1 ))
+        done
+    done
+}
+
+multicrypt_execute() {
+
+    [ -z "${MULTICRYPT_type0}" ] && return 1   # multicrypt not requested
+
+    local root_or_swap=
+    if [ -n "${CRYPT_ROOTS}" ] || [ -n "${CRYPT_SWAPS}" ]; then
+        root_or_swap=1
+    fi
+
+    if ! multicrypt_all_volumes_mapped; then
+        echo "Opening multiple encrypted partitions..."
+    fi
+
+    local try=0
+    while ! multicrypt_all_volumes_mapped && [ "$try" -lt "$MULTICRYPT_MAX_TRIES" ]; do
+        try=$(( try+1 ))
+
+        echo -n "Password (try $try of $MULTICRYPT_MAX_TRIES): "
+        read -s pass
+        echo ""
+
+        multicrypt_open_volumes "$pass"
+
+        if [ $? -ne 0 ]; then
+            echo "ERROR: Decrypting one or more volumes failed."
+        fi
+    done
+
+    if [ -n "${root_or_swap}" ]; then
+        # We postponed the initialization of raid devices
+        # in order to avoid to assemble possibly degraded
+        # arrays.
+        start_volumes
+    fi
+}
diff --git a/defaults/initrd.d/00-crypt.sh b/defaults/initrd.d/00-crypt.sh
index 0e7c863..0515446 100755
--- a/defaults/initrd.d/00-crypt.sh
+++ b/defaults/initrd.d/00-crypt.sh
@@ -4,6 +4,7 @@
 . /etc/initrd.d/00-devmgr.sh
 . /etc/initrd.d/00-splash.sh
 . /etc/initrd.d/00-fsdev.sh
+. /etc/initrd.d/00-crypt-multicrypt.sh
 
 CRYPTSETUP_BIN="/sbin/cryptsetup"
 KEY_MNT="/mnt/key"
@@ -285,6 +286,8 @@ _open_luks() {
 
 start_luks() {
 
+    multicrypt_execute && return 0
+
     local root_or_swap=
     if [ -n "${CRYPT_ROOTS}" ] || [ -n "${CRYPT_SWAPS}" ]; then
         root_or_swap=1

该补丁必须以 root 身份应用于 genkernel 目录/usr/share/genkernel

su

# Make a backup of genkernel if something goes wrong.
cp -r /usr/share/genkernel /root/genkernel-backup

cd /usr/share/genkernel
patch -p1 < /tmp/genkernel_multicrypt.patch

如果一切顺利,补丁将被应用,您将不会看到任何错误消息。

用法

首先确保您的磁盘可以使用相同的密码解密!!!

该补丁修改了 genkernel 的初始 ramdisk 以支持以下附加输入参数:

MULTICRYPT_type0=boot
MULTICRYPT_type1=root
MULTICRYPT_type2=tank

MULTICRYPT_boot0=aaaaaaaaa

MULTICRYPT_root0=bbbbbbbbb
MULTICRYPT_root1=ccccccccc

MULTICRYPT_tank0=ddddddddd
MULTICRYPT_tank1=eeeeeeeee
...

在上面的例子中你可以自由选择你想要的类型,我用了 3: boot, root, tank. 对于每种类型,您可以拥有一个或多个卷 UUID,如上所示。

确保 UUID 存在于/dev/disk/by-uuid. 确保 UUID 准确无误!错别字会导致系统无法启动!

设备将以 、 、 等形式添加到设备映射boot0root0root1

现在,内核行必须进行如下修改(只需将上面提到的所有参数与常规参数一起附加到内核行,例如dolvmdozfs等)。

不要删除您原来的内核行,只需将其注释掉以防您想恢复。

GRUB_CMDLINE_LINUX="MULTICRYPT_type0=boot MULTICRYPT_type1=root MULTICRYPT_type2=tank MULTICRYPT_boot0=aaaaaaaaa MULTICRYPT_root0=bbbbbbbbb MULTICRYPT_root1=ccccccccc MULTICRYPT_tank0=ddddddddd MULTICRYPT_tank1=eeeeeeeee ..."

# As per standard grub configuration, we need to load the necessary modules and enable encryption:
GRUB_PRELOAD_MODULES="part_gpt search_fs_uuid cryptodisk luks linux"  # zfs lvm etc. if necessary
GRUB_ENABLE_CRYPTODISK="y"

完成这项工作后,我们可以调用 genkernel 生成新的 initramfs。确保您制作了旧副本的备份副本,以便在出现问题时轻松恢复。不需要编译内核和模块。

另外,在一张纸上写下你原来的内核行,这样你就可以在 Grub 中输入它,以防系统无法正常启动。

su
cp /boot/<YOUR-INITRAMFS> /boot/<YOUR-INITRAMFS>--copy

# This uses 8 threads for compilation, adjust accordingly.
# Add "--zfs" if your root is on ZFS.
genkernel --makeopts=-j8 --udev --luks --busybox --bootloader=grub2 --menuconfig --oldconfig --install initramfs

您闪亮的新 initramfs 安装在/boot. 现在进行最后一步 - 必须生成 GRUB 的配置文件以激活新参数:

grub-mkconfig -o /boot/grub/grub.cfg

在编写时 grub-mkconfig 会生成一个不正确的文件,如果您的根目录位于 ZFS 上,则需要手动修补该文件。在文件中,/boot/grub/grub.cfg我的根数据集被错误地指定为/ROOT/gentoozroot/ROOT/gentoo所以我需要zroot在多个位置插入。一旦修复了特定的错误,就不需要这样做了。

完毕!重启后会出现如下提示:

Opening multiple encrypted partitions...
Password (try 1 of 4):

输入您的密码,然后(手指交叉)所有卷都应该解密。

故障排除

如果您的系统无法启动,您可以使用我们保存的旧 initramfs。当显示 Grub 菜单时,点击E并重新键入原始内核行,将“--saved”附加到您的 initramfs 文件名。这应该像以前一样引导您的系统。

如果您对补丁不满意,请将原始 genkernel 从/root/genkernel-backupto/usr/share/genkernel恢复,然后恢复原始内核行/etc/default/grub并再次调用 genkernel 和 grub-mkconfig:

genkernel --makeopts=-j8 --udev --luks --busybox --bootloader=grub2 --menuconfig --oldconfig --install initramfs
grub-mkconfig -o /boot/grub/grub.cfg

警告

因为我使用全盘加密,我仍然需要在启动时输入两次密码。首先,解密/boot并加载内核,然后第二次解密所有其他卷。我不知道有任何解决方案。

状态 17.02.2022

于 2022-02-16T23:29:33.053 回答