跳转到内容

dm-crypt/交换分区加密

来自 Arch Linux 中文维基

本文介绍了多种加密交换分区的方法,可满足不同的需求。若在每次重启时都重新对交换分区进行加密(使用不同密钥)的方式,可避免换出到交换分区上的敏感文件片段因未被覆盖而长期存在,从而更好地保护数据。然而,若使用重新加密,则无法使用休眠功能。

无需休眠支持

[编辑 | 编辑源代码]

若无需使用休眠功能,则可以通过配置/etc/crypttab,在每次启动时以随机密码,使用dm-crypt plain模式进行解密。在关机时,随机密码将被丢弃,设备上只含有加密的、无法访问的交换数据。

要使用该配置,只需要取消注释/etc/crypttab中以swap开头的一列,并修改“设备”(device)参数指向交换分区,例如:

/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。之后,像普通的swap分区一样,将/dev/mapper/swap添加到/etc/fstab中,即可完成交换分区配置。若之前已经配置了非加密的交换分区,需要将其禁用(或直接将其在fstab中的条目指向/dev/mapper/swap)。上面给出的选项应当足以应对大多数场景。若需要了解每个选项的详细解释,可参见crypttab(5)point cryptsetup FAQ 2.3

警告:上述配置中“设备”参数对应的设备的数据将被永久清除。不要使用内核的简单命名(例如,/dev/sda, /dev/sdb)指定设备,简单命名的顺序可能在每次启动时都不同,导致设备数据被意外清除。建议使用如下方式指定:
注意:有时,交换分区配置可能失败,参见systemd issue 10179

若要使用by-id持久化命名,首先,找到swap分区对应的设备:

# 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

之后,修改配置文件,使用持久化引用(若上述命令返回多个结果,任选一个即可):

/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命令,可看到交换分区的FSTYPEcrypt。由于每次启动时都重新加密并格式化交换分区,/dev/mapper/swap的文件系统UUID会在每次启动时变化。

注意:若swap分区之前曾用作LUKS加密卷,则crypttab不会覆盖该LUKS加密卷以创建加密的swap分区。这是一项安全措施,用于避免在crypttab中错误指定swap分区对应的设备时,造成数据丢失。若确定要使用之前的LUKS加密卷作为swap分区,必须先覆盖LUKS头

文件系统UUID和文件系统标签

[编辑 | 编辑源代码]

