双 Ubuntu 安装与全盘加密

双 Ubuntu 安装与全盘加密

我的目标是拥有 Xubuntu/Ubuntu 双启动,但有一个问题 - 我希望磁盘使用 dm-crypt(本机提供)全盘加密进行完全加密。现在我知道,开箱即用的 ubuntu 安装程序不会让我轻松完成此操作,也许这是不可行的,因为我不确定我最终能否欺骗工具为每个根文件系统创建两个不同的 initrd 配置。

所以问题是:

  1. 以前有人这样做过吗?是否有一种我所缺少的简单方法来做到这一点?

  2. 鉴于 (1) 是否定的... a. 我应该为每个安装 (xubuntu/ubuntu) 创建单独的基本加密卷,还是应该只创建 1 个加密卷并在其中创建单独的安装分区?我倾向于后者,以使过程更简单。但是我不确定引导加载程序将如何处理这个问题。

b. 一旦我获得第一个发行版,如果我使用 1 个加密卷,我该如何解密它并安装第二个发行版(并正确更新引导加载程序、initrd 等)?

我曾在 Security Stack Exchange 上询问过有关安全方面的问题。

答案1

我添加了新答案适用于 Ubuntu 22.04 Jammy Jellyfish。

以下是完整内容。

我已将步骤分为重新启动之间的阶段:

  1. 准备工作

  2. 备份数据

  3. 重新启动到 live-USB 以执行主要任务 a. 预安装:在磁盘上腾出空间 b. 安装:进行手动分区 c. 安装后:补充 initramfs

  4. 重新启动到主 Ubuntu 以更新 grub

  5. 重新启动到第二个 Ubuntu 来添加密钥文件

  6. 重新启动到第二个 Ubuntu 以完成最后一步

  7. 未来安装的提醒

  8. 关于未加密的 /boot

  9. 准备工作


我在有 BIOS 的笔记本电脑上完成了此操作(有关 UEFI 的详细信息,请参阅Ubuntu 全盘加密,带加密 /boot),并且已经安装了加密的 Ubuntu 15.10(但也可能是 14.04 LTS)。我重复了该过程,在早期的 16.04 上安装 Ubuntu 16.10,然后在早期的 16.10 上安装 18.04。但是,我必须擦除用于 Bionic 安装的根目录 (/) 的逻辑卷的内容。每当我不擦除它时,Ubiquity 或 update-initramfs 都会以各种方式失败。

从宇宙开始,LUKS2 是默认值,而 grub 仅支持 LUKS1。因此,您不能从安装 Cosmic 或更高版本开始,并期望能够按照此处说明的方式在同一容器中添加另一个安装。相反,你必须先进行分区并手动创建 LUKS1 容器

我将使用标准 Ubuntu 安装在硬盘 /dev/sda 上创建的名称来引用分区和 LVM 卷:

$ lsblk -o NAME,TYPE,FSTYPE,MOUNTPOINT
NAME                    TYPE  FSTYPE      MOUNTPOINT
sda                     disk              
├─sda1                  part  ext2        /boot
├─sda2                  part              
└─sda5                  part  crypto_LUKS 
  └─sda5_crypt          crypt LVM2_member 
    ├─ubuntu--vg-root   lvm   ext4        /
    └─ubuntu--vg-swap_1 lvm   swap        [SWAP]

LUKS 容器“sda5_crypt”占用了逻辑分区上的所有空间。缩小 LUKS 容器对我来说太难了;我不想因为尝试这样做而破坏现有的 Ubuntu 安装。因此,我决定缩小逻辑卷“root”为新安装腾出空间。

因此,磁盘上唯一未加密的空间是 255M 的 /boot 分区。可以拆分此分区,但两个相等的部分只能容纳两个内核版本,对我来说这还不够。因此,我决定将新的 /boot 目录放在新的 /root 下(通过不将其指向任何其他位置)。这会产生一些额外的麻烦,但也为与主 Ubuntu 一起进行多个安装留出了空间。

以下所有命令均需使用 sudo 权限执行,所以我跳过了所有命令行的 sudo 部分。

