dm-crypt/交换分区加密

来自 ArchWiki

根据需求,可以使用不同的方法来加密 交换分区,以下将对此进行描述。在重启时重新初始化交换分区加密(使用新的加密)的设置提供了更高的数据保护,因为它避免了可能很久以前被换出而没有被覆盖的敏感文件片段。然而,重新加密交换分区通常也禁止使用休眠到磁盘功能。

不支持休眠到磁盘

在不需要休眠到磁盘(休眠)功能的系统中,可以设置 /etc/crypttab 以在启动时使用随机密码和 plain dm-crypt 解密交换分区。随机密码在关机时被丢弃,只在交换设备中留下加密的、无法访问的数据。

要启用此功能,只需取消注释 /etc/crypttab 中以 swap 开头的行。将设备参数更改为您的交换设备名称。例如,它看起来会像这样

/etc/crypttab
# <name>  <device>     <password>     <options>
swap      /dev/sdX#    /dev/urandom   swap,cipher=aes-xts-plain64,size=512,sector-size=4096

这将把 /dev/sdX# 映射到 /dev/mapper/swap 作为交换分区,可以在 /etc/fstab 中像普通的交换分区一样添加。如果您之前有一个未加密的交换分区,请不要忘记禁用它 - 或者通过将设备更改为 /dev/mapper/swap 来重复使用其 fstab 条目。默认选项对于大多数用途来说应该足够了。有关其他选项和每列的解释,请参阅 crypttab(5) 以及 cryptsetup FAQ 2.3 点

警告: 指定设备的所有内容都将被永久删除。对交换设备使用内核的简单命名是很危险的,因为它们的命名顺序(例如 /dev/sda/dev/sdb)在每次启动时都会更改。可选项有
注意: 交换分区设置有时可能会失败,请参阅 systemd 问题 10179

要使用 by-id 持久设备命名而不是内核简单命名,首先识别交换设备

# find -L /dev/disk -samefile /dev/sdaX
/dev/disk/by-id/ata-WDC_WD2500BEVT-22ZCT0_WD-WXE908VF0470-partX
/dev/disk/by-id/wwn-0x60015ee0000b237f-partX

然后将其用作 /dev/sdX# 示例分区的持久引用(如果返回如上所示的两个结果,请选择其中一个)

/etc/crypttab
# <name>  <device>                                                         <password>     <options>
swap      /dev/disk/by-id/ata-WDC_WD2500BEVT-22ZCT0_WD-WXE908VF0470-partX  /dev/urandom   swap,cipher=aes-xts-plain64,size=512,sector-size=4096

重启以激活加密交换分区后,您会注意到运行 swapon -s 显示一个任意的设备映射器条目(例如 /dev/dm-1),而 lsblk 命令在 FSTYPE 列中显示 crypt。由于每次启动都进行全新加密,因此 /dev/mapper/swap 的 UUID 每次都会更改。

注意: 如果选择用于交换的分区以前是 LUKS 分区,则 crypttab 不会覆盖该分区以创建交换分区。这是一种安全措施,以防止因错误识别 crypttab 中的交换分区而导致数据丢失。为了使用这样的分区,必须 覆盖 LUKS 标头 一次。

UUID 和 LABEL