在crypttab中使用内核简单命名(例如,/dev/sdX#)、ID命名(例如,/dev/disk/by-id/ata-SERIAL-partX)指定加密交换分区的目标设备有较大风险,设备名称、分区结构的细微变化都可能导致指向错误的设备,从而造成数据丢失。使用PARTLABEL、PARTUUID(与分区,而不是文件系统、设备绑定)的风险相对较小,但若打算将目标设备用作其它用途,而忘记移除crypttab中的条目,数据仍可能被覆盖(文件系统改变,分区不改变)。

更可靠的方法是使用文件系统标签或文件系统UUID。但在默认情况下,每次重启时,dm-crypt和mkswap都将覆盖目标分区上的内容,导致文件系统标签和文件系统UUID被移除。不过,可以指定swap分区的起始偏移量,以在设备开始处放置另一个空的、容量较小的文件系统。该文件系统仅用于提供持久性的文件系统UUID和文件系统标签。

使用指定文件系统标签创建文件系统

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

设备名后的1M参数限制文件系统的大小为1MiB,为之后加密的交换分区留出空间。

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

这样,无论设备名称、分区数量如何变化,始终可以使用文件系统UUID或文件系统标签指向/dev/sdX#

接下来,配置/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

注意偏移量的指定(offset=2048),偏移量的单位为512字节的扇区(不受dm-crypt扇区大小的影响),因此offset=2048相当于1MiB,跳过了提供UUID的文件系统的区域,因此不影响文件系统UUID和文件系统标签,并正确处理了数据对齐。

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

在本配置中,只会尝试使用特定文件系统标签的设备作为加密交换分区,而不受设备名称影响。若打算将加密交换分区用作其它用途,当格式化时,文件系统标签被覆盖,因此/etc/crypttab不会在下次启动时意外覆盖新的文件系统及数据。

在桌面环境中关闭休眠

[编辑 | 编辑源代码]

桌面环境可能无法自动检测到swap分区已被随机密码加密,不能用作休眠,仍错误显示休眠按钮。

若使用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

需要休眠支持

[编辑 | 编辑源代码]

下面介绍在需要进行休眠的情况下,设置加密swap的三种方法。若已经使用其中一种方法完成设置,需要注意系统换出的敏感数据可能在交换分区/交换文件中保留较长时间,直到被覆盖。若要降低相关风险,可以设置系统任务,在特定时机(例如,系统关机时)重新加密交换分区/重置交换文件。

使用交换文件

[编辑 | 编辑源代码]

交换文件可放置在加密设备的文件系统中。依照Swap#交换文件中的方法创建交换文件,并完成休眠设置即可。

若采用加密根文件系统的配置,并使用基于systemd的initrd,则配置加密交换文件非常简单、灵活。在完成配置加密的根文件系统后,只需要按常规方式创建并激活交换文件,并将其添加到/etc/fstab中即可,无需额外配置。

注意:在设置resume=内核参数时,注意其必须指向解密后产生的映射设备,该映射设备包含存储有交换文件的文件系统。

使用交换分区

[编辑 | 编辑源代码]
注意:若要重用当前正在被系统使用的交换分区,必须先以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

在映射设备上创建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

在initramfs中解密分区

[编辑 | 编辑源代码]

若要从加密的交换分区中唤醒,必须在initramfs中解密该分区。

mkinitcpio
[编辑 | 编辑源代码]
基于systemd的initramfs
[编辑 | 编辑源代码]

若使用基于systemd的inintramfs(使用sd-encrypt钩子),则可使用如下任意一个方案:

例如,若使用TPM加密交换分区:

/etc/crypttab.initramfs
swap UUID=56f8ee97-54b3-4a65-9282-688deb922527 none tpm2-device=auto
基于busybox的initramfs
[编辑 | 编辑源代码]

若使用基于busybox的initramfs(使用encrypt钩子),需进行如下操作。

若交换分区所在设备与根文件系统的不同,则其不会被encrypt钩子打开。由于从休眠中唤醒的过程在读取/etc/crypttab前进行,不能在/etc/crypttab中进行配置以打开加密的交换分区,而需要修改/etc/mkinitcpio.conf并创建自定义钩子,以在唤醒开始之前打开加密的交换分区。

注意:本节只适用于encrypt钩子,其只能解密单个设备(archlinux/mkinitcpio/mkinitcpio#231);若使用sd-encrypt钩子,则可以解密多个设备(包括加密的交换分区),详见Dm-crypt/系统配置#systemd-gpt-auto-generator

mkinitcpio-openswapAUR中包含了所需的钩子及配置文件。

警告:在系统休眠且还未恢复时,在initramfs中挂载文件系统非常危险且可能导致数据丢失。若使用密钥文件解密,密钥文件不应保存到任何休眠时已挂载的文件系统上。
注意:为了降低文件系统损坏的可能性,上述包中的脚本使用了-o ro,noload挂载选项。这些选项适用于ext4文件系统,若使用其它文件系统,需修改openswap.conf,使用作用相似的选项。

openswap钩子添加到/etc/mkinitcpio.confHOOKS数组中,注意应当添加到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参数。

修改后的内核命令行应当与下例相似:

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

在LUKS上配置LVM

[编辑 | 编辑源代码]

若交换分区位于LVM卷组内,且对应卷组在initramfs中被激活,只需要按照电源管理/挂起与休眠#休眠中的步骤进行配置即可。

已知问题

[编辑 | 编辑源代码]
  • 系统日志中出现形如Stopped (with error) /dev/dm-1的错误。详见systemd issue 1620