另外,我将讨论“辅助 Ubuntu”,因为我不知道您希望安装哪种 Linux。将“辅助 Ubuntu”(以及任何特定于 Ubiquity 的详细信息)替换为您选择的版本。

  1. 备份数据

除了常规备份之外,您可能还想为基本设置(例如 /etc/crypttab)创建单独的副本,并将其保存在易于访问的位置。如果一切按计划进行,则不需要这样做,但这可能会帮助您保持冷静。

  1. 重新启动到 live-USB 以执行主要任务

2.a. 安装前:腾出磁盘空间

打开LUKS容器并激活LVM。

cryptsetup luksOpen /dev/sda5 sda5_crypt
vgscan
vgchange -ay

缩小现有的根卷。

e2fsck -f /dev/mapper/ubuntu--vg-root
#resize2fs -p /dev/mapper/ubuntu--vg-root 16G
lvreduce -L 16G --resizefs /dev/ubuntu-vg/root
  • 注释掉的那行只是以防万一您不相信“lvreduce --resizefs”能够可靠地执行调整大小操作。如果“resize2fs”让您感觉好一些,请运行它。

添加新的根卷。大小由您选择;16G 只是示例。

lvcreate -L 16G -n root2 ubuntu-vg

创建新的交换除非您相信您可以让 Hibernate 与 LUKS 一起工作。否则,让两个安装共享现有的交换空间。

lvcreate -L 4G -n swap2 ubuntu-vg

创建新的数据卷似乎是一件显而易见的事情,但对于这里描述的安装来说它并不是必不可少的。

lvcreate -l 100%FREE -n data ubuntu-vg

此时,新手可能想要在没有 live-USB 的情况下重新启动并登录到主 Ubuntu,只是为了看看它是否仍然有效。如果这样做,请记住在重新启动回 live-USB 时再次重新打开 LUKS 容器。

而且,注意使用正确的命令打开 LUKS 容器。例如,如果您单击启动器侧栏中看到的图标,容器将以错误的名称打开,这将导致 update-initramfs 稍后无法完成其工作。

cryptsetup luksOpen /dev/sda5 sda5_crypt

2.b. 安装:手动分区

启动安装程序并选择“其他”作为安装类型。

  • / 指向您的新根卷 (/dev/ubuntu-vg/root2)。
  • 不要将 /boot 指向任何地方。
  • 如果您创建了交换卷,则将交换指向新的交换卷,否则指向旧的交换卷。
  • 仔细检查确保没有其他分区或 LVM 卷参与安装。
  • 将 grub 放在逻辑卷上。哪个卷并不重要,因为重点是确保 gub-install 失败。第一次,这是最安全的选择。稍后,当您多次这样做后,您将确切知道何时选择 /dev/sda。

继续进行剩余的安装。

  • 如果安装程序询问是否应卸载挂载,则表示您做了此处未提及的事情。请卸载多余的挂载。

在安装结束时,选择继续测试。

  • 当安装程序报告 grub-install 失败时,选择不使用 grub 继续。
  • 如果弹出窗口卡住,只需最小化安装程序窗口。

2.c. 安装后:补充 initramfs

挂载两个根卷。

mkdir /mnt/newroot && mount /dev/mapper/ubuntu--vg-root2 /mnt/newroot
mkdir /mnt/oldroot && mount /dev/mapper/ubuntu--vg-root /mnt/oldroot

将文件 /etc/crypttab 从旧根卷复制到新根卷。

cp -p /mnt/oldroot/etc/crypttab /mnt/newroot/etc/
cat /mnt/newroot/etc/crypttab

如果您复制的文件已经引用了密钥文件,请将密钥文件和加载密钥所需的脚本也复制到 initrd.img。

cp -p /mnt/oldroot/crypto_keyfile.bin /mnt/newroot/
cp -p /mnt/oldroot/etc/initramfs-tools/hooks/crypto_keyfile /mnt/newroot/etc/initramfs-tools/hooks/
  • 第一次执行时,密钥尚不存在,最好在后面的步骤中创建它,因为当不是一次性完成所有更改时,故障排除会更容易。

至关重要的最后一步是在 chroot jail 中加载对 initrd.img 的更改。