使用 crypttab 交换分区和简单的内核设备名称(如 /dev/sdX# 甚至 /dev/disk/by-id/ata-SERIAL-partX)是很危险的。您的设备名称或分区布局的微小更改,/etc/crypttab 将在下次启动时格式化您的宝贵数据。如果您使用 PARTUUID,然后决定将该分区用于其他用途,而没有首先删除 crypttab 条目,情况也是如此。

更可靠的方法是通过给正确的分区一个真正的 UUID 或 LABEL 来识别它。默认情况下,这不起作用,因为 dm-crypt 和 mkswap 会简单地覆盖该分区上的任何内容,这将删除 UUID 和 LABEL;但是,可以指定交换偏移量。这允许您创建一个非常小的、空的、伪造的文件系统,其唯一目的是为交换分区加密提供持久的 UUID 或 LABEL。

使用您选择的标签创建一个 文件系统

# mkfs.ext2 -L cryptswap /dev/sdX# 1M

设备名称后的不寻常参数将文件系统大小限制为 1 MiB,为后面的加密交换分区留出空间。

# blkid /dev/sdX#
/dev/sdX#: LABEL="cryptswap" UUID="b72c384e-bd3c-49aa-b7a7-a28ea81a2605" TYPE="ext2"

有了这个,/dev/sdX# 现在可以很容易地通过 UUID 或 LABEL 来识别,而不管其设备名称甚至分区号将来如何更改。剩下的只是 /etc/crypttab/etc/fstab 条目。例如,使用不同的加密选项

/etc/crypttab
# <name> <device>         <password>    <options>
swap     LABEL=cryptswap  /dev/urandom  swap,offset=2048,cipher=aes-xts-plain64,size=512,sector-size=4096

请注意偏移量:它是 2048 个扇区,每个扇区 512 字节(它不受 dm-crypt 扇区大小的影响),因此为 1 MiB。这样,加密交换分区将不会影响文件系统 LABEL/UUID,并且数据对齐也正常工作。

/etc/fstab
# <filesystem>    <dir>  <type>  <options>  <dump>  <pass>
/dev/mapper/swap  none   swap    defaults   0       0

使用此设置,cryptswap 将仅尝试使用具有相应 LABEL 的分区,而不管其设备名称可能是什么。如果您决定将该分区用于其他用途,通过格式化它,cryptswap LABEL 也将消失,因此 /etc/crypttab 不会在您下次启动时覆盖它。

在桌面环境中禁用休眠

桌面环境可能无法自动检测到交换分区是随机加密的,并且不能用于休眠到磁盘。

可以通过运行以下命令配置 Xfce 以隐藏其休眠混合睡眠按钮

$ xfconf-query -c xfce4-session -np /shutdown/ShowHibernate -t bool -s false
$ xfconf-query -c xfce4-session -np /shutdown/ShowHybridSleep -t bool -s false

支持休眠到磁盘

以下三种方法是设置用于休眠到磁盘(休眠)的加密交换分区的替代方法。如果您应用其中任何一种方法,请注意系统换出的关键数据可能会在交换分区中停留很长时间(即直到它被覆盖)。为了降低这种风险,请考虑设置一个系统作业来重新加密交换分区,例如,每次系统进入常规关机时,以及您选择的方法。

LVM on LUKS

如果交换卷位于 initramfs 中激活的卷组中,只需按照 电源管理/挂起和休眠#休眠 中的说明进行操作即可。

使用交换分区

注意: 要使用系统当前正在使用的分区,您必须首先以 root 身份运行 swapoff /dev/device 来禁用它,并确保删除 /etc/crypttab 中指向此设备的任何行。

使用 cryptsetup-luksFormat(8) 为交换分区创建加密容器

# cryptsetup luksFormat --label swap /dev/device

打开容器到 /dev/mapper/swap

# cryptsetup open /dev/disk/by-label/swap swap

在映射的分区内创建一个交换文件系统

# mkswap /dev/mapper/swap

如果不使用 systemd#GPT 分区自动挂载,请通过添加以下行将映射的分区添加到 /etc/fstab

/dev/mapper/swap none swap defaults 0 0

要设置您的系统从休眠状态恢复,请使用 resume=/dev/mapper/swap 内核参数。有关详细信息,请参阅 电源管理/挂起和休眠#将休眠位置传递给 initramfs

使用 TPM

以下内容提供了使用存储在 TPM 中的密钥进行无人值守的交换分区解密。

您可以使用 systemd-cryptenroll 将密钥注册到 Luks 容器和 TPM,并擦除先前创建的包含密码的密钥槽

# systemd-cryptenroll --tpm2-device auto /dev/device
# systemd-cryptenroll --wipe-slot password /dev/device

使用以下命令检查结果

# systemd-cryptenroll /dev/device
SLOT TYPE
   0 tpm2

本文或章节需要扩充。

原因: 使用 TPM 作为交换密钥使得(可选地)自动化擦除/替换它成为可能,例如在安装内核/需要重启时。(在 Talk:Dm-crypt/Swap encryption 中讨论)

使用额外的密码或密钥文件

上面的 基本设置 的缺点是每次启动都必须手动为交换分区插入额外的密码。

警告: 如果 /boot 未加密,请不要将此设置与密钥文件一起使用。请阅读 此处 报告的问题。或者,按照 https://bbs.archlinux.org/viewtopic.php?id=120181 的说明使用 gnupg 加密的密钥文件

在 initramfs 中解锁分区

要从加密的交换分区恢复,必须在 initramfs 中解锁加密分区。

mkinitcpio
基于 systemd 的 initramfs

当将基于 systemd 的 initramfs 与 sd-encrypt mkinitcpio 钩子一起使用时,可以

例如,对于 TPM 支持的加密交换设备

/etc/crypttab.initramfs
swap UUID=56f8ee97-54b3-4a65-9282-688deb922527 none tpm2-device=auto
基于 busybox 的 initramfs

当将默认的基于 busybox 的 initramfs 与 encrypt 钩子一起使用时,请按照以下说明进行操作。

如果交换设备与根文件系统的设备不同,则 encrypt 钩子不会打开它,即将在可以使用 /etc/crypttab 之前进行恢复,因此需要在 /etc/mkinitcpio.conf 中创建一个钩子以在恢复之前打开交换 LUKS 设备。

本文或章节是与 dm-crypt/Specialties#多个非根分区 合并的候选对象。

注意: 相同的使用案例。(在 Talk:Dm-crypt/Swap encryption 中讨论)
注意: 本节仅在使用 encrypt 钩子时适用,该钩子只能解锁单个设备 (archlinux/mkinitcpio/mkinitcpio#231)。使用 sd-encrypt 可以解锁多个设备,请参阅 dm-crypt/System configuration#使用 systemd-cryptsetup-generator

现在您必须创建一个钩子以在启动时打开交换分区。您可以 安装 和配置 mkinitcpio-openswapAUR,或按照以下说明进行操作。创建一个包含 open 命令的钩子文件

/etc/initcpio/hooks/openswap
run_hook ()
{
    cryptsetup open /dev/device swap
}
警告: 挂载文件系统 是危险且具有破坏性的。密钥文件不应从系统挂起时挂载的文件系统中读取。

本文或章节需要扩充。

原因: 添加不会导致数据丢失的说明。(在 Talk:Dm-crypt/Swap encryption 中讨论)

用于通过键入密码打开交换设备,或

/etc/initcpio/hooks/openswap
run_hook ()
{
    ## Optional: To avoid race conditions
    x=0;
    while [ ! -b /dev/mapper/root-device ] && [ $x -le 10 ]; do
       x=$((x+1))
       sleep .2
    done
    ## End of optional

    mkdir crypto_key_device
    mount /dev/mapper/root-device crypto_key_device
    cryptsetup open --key-file crypto_key_device/path-to-the-key /dev/device swap
    umount crypto_key_device
}

用于通过从加密的根设备加载密钥文件来打开交换设备。

在某些计算机上,当 mkinitcpio 尝试在解密过程和设备枚举完成之前挂载设备时,可能会发生竞争条件。注释掉的可选块会将启动过程延迟最多 2 秒,直到根设备准备好挂载。

注意: 如果交换分区位于固态硬盘 (SSD) 上并且需要 Discard/TRIM,则必须将选项 --allow-discards 添加到上面 openswap 钩子中的 cryptsetup 行。有关丢弃的更多信息,请参阅 Dm-crypt/Specialties#固态硬盘 (SSD) 的 Discard/TRIM 支持SSD。此外,您必须将挂载选项“discard”添加到交换设备的 fstab 条目中。

然后创建并编辑钩子设置文件

/etc/initcpio/install/openswap
build ()
{
   add_runscript
}
help ()
{
cat<<HELPEOF
  This opens the swap encrypted partition /dev/device in /dev/mapper/swap
HELPEOF
}

/etc/mkinitcpio.confHOOKS 数组中添加钩子 openswap,在 filesystem 之前,但在 encrypt 之后。不要忘记在 openswap 之后添加 resume 钩子。

HOOKS=(... encrypt openswap resume filesystems ...)

重新生成 initramfs.

在启动时,openswap 钩子将打开交换分区,以便内核恢复可以使用它。如果您使用特殊的钩子从休眠状态恢复,请确保它们放置在 HOOKS 数组中的 openswap 之后。请注意,由于 initrd 打开了交换分区,因此在这种情况下,/etc/crypttab 中不需要交换分区的条目。

dracut

创建一个密钥文件

# dd bs=512 count=4 if=/dev/random iflag=fullblock | install -m 0600 /dev/stdin /etc/cryptsetup-keys.d/swap.key

将密钥文件添加到 LUKS

# cryptsetup luksAddKey /dev/device /etc/cryptsetup-keys.d/swap.key

配置 dracut 以包含 resume 模块,并将 swap.key 文件添加到 initramfs(另请参阅 dracut#休眠

/etc/dracut.conf.d/resume-from-hibernate.conf
add_dracutmodules+=" resume "
install_items+=" /etc/cryptsetup-keys.d/swap.key "

重新生成 initramfs.

rd.luks.namerd.luks.key (替换交换分区的 UUID)条目添加到您的内核命令行。您的内核命令现在可能看起来像这样

kernel /vmlinuz-linux cryptdevice=/dev/sda2:root root=/dev/mapper/root resume=/dev/mapper/swap rd.luks.name=fd839505-3213-4603-9a70-c5a96a24768f=swap rd.luks.key=/etc/cryptsetup-keys.d/swap.key ro

使用交换文件

交换文件可用于在现有分区内保留交换空间,也可以在加密块设备的分区内设置。

按照 Swap#交换文件 中的交换文件创建说明进行操作,并根据 电源管理/挂起和休眠#配置 initramfs 设置休眠。

本文或章节的真实性存在争议。

原因: resume 钩子仅适用于 BIOS 系统和/或那些不使用基于 systemd 的 initramfs 的系统。有关更多详细信息,请参阅 电源管理/挂起和休眠#配置 initramfs。(在 Talk:Dm-crypt/Swap encryption 中讨论)
注意
  • 从交换文件恢复时,resume 参数必须指向包含交换文件的文件系统的已解锁/映射设备。
  • 确保 mkinitcpio 的 resume 钩子在交换分区所在的设备被解锁后运行,方法是将 resume 放在 HOOKS 数组中的 encrypt 之后。

已知问题