for DEV in dev dev/pts sys proc; do mount --bind /$DEV /mnt/newroot/$DEV; done

chroot /mnt/newroot update-initramfs -u

# Note reverse order.
for DEV in proc sys dev/pts dev; do umount /mnt/newroot/$DEV; done
  • 如果您收到一条错误消息“cryptsetup:警告:/etc/crypttab 中的无效行”,则表示您没有使用正确的名称打开 LUKS 容器。

整理(不是 100% 必要的,特别是如果您在创建 live-USB 时没有选择持久性)。

umount /mnt/oldroot && rmdir /mnt/oldroot
umount /mnt/newroot && rmdir /mnt/newroot

您也可以尝试通过关闭 LUKS 容器来清理,但如果您必须最小化安装程序窗口,您将收到一条错误消息,提示“设备或资源繁忙”。别担心,无论如何它都会在关机时关闭。

cryptsetup luksClose sda5_crypt
  • 最艰难的部分现在已经过去了。
  1. 重新启动到主 Ubuntu 以更新 grub

编辑文件 /etc/default/grub 以使加密的 /boot 包含以下内容:

GRUB_ENABLE_CRYPTODISK=y
GRUB_CMDLINE_LINUX="cryptdevice=/dev/sda5:sda5_crypt"
  • 如果将 GRUB_ENABLE_CRYPTODISK 的值设置为“true”或“1”或其他任何值,update-grub 将会抱怨该值应该是“1”,但实际上必须是“y”。这是一个已知的错误。
  • 与往常一样,注意不要在文件末尾添加换行符。

接下来更新grub——主要是为了将新安装的Ubuntu添加到菜单中,也是为了修改后的设置。

update-grub
  1. 重新启动到第二个 Ubuntu 来添加密钥文件

当您从 grub 菜单中选择辅助 Ubuntu 时,系统会要求您输入密码以打开 LUKS 容器。然后系统会再次要求您输入相同的密码。登录后,我们需要解决必须输入两次密码的问题。我们通过向 LUKS 容器添加密钥文件来实现这一点。

首先,我们想知道 LUKS 容器已经有多少个密钥。一个 LUKS 容器最多可以有 8 个密钥(编号为 0..7),因此我们只想创建真正需要的密钥。

cryptsetup luksDump /dev/sda5
  • 在 Wily Werewolf 中,容器中已经有三把钥匙。不知道为什么。

接下来,我们创建新的密钥文件。

dd bs=512 count=4 if=/dev/urandom of=/crypto_keyfile.bin
chmod a=,u+r /crypto_keyfile.bin

然后我们将新密钥添加到容器中。该命令将要求使用现有密码,因此请输入您知道的密码。

cryptsetup luksAddKey /dev/sda5 /crypto_keyfile.bin

我们还需要 update-initramfs 运行的一个脚本来将密钥加载到 initrd.img。将文件放在 /etc/initramfs-tools/hooks/ 中,并设置其保护。

chmod +x /etc/initramfs-tools/hooks/crypto_keyfile

该脚本只需一行:

cp /crypto_keyfile.bin "${DESTDIR}"
  • 姓名脚本的内容以及密钥文件的名称由您决定。

我们还必须向 /etc/crypttab 添加对密钥的引用。修改之前,它看起来像这样:

sda5_crypt UUID=sda5-uuid-here none luks,discard

修改之后应该是这样的:

sda5_crypt UUID=sda5-uuid-here /crypto_keyfile.bin luks,discard,keyscript=/bin/cat

现在我们终于可以更新 initramfs 了:

update-initramfs -u
  1. 重新启动到第二个 Ubuntu 以完成最后一步

这一次,当您从 grub 菜单中选择辅助 Ubuntu 时,您只需输入一次 LUKS 密码。

将密钥文件复制到旧根卷进行备份。

mkdir /mnt/oldroot
mount /dev/mapper/ububtu--vg-root /mnt/oldroot
cp /crypto_file /mnt/oldroot/

还要复制 grub 设置以进行备份(从旧根卷到新根卷)。由于 grub 菜单由两个安装共享,因此其设置对两个安装都相同,并且可以通过任一安装安装菜单。因此,即使您现在希望将主 Ubuntu 保留在菜单顶部,您以后也可能需要备份设置。

cp /mnt/oldroot/etc/default/grub /etc/default/
umount /mnt/oldroot
rmdir /mnt/oldroot

您可能还想修改逻辑卷(主要是根卷)的安装选项,以便两个安装不会在 GUI 中暴露彼此的私有部分。我可以为您提供 /etc/fstab 的模式,但幸运的是,Disks 做得非常好,我不需要这样做。

最后,您可以开始正常部署辅助 Ubuntu,并在两个安装中部署新的数据卷。

  1. 未来安装的提醒

  • 覆盖任一 Ubuntu 安装时,您必须始终重复相同的安装后步骤,除了为 LUKS 创建新的密钥文件。
  • 将来的任何版本都可能不再需要密钥文件。实际上,我没有找到有关安装的 cryptsetup 部分的正确文档,因此我担心有关它的任何事情都可能发生变化。小心!
  1. 关于未加密的 /boot

如果您选择分割未加密的主分区以便为新的 /boot 腾出空间,则可以放弃我介绍的一些步骤:

  • 您不需要密钥文件,因此您也不需要脚本将密钥加载到 initrd.img 中,并且您不需要在 /etc/crypttab 中添加对密钥文件的引用。即便如此,您仍然需要在安装后阶段添加 /etc/crypttab 文件并在 chroot jail 中运行 update-initramfs。
  • 如果新的 /boot 没有加密,你也不需要在你的 grub 设置里设置 GRUB_ENABLE_CRYPTODISK,也不需要将启动参数设置为 GRUB_CMDLINE_LINUX。即便如此,你仍然需要运行 update-grub 将二次安装添加到 grub 菜单。

答案2

注意:我已经按照要求回答了问题,但您可能想要的是我的最后一段。

手动分区和双启动配置

您需要从 dmcrypt 的备用 CD 进行安装。在安装程序中选择手动分区。如果您想要两个单独的加密卷,请将它们都设为主分区、扩展分区或 EFI 分区,并在安装第一个操作系统时为另一个卷留出足够的空间。如果您想要两个共享加密卷的 Linux 发行版(但您可能不希望这样,正如我下面所解释的那样),请在安装该操作系统时创建一个大型加密卷并为每个操作系统创建文件系统。

将加密卷设为 LVM 物理卷,并创建一个仅跨越该物理卷的卷组。如果两个操作系统共享加密卷,它们也将共享卷组:卷组是管理多个卷的一种方式,在该配置中只有一个卷。为每个根文件系统创建至少一个逻辑卷。如果两个操作系统共享加密卷并且您不想使用休眠,它们可以共享交换区域。

留出足够大的启动区域,该区域需要解密。我建议至少留出 1GB(以便在紧急情况下存储救援 CD),除非您的磁盘空间严重受限,但 200MB 足以容纳一个内核和一个备用内核。

拥有两个独立的启动分区是最简单的安装方式。让一个发行版控制启动扇区,并在其启动分区的第一个扇区上安装辅助发行版的引导加载程序。从主引导加载程序链式加载辅助发行版的引导加载程序。

如果您想要单个启动分区,请仅在一个操作系统上安装 Grub,并/boot在两个操作系统之间共享。

安装两个 Linux 发行版

双启动使用起来很麻烦,而且在大多数情况下都不需要。如果你想运行两个操作系统,请使用某种形式的虚拟化。我能想到的双启动的唯一用例是当你需要在同一台昂贵的硬件上测试多个操作系统时(即使这样,如果你能负担得起,每个操作系统都有单独的机器会更方便)。

如果您想要两个具有不同密码的独立 Linux 安装,则需要双启动。即便如此,您也可以通过发布单独的帐户或创建单独的虚拟化容器(每个容器都有自己的根用户)来实现所需的安全策略。

要在 Linux 上运行 Linux,您甚至可能不需要虚拟化:您可以使用chroot. 使用 Ubuntu 或其他基于 Debian 的发行版作为主操作系统,施鲁特使这变得非常容易。如果您将 schroot 与不同的辅助发行版一起使用,则可能需要单独安装它,因此需要在单独的卷上安装。如果辅助发行版是基于 Debian 的,并且您永远不需要启动它,则可以将其安装在子目录中解引导. 看看我的雪根指南

Ubuntu/Xubuntu 双安装

如果你想尝试 Ubuntu 和 Xubuntu,你不需要所有这些繁琐的程序。Xubuntu 和 Ubuntu 是同一个发行版,只是默认软件包不同。从任何版本安装 Ubuntu,并确保Ubuntu 桌面xubuntu 桌面软件包已安装。登录时选择您喜欢的环境,您将使用 Ubuntu/Unity 又名 Ubuntu 或 Ubuntu/XFCE 又名 Xubuntu。

答案3

我最近在计算机上安装了加密的 Ubuntu 的同时又安装了另一个 Ubuntu。对于大部分操作,我都遵循了在 LUKS 加密硬盘上安装多个 Linux 发行版博客条目。

但是,我想保持现有安装不变,但由于调整现有 LUKS 容器的大小对我来说太难了,而且我不想重新分区整个磁盘,所以我最终使用 live-USB 重新组织了现有 LUKS 容器内的 LVM 卷。这个决定让我稍微偏离了说明,因为我必须将新的 /boot 文件夹放在 LUKS 容器内。不过,结果比预期的要简单。

因此,在仍然登录到 live-USB 的情况下,我启动了安装程序并选择手动分区。我将“/”指向一个新的逻辑卷,并让安装程序将新的 /boot 放置在 LUKS 容器内,而不是将其指向其他任何地方。我还将 swap 指向了一个新的逻辑卷,尽管我不确定 hibernate 是否适用于 LUKS。对于 grub 安装,我选择了一个安装肯定会失败的目标。最后,我选择“继续测试”,然后继续,无需安装 grub。

安装后重新启动,我将 /etc/crypttab 从第一个 Ubuntu 的根卷复制到新的根卷,并使用 chroot 运行 update-initramfs -u。这是至关重要的一步。

重启后,我登录到第一个 Ubuntu,编辑 /etc/default/grub 以添加 GRUB_ENABLE_CRYPTODISK=y 并修改 GRUB_CMDLINE_LINUX 以包含“cryptdevice=/dev/sda5:sda5_crypt”,运行 update-grub 并重新启动。

重启后,一旦我启动并运行了新安装,我就会添加一个密钥文件,以避免在启动时输入两次 LUKS 密码(因为 /boot 现在已经加密)。为了添加密钥文件,我遵循了来自多个来源的几乎相同的说明。我相信Pavel Kogan 的“Linux Mint 加密”博客条目必须是原始来源。

一切都比我预想的简单得多,尽管我确实必须克服一些愚蠢的障碍(例如“GRUB_ENABLE_CRYPTODISK 的值:util/grub-install.c 指示‘1’但 util/config.c 需要‘y’”这个错误)。

答案4

自从我在 2016 年写下“完整叙述”以来,cryptsetup-initramfs 集成已经放弃了 keyscript 方法,转而只指出要包含在 Initramfs 中的一堆密钥文件。此外,Grub 仍然需要跟上 LUKS2 的步伐,Ubuntu 安装程序已经部署了 LUKS2。有关这些内容以及更多内容的详细信息,请参阅全盘加密方法2019,我现在推荐使用“完整帐户”。应该很容易将其扩展到同一磁盘上的多个安装。

不过,有一个方面我希望改进。

我不想在安装后使用 chroot 来处理密钥文件,而是想在安装之前就写入密钥文件并将其作为 LUKS 密钥植入。如果安装介质是使用持久性创建的,我会明确将密钥文件写入 RAM,以确保它永远不会写入我的拇指驱动器。有了密钥文件,我可以在安装过程中将密钥文件和任何其他加密启用程序注入 /target 目录,并让安装程序为我运行 update-initramfs,就像 Wiki 文章在安装过程中注入一个必要的 Grub 设置一样。

由于基础知识已在 Help Ubuntu Wiki 文章中详细解释,因此我在此以简单的命令序列的形式介绍我的替代方案。整个序列的先决条件是:分区已完成,两个 LUKS 容器都已打开,LVM 卷组已激活,命令在“ sudo -i bash”环境中执行。我使用 Ubuntu 22.04(Jammy Jellyfish)对此进行了测试。

第一部分处理密钥文件:

# Recollect keyfile naming scheme:

keydir=/etc/luks
keyfile=$keydir/boot_os.keyfile
keypat=$keydir/*.keyfile

# Write keyfile into RAM:

mkdir -p -m go=,u=rwx $keydir
mount -t tmpfs -o size=1m tmpfs $keydir # 5k RAM would be enough
(umask go=,u=rx
 dd if=/dev/urandom of=$keyfile bs=1 count=64
)

# Recollect partition paths:

pnum2path()
{
    echo $1$(case $1 in /dev/nvme*) echo p ;;
             esac)$2
}
disk=/dev/nvme0n1
luks1dev=$(pnum2path $disk 1)
luks2dev=$(pnum2path $disk 5)

# Plant the keyfile as LUKS key in both containers:

cryptsetup luksAddKey $luks1dev $keyfile # type in passphrase
cryptsetup luksAddKey $luks2dev $keyfile # type in passphrase

第二部分是关于向 /target 目录注入加密启动器。

准备工作首先要做好:

# Define helper routines:

is-ssd(){
    [ $(lsblk -dno rota $1) -eq 0 ] # does the disk rotate or not?
}
wait-write(){
    local d=${1%/*}
    until [ -d $d ]; do sleep 1; done
    (set -x; echo "$2" >> $1)
}

(由于重定向,输出文件路径不幸不是“ set -x”显示的命令的一部分。)

# Recollect details to include in encryption enablers:

luks1name=LUKS_BOOT
luks2name=${$luks2dev##*/}_crypt
cryptopt="luks$(is-ssd && echo ,discard)"

准备工作已完成,我们准备安装。如果您将以下命令复制并粘贴到终端,请将其作为一组执行(或将这些行写入文件,然后运行该文件)。在回答完 Ubiquity 的所有问题后立即运行该序列就足够了。但是,如果您在 Ubiquity 自己的窗口中启动该序列,您将看到所有注入都在您完成回答时完成(使用 SSD,目标目录似乎在我输入用户名和计算机名称时就位,并且所有注入都在我第二次输入密码之前完成)。

# During installation, inject encryption enablers into /target directories:

umask go=r,u=rw
etc=/target/etc

wait-write $etc/crypttab "# Both /boot and rootfs are encrypted.
$luks1name UUID=$(cryptsetup luksUUID $luks1dev) $keyfile $cryptopt
$luks2name UUID=$(cryptsetup luksUUID $luks2dev) $keyfile $cryptopt"

(set -x; cp -ar $keydir $etc/) # from RAM to disk

wait-write $etc/default/grub.d/local.cfg "GRUB_ENABLE_CRYPTODISK=y"
wait-write $etc/initramfs-tools/initramfs.conf "UMASK=0077"
wait-write $etc/cryptsetup-initramfs/conf-hook "KEYFILE_PATTERN=\"$keypat\""

安装结束时,您可以立即接受 Ubiquity 的重新启动提议!

附言:

我最初的动机并不是加密 /boot。作为我自己的笔记本电脑的唯一用户,它只有一个硬盘,我讨厌调整我使用的 LUKS 容器大小的想法;如果只需处理 LVM,管理空间预留会简单得多。因此,我只想有一个 LUKS 容器,在其中安装 1-3 个 Ubuntu 版本。在此设置中,将每个 /boot 包含在同一个容器中只是一个副作用。

在我的单容器设置中,从安装介质运行 Ubuntu 时我不必处理密钥文件。在安装过程中,我只需注入我需要的两个 Grub 设置(另一个用于启用 os-prober),然后注入 /etc/crypttab 文件,用“none”代替 keyfile。安装后,我确实必须输入两次密码,但是一旦我登录到新安装的 Ubuntu,我就可以随意处理密钥文件了。我更喜欢这样,但是 Grub 与 LUKS2 不兼容,现在迫使我做出选择。

相关内容