dm-crypt/加密整个系统
本文介绍了几种常见的使用“dm-crypt”加密整个系统的方式,以及相比正常安装过程所需的改动。官方安装镜像已经包含了加密所需的工具。
若要加密的是已有的未加密的文件系统,见 dm-crypt/设备加密#加密现有的未加密文件系统。
“dm-crypt”能为为根文件系统提供安全保护,且相比其它方案具更优的性能。相比仅仅加密部分非根文件系统,加密根文件系统可以隐藏许多敏感信息(如已安装应用列表、用户名等),并能避免通过locate、/var/log/等常见方式泄露数据。此外,由于除了引导加载程序和内核(通常情况下),所有数据都被加密,更难对系统进行未授权的改动。
除了上面提到的共同优点以外,各种加密方案还有如下特有的优缺点:
| 方案 | 优点 | 缺点 |
|---|---|---|
| #在单一分区上配置LUKS 展示了使用LUKS完全加密的根文件系统的基本方式,最直接。 |
|
|
|
#使用TPM2和安全启动在单一分区上配置
与上例相似,并通过使用安全启动、TPM2提高了安全性。 |
相比上例,本方法还有如下优点:
|
|
|
#在LUKS上配置LVM
在LUKS加密的单一分区上配置LVM,实现了分区灵活性。 |
|
|
|
#在LVM上配置LUKS
在LVM上层使用LUKS。 |
|
|
|
#在软RAID上配置LUKS
在软RAID上层使用LUKS。 |
|
|
|
#Plain dm-crypt
使用dm-crypt的plain模式(不使用LUKS头及LUKS的多密钥选项)。 |
|
|
|
#加密boot分区(GRUB)
展示了如何在使用GRUB时加密boot分区。 |
|
|
| #Root on ZFS |
|
虽然对于外界威胁,相比文件系统层面的加密,上述方案提供了好得多的保护。但也有一个共同的缺点:任何拥有密码的用户都能解密整个设备,进而访问其它用户的数据。若要防范上述风险,可以结合使用块设备加密和文件系统加密。可参见静态数据加密进行提前规划。
对于本文中所有方案的分区策略的概述,参见dm-crypt/准备磁盘#分区。
此外,还需考虑是否设置加密的swap分区及设置方式。详见Dm-crypt/交换分区加密。
加密整个系统可在设备失窃时保护数据,但不能抵御逻辑层面的非法修改(例如,系统上运行的恶意软件修改未加密的boot分区)。若有相关需求,还应参见dm-crypt/特殊应用#保护未加密的boot分区。
在使用固态硬盘时,可能需要启用TRIM支持。但这可能影响安全性,详见dm-crypt/特殊应用#固态硬盘的Discard/TRIM支持。
- 在任何情况下都不要直接在加密卷上运行文件系统修复工具(例如,fsck),否则,加密密钥将永久丢失,使得所有加密内容无法被解密。只应当在解密后的设备上运行文件系统修复工具。
- Argon2 密钥派生函数的设计方式使得其在运行时将占用大量内存(在默认设置下,每个加密卷将占用1GiB内存)。在设备内存较少或启动时并行解密多个LUKS2分区的情况下,可能导致错误。可使用
--pbkdf-memory选项控制内存使用。[1] - GRUB对LUKS2的支持并不完善,详见GRUB#加密的/boot。对于需要由GRUB解密的分区,建议使用PBKDF2密钥派生函数(
cryptsetup luksFormat --pbkdf pbkdf2)。 - 对于ZFS,即使交换分区并没有放置在zvol上,从休眠中唤醒时也有可能损坏存储池。因此在配置休眠时需要额外注意。参考
本例说明了如何通过“dm-crypt”与LUKS,将安装在单一分区上的系统进行加密。
+-----------------------+------------------------+-----------------------+ | boot分区 | LUKS加密的根分区 | 可选的用于其它分区的 | | | partition | 空闲空间 | | | | | | /boot | / | | | | | | | | /dev/mapper/root | | | |------------------------| | | /dev/sda1 | /dev/sda2 | | +-----------------------+------------------------+-----------------------+
本例的前几步可在启动到Arch Linux安装镜像后直接进行。
在创建分区前,应先查看dm-crypt/准备磁盘,了解安全地擦除整个磁盘的重要性,并掌握相关方法。
接下来,创建本例中的分区(至少需要/(/dev/sda2)和/boot(/dev/sda1),详见分区。
在格式化分区时,不要使用安装指南中的步骤,而是使用本节及下一节的步骤。
使用如下命令创建并挂载加密的根分区,dm-crypt/设备加密#使用 LUKS 模式加密设备中详细介绍了进行的操作。若要使用非默认的加密选项(例如,修改加密算法,密钥长度,扇区大小),在执行如下第一条指令前参见相关加密选项。
# cryptsetup -v luksFormat /dev/sda2 # cryptsetup open /dev/sda2 root
在解密的LUKS设备上创建文件系统。例如,要创建Ext4文件系统,执行:
# mkfs.ext4 /dev/mapper/root
将根分区挂载到/mnt:
# mount /dev/mapper/root /mnt
确保设备映射正常:
# umount /mnt # cryptsetup close root # cryptsetup open /dev/sda2 root # mount /dev/mapper/root /mnt
若还创建了其它分区(例如,/home),则对于除了/boot的其它分区,执行类似操作。在启动时解密其它分区的方法可参见dm-crypt/加密非root文件系统#自动解锁并挂载。
注意,对于每个要加密并挂载的块设备,都需要单独设置密钥,这将导致在启动时需要多次输入密钥,造成不便。可通过在根分区中存储密钥文件,并通过修改crypttab设置,自动使用密钥文件解锁其它设备。详见dm-crypt/设备加密#使用LUKS来格式化带有密钥文件的分区。
对于加密根分区的配置,需要设置非加密的/boot分区。
对于UEFI启动的系统,使用如下命令格式化新创建的EFI 系统分区:
# mkfs.fat -F32 /dev/sda1
对于传统BIOS启动的系统:
# mkfs.ext4 /dev/sda1
之后,创建boot分区的挂载点并挂载分区:
# mount --mkdir /dev/sda1 /mnt/boot
在安装指南#挂载分区步骤时,应当挂载/dev/mapper/*中的相应设备(包含LUKS加密的设备的解密后的版本),而不是LUKS加密的设备自身对应的分区。不过,对于未加密的/boot分区,仍应当直接挂载到/mnt/boot(假设在安装过程中,根分区被挂载到/mnt)。
在安装指南#关于_initramfs步骤前,需要在新安装的系统中完成如下操作:
若使用基于busybox的initramfs,在mkinitcpio.conf中添加keyboard和encrypt钩子。此外,若要使用非标准键盘布局,添加keymap钩子;若要自定义控制台字体,添加consolefont钩子。
HOOKS=(base udev autodetect microcode modconf kms keyboard keymap consolefont block encrypt filesystems fsck)
若使用基于systemd的initramfs,在mkinitcpio.conf中添加keyboard和sd-encrypt钩子。此外,若要使用非标准键盘布局,或要自定义控制台字体,添加sd-vconsole钩子。
HOOKS=(base systemd autodetect microcode modconf kms keyboard sd-vconsole block sd-encrypt filesystems fsck)
保存上述修改后,重新生成initramfs。其它可能需要用到的钩子以及配置细节参见Dm-crypt/系统配置#mkinitcpio。
要在启动时解密已加密的根分区,需配置引导加载程序,设置如下内核参数:
cryptdevice=UUID=device-UUID:root root=/dev/mapper/root
若使用的是sd-encrypt,则应该添加如下内核参数:
rd.luks.name=device-UUID=root root=/dev/mapper/root
device-UUID指的是LUKS超级块的UUID,在本例中为/dev/sda2对应的UUID。详见块设备持久化命名。
本例与#在单一分区上配置LUKS相似,但通过使用安全启动和可信平台模块,使启动过程更安全。
在本配置方案中,只有EFI 系统分区是未加密的,存储经过签名以用于安全启动的统一内核映像和systemd-boot。在本配置中,若安全启动功能被关闭,或者安全启动的密钥数据库被修改,则TPM将不会释放用于解密分区的密钥。此时,仍可以使用配置过程中创建的恢复密钥解密数据。此外,还可要求在解密数据前必须输入设置的TPM PIN码。本配置方案类似Windows中的BitLocker和macOS中的FileVault。
在继续之前,确保已经详细阅读了可信平台模块#LUKS_数据加密,并着重留意其中的警告。
本例中的分区按照符合Systemd#GPT分区自动挂载的方式创建,因此无需fstab、crypttab文件。
+-----------------------+---------------------------------+ | EFI系统分区 | LUKS加密的根分区 | | | | | | | | /boot | / | | | | | | /dev/mapper/root | | |---------------------------------| | /dev/sda1 | /dev/sda2 | +-----------------------+---------------------------------+
按照安装指南#创建硬盘分区前的步骤进行基本配置。之后,按本文下一节的内容进行磁盘分区。
在创建分区前,应先查看dm-crypt/准备磁盘,了解安全地擦除整个磁盘的重要性,并掌握相关方法。
使用GUID分区表 (GPT),并创建需要的分区。
创建大小合适的EFI 系统分区(在本例中,使用/dev/sda1)。该分区将被挂载到/boot。
在磁盘的剩余空间上创建根分区(在本例中,使用/dev/sda2)。根分区将被加密,并挂载到/。将根分区的分区类型GUID设置为4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709(在fdisk中,设置为"Linux root (x86-64)"类型;在gdisk中,设置为8304类型)。
使用如下命令创建并挂载加密的根分区,dm-crypt/设备加密#使用 LUKS 模式加密设备中详细介绍了进行的操作。
若要使用非默认的加密选项(例如,修改加密算法,密钥长度,扇区大小),或者不想使用TPM解密,在执行如下第一条指令前参见相关加密选项。
创建并挂载LUKS卷(由于在配置完成后将擦除密码槽位,可以直接使用空密码):
# cryptsetup luksFormat /dev/sda2 # cryptsetup open /dev/sda2 root
在解密的LUKS设备上创建文件系统。例如,要创建Ext4文件系统,执行:
# mkfs.ext4 /dev/mapper/root
将根分区挂载到 /mnt:
# mount /dev/mapper/root /mnt
格式化新创建的EFI系统分区,并挂载:
# mount --mkdir /dev/sda1 /mnt/boot
继续执行安装指南#关于_initramfs前的步骤。注意无需执行安装指南#生成_fstab_文件步骤。
修改mkinitcpio.conf中的HOOKS=为如下内容,以构建可用的基于systemd的initramfs:
HOOKS=(base systemd autodetect microcode modconf kms keyboard sd-vconsole block sd-encrypt filesystems fsck)
按照统一内核映像#mkinitcpio中的步骤配置统一内核映像。
由于/boot/EFI/Linux目录暂未由启动加载程序创建,暂时不要重新生成initramfs。
可以直接通过UEFI启动内核,而无需引导加载程序。
若仍需使用引导加载程序,可以安装systemd-boot:
# bootctl install
systemd-boot可自动识别mkinitcpio生成的统一内核映像,无需在/boot/loader/entries/手动添加条目。
其它配置参见systemd-boot#更新 EFI 启动管理器 、Systemd-boot#配置。
重新生成initramfs,并确保相关镜像成功生成。
不要忘记设置 root 密码,重启以完成安装。
为了启用安全启动,需要为引导加载程序、EFI镜像签名。可使用sbctl简单、快速地实现。
在签名引导加载程序并启用安全启动后,可以向TPM注册密钥用以解锁LUKS卷。如下命令将移创建LUKS卷时设置的空密码,创建绑定到TPM PCR 7(安全启动状态和已注册证书)寄存器的密钥,并创建恢复密钥,用于在TPM出现问题时解密卷。若安全启动链完好,TPM将自动释放密钥。详见systemd-cryptenroll#Trusted Platform Module、systemd-cryptenroll(1)。
# systemd-cryptenroll /dev/sda2 --recovery-key # systemd-cryptenroll /dev/sda2 --wipe-slot=empty --tpm2-device=auto --tpm2-pcrs=7
--tpm2-with-pin=yes参数。
在加密的单个分区上配置LVM是一种较为直接的方案。该方案将LVM设置在一个大的加密块设备中,LVM结构只在块设备解密,扫描并挂载LVM物理卷后才可见。
示例磁盘结构如下:
+-----------------------------------------------------------------------+ +----------------+ | 逻辑卷 1 | 逻辑卷 2 | 逻辑卷 3 | | boot分区 | | | | | | | | [SWAP] | / | /home | | /boot | | | | | | | | /dev/MyVolGroup/swap | /dev/MyVolGroup/root | /dev/MyVolGroup/home | | | |_ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _| | (可能在其他 | | | | 设备上) | | 使用LUKS加密的分区 | | | | /dev/sda1 | | /dev/sdb1 | +-----------------------------------------------------------------------+ +----------------+
- dm-crypt/特殊应用#在加密系统时使用分离的LUKS头介绍了如何将LUKS头单独存放于USB设备上,实现两步验证。
- dm-crypt/Specialties#Encrypted /boot and a detached LUKS header on USB则将LUKS头、加密的boot分区、加密的密钥文件都存放在USB设备上。
在创建分区前,应先查看dm-crypt/准备磁盘,了解安全地擦除整个磁盘的重要性,并掌握相关方法。
创建一个大于1GiB的分区用于/boot。
/boot。创建一个分区,用于存储整个加密的LVM。
在上述创建的分区上配置LUKS作为LVM的容器(若要修改加密选项,参见dm-crypt/设备加密#LUKS 模式的加密选项):
# cryptsetup luksFormat /dev/sda1
打开创建的容器:
# cryptsetup open /dev/sda1 cryptlvm
现在可通过/dev/mapper/cryptlvm访问解密的容器。
在解密的LUKS容器上创建物理卷:
# pvcreate /dev/mapper/cryptlvm
创建卷组(本例中使用MyVolGroup,也可使用其它名称),并加入先前创建的物理卷:
# vgcreate MyVolGroup /dev/mapper/cryptlvm
在卷组中创建逻辑卷:
-l 100%FREE创建占满所有剩余空间的最后一个逻辑卷后,使用类似lvreduce -L -256M MyVolGroup/home的命令减少该逻辑卷的大小。# lvcreate -L 4G -n swap MyVolGroup # lvcreate -L 32G -n root MyVolGroup # lvcreate -l 100%FREE -n home MyVolGroup
在每个逻辑卷上创建文件系统。例如,若根分区和home分区使用Ext4文件系统:
# mkfs.ext4 /dev/MyVolGroup/root # mkfs.ext4 /dev/MyVolGroup/home # mkswap /dev/MyVolGroup/swap
挂载文件系统:
# mount /dev/MyVolGroup/root /mnt # mount --mkdir /dev/MyVolGroup/home /mnt/home # swapon /dev/MyVolGroup/swap
引导加载程序从/boot目录加载内核、initramfs和自身的配置文件。可使用任何引导加载程序支持的文件系统。
为/boot分区创建文件系统。对于UEFI启动的系统,使用如下命令格式化新创建的EFI 系统分区:
# mkfs.fat -F32 /dev/sdb1
对于传统BIOS启动的系统:
# mkfs.ext4 /dev/sdb1
将上述分区挂载到/mnt/boot:
# mount --mkdir /dev/sdb1 /mnt/boot
继续执行安装指南#开始安装系统中的步骤。之后回到本页,执行修改后的关于 initramfs、安装引导程序步骤。
若使用基于busybox的initramfs,在mkinitcpio.conf中添加keyboard、encrypt、lvm2钩子。此外,若要使用非标准键盘布局,添加keymap钩子;若要自定义控制台字体,添加consolefont钩子。
HOOKS=(base udev autodetect microcode modconf kms keyboard keymap consolefont block encrypt lvm2 filesystems fsck)
若使用基于systemd的initramfs,在mkinitcpio.conf中添加keyboard、sd-encrypt、lvm2钩子。此外,若要使用非标准键盘布局,或要自定义控制台字体,添加sd-vconsole钩子。
HOOKS=(base systemd autodetect microcode modconf kms keyboard sd-vconsole block sd-encrypt lvm2 filesystems fsck)
保存上述修改后,重新生成initramfs。其它可能需要用到的钩子以及配置细节参见Dm-crypt/系统配置#mkinitcpio。
注意:若使用dracut生成mkinitcpio,则其已经包含必要的模块,无需额外配置。
要在启动时解密已加密的根分区,需配置引导加载程序设置如下内核参数:
cryptdevice=UUID=device-UUID:cryptlvm root=/dev/MyVolGroup/root
若使用的是sd-encrypt,则应该添加如下内核参数:
rd.luks.name=device-UUID=cryptlvm root=/dev/MyVolGroup/root
device-UUID指的是LUKS超级块的UUID,在本例中为/dev/sda1对应的UUID。详见块设备持久化命名。
若使用dracut,一般可使用如下参数:
rd.luks.uuid=device-UUID root=/dev/MyVolGroup/root
有时,需要设置更多参数:
rd.luks.uuid=luks-deviceUUID rd.lvm.lv=MyVolGroup/root rd.lvm.lv=MyVolGroup/swap root=/dev/mapper/MyVolGroup-root rootfstype=ext4 rootflags=rw,relatime
为了在LVM上层设置加密,首先要设置LVM卷,用作加密分区的基础。在本方案中,可同时创建加密及未加密的分区。
下例展示了在LVM上配置LUKS加密卷,并使用密钥文件解锁home分区。对于swap分区,使用临时加密卷,以确保在每次重启后,都重新配置swap分区的加密,防止敏感信息泄露,提升安全性。若熟悉LVM配置,可自行修改LVM分区方案。
若要创建横跨多个磁盘的逻辑卷,或要将已有逻辑卷扩展到其它已配置好的磁盘上,详见dm-crypt/特殊应用#将LVM拓展到多个磁盘上。注意调整逻辑卷的大小后,LUKS加密容器的大小也需要调整。
分区方案如下:
+----------------+-------------------------------------------------------------------------------------------------+ | boot分区 | dm-crypt plain加密的分区 | LUKS加密的分区 | LUKS加密的分区 | | | | | | | /boot | [SWAP] | / | /home | | | | | | | | /dev/mapper/swap | /dev/mapper/root | /dev/mapper/home | | |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _| | | 逻辑卷 1 | 逻辑卷 2 | 逻辑卷 3 | | | /dev/MyVolGroup/cryptswap | /dev/MyVolGroup/cryptroot | /dev/MyVolGroup/crypthome | | |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _| | | | | /dev/sda1 | /dev/sda2 | +----------------+-------------------------------------------------------------------------------------------------+
按照dm-crypt/准备磁盘#dm-crypt 擦除空设备或分区随机擦除/dev/sda2。
# pvcreate /dev/sda2 # vgcreate MyVolGroup /dev/sda2 # lvcreate -L 4G -n cryptswap MyVolGroup # lvcreate -L 32G -n cryptroot MyVolGroup # lvcreate -l 100%FREE -n crypthome MyVolGroup
# cryptsetup luksFormat /dev/MyVolGroup/cryptroot # cryptsetup open /dev/MyVolGroup/cryptroot root
在解密后的设备上创建文件系统,并挂载到对应挂载点。例如,要创建Ext4文件系统:
# mkfs.ext4 /dev/mapper/root # mount /dev/mapper/root /mnt
关于加密选项的更多信息,详见dm-crypt/设备加密#LUKS 模式的加密选项。
注意/home的加密会在#加密/home逻辑卷步骤中进行。
open操作。为/boot分区创建文件系统。对于UEFI启动的系统,使用如下命令格式化新创建的EFI 系统分区:
# mkfs.fat -F32 /dev/sda1
对于传统BIOS启动的系统:
# mkfs.ext4 /dev/sda1
之后,创建boot分区的挂载点并挂在分区:
# mount --mkdir /dev/sda1 /mnt/boot
若使用基于busybox的initramfs,在mkinitcpio.conf中添加keyboard、encrypt、lvm2钩子。此外,若要使用非标准键盘布局,添加keymap钩子;若要自定义控制台字体,添加consolefont钩子。
HOOKS=(base udev autodetect microcode modconf kms keyboard keymap consolefont block lvm2 encrypt filesystems fsck)
若使用基于systemd的initramfs,在mkinitcpio.conf中添加keyboard、sd-encrypt、lvm2钩子。此外,若要使用非标准键盘布局,或要自定义控制台字体,添加sd-vconsole钩子。
HOOKS=(base systemd autodetect microcode modconf kms keyboard sd-vconsole block sd-encrypt lvm2 filesystems fsck)
保存上述修改后,重新生成initramfs。其它可能需要用到的钩子以及配置细节参见Dm-crypt/系统配置#mkinitcpio。
要在启动时解密已加密的根分区,需配置引导加载程序设置如下内核参数:
cryptdevice=UUID=device-UUID:root root=/dev/mapper/root
若使用的是sd-encrypt,则应该添加如下内核参数:
rd.luks.name=device-UUID=root root=/dev/mapper/root
device-UUID指的是LUKS超级块的UUID,在本例中为/dev/MyVolGroup/cryptroot对应的UUID。详见块设备持久化命名。
若使用的是dracut,需要一系列更复杂的参数:
kernel_cmdline="rd.luks.uuid=luks-deviceUUID rd.lvm.lv=MyVolGroup/root rd.lvm.lv=MyVolGroup/swap root=/dev/mapper/MyVolGroup-root rootfstype=ext4 rootflags=rw,relatime"
crypttab用于解密设备,fstab用于挂载文件系统。如下配置将在每次重启时用不同的密钥重新加密swap分区:
/etc/crypttab
swap /dev/MyVolGroup/cryptswap /dev/urandom swap,cipher=aes-xts-plain64,size=256,sector-size=4096
/etc/fstab
/dev/mapper/root / ext4 defaults 0 1 UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx /boot ext4 defaults 0 2 /dev/mapper/swap none swap defaults 0 0
由于本方案使用LVM作为第一层,dm-crypt作为第二层,每个加密逻辑卷都需要单独进行加密解密配置。此外,显然,和临时文件系统可采用临时随机密钥加密不同,/home对应的逻辑卷应该采用持久不变的密钥。下列命令假定你已经重启进入了安装好的系统。否则,需要调整相应路径。
为了避免在系统启动时输入两次密码,创建密钥文件:
# dd bs=512 count=4 if=/dev/random iflag=fullblock | install -m 0600 /dev/stdin /etc/cryptsetup-keys.d/home.key
/home逻辑卷将采用上述密钥文件加密:
# cryptsetup luksFormat -v /dev/MyVolGroup/crypthome /etc/cryptsetup-keys.d/home.key # cryptsetup -d /etc/cryptsetup-keys.d/home.key open /dev/MyVolGroup/crypthome home
在解密后的设备上创建文件系统,并挂载到对应挂载点。例如,要创建Ext4文件系统:
# mkfs.ext4 /dev/mapper/home # mount /dev/mapper/home /home
/etc/crypttab
home /dev/MyVolGroup/crypthome none
/etc/fstab
/dev/mapper/home /home ext4 defaults 0 2
下例基于真实的工作站笔记本设置,该工作站有两块大小相同的SSD及一块大容量机械硬盘。在本配置中,对所有磁盘采用LUKS加密(包括/boot),并将两块SSD组成了RAID0阵列。系统启动时,在GRUB中输入正确的密码后,将用解密出的密钥文件解密所有分区。
本方案采用的分区配置非常简单,组成的RAID阵列挂载在/(没有单独的/boot 分区),解密后的机械硬盘挂载在/data。
注意对于本方案,定期的备份非常重要。若两块SSD中的任何一块损坏,整个RAID阵列中的数据都将丢失。若要求较高的容错能力,应选择其它RAID级别。
本配置中的加密方式不是可抵赖加密。
在之后的命令中,假定采用如下块设备设置:
/dev/sda = 第一块SSD /dev/sdb = 第二块SSD /dev/sdc = 机械硬盘
+---------------------+---------------------------+---------------------------+ +---------------------+---------------------------+---------------------------+ +---------------------------+ | BIOS boot分区 | EFI系统分区 | LUKS加密的分区 | | BIOS 启动分区 | EFI系统分区 | LUKS加密的分区 | | LUKS加密的分区 | | | | | | | | | | | | | /efi | / | | | /efi | / | | /data | | | | | | | | | | | | | | /dev/mapper/root | | | | /dev/mapper/root | | | | +---------------------------+---------------------------+ | +---------------------------+---------------------------+ | | | | RAID1 array (part 1 of 2) | RAID0 array (part 1 of 2) | | | RAID1 array (part 2 of 2) | RAID0 array (part 2 of 2) | | | | | | | | | | | | | | | /dev/md/ESP | /dev/md/root | | | /dev/md/ESP | /dev/md/root | | /dev/mapper/data | | +---------------------------+---------------------------+ | +---------------------------+---------------------------+ +---------------------------+ | /dev/sda1 | /dev/sda2 | /dev/sda3 | | /dev/sdb1 | /dev/sdb2 | /dev/sdb3 | | /dev/sdc1 | +---------------------+---------------------------+---------------------------+ +---------------------+---------------------------+---------------------------+ +---------------------------+
在之后的操作中,需要根据实际情况替换上述配置。
在创建分区前,应先查看dm-crypt/准备磁盘,了解安全地擦除整个磁盘的重要性,并掌握相关方法。
对于使用GPT分区表的BIOS启动的系统,需创建一个大小为1MiB的BIOS启动分区,GRUB将在此存储第二阶段的BIOS引导加载程序。不要挂载该分区。
对于UEFI启动的系统,需创建大小适当的EFI 系统分区,并挂载到/efi。
对于设备上的剩余空间,创建一个用于"Linux RAID"的分区(本例中为/dev/sda3)。对于MBR分区表,选择fd分区类型ID;对于GPT分区表,选择A19D880F-05FC-4D3B-A006-743F0F84911E分区类型GUID。
一旦在/dev/sda上创建好了分区,可使用下列命令将它们的配置克隆到/dev/sdb上:
# sfdisk -d /dev/sda > sda.dump # sfdisk /dev/sdb < sda.dump
对于机械硬盘,创建单个占据整个磁盘的Linux分区(/dev/sdc1)。
创建用于两块SSD的RAID阵列:
- 对于两块SSD,EFI系统分区必须能在每块SSD上单独访问,因此只能存放在RAID1上。
- 必须通过
--metadata=1.0选项将RAID superblock放置在EFI系统分区的后部,否则固件将不能访问EFI系统分区。
# mdadm --create --verbose --level=1 --metadata=1.0 --raid-devices=2 /dev/md/ESP /dev/sda2 /dev/sdb2
对于根分区,本例采用了RAID0。可根据实际偏好与需要选择其它RAID级别。
# mdadm --create --verbose --level=0 --metadata=1.2 --raid-devices=2 /dev/md/root /dev/sda3 /dev/sdb3
dm-crypt/准备磁盘中介绍了通过使用随机密钥创建加密卷,并向加密卷中写入/dev/zero产生的全零数据来随机擦除设备的方法。此外,也可使用dd与/dev/random或/dev/urandom来擦除,不过速度较慢。
# cryptsetup open --type plain --sector-size 4096 --key-file /dev/urandom /dev/md/root to_be_wiped # dd if=/dev/zero of=/dev/mapper/to_be_wiped bs=1M status=progress # cryptsetup close to_be_wiped
对本例中的机械硬盘(/dev/sdc1)也需重复上述操作。
为/dev/md/root设置加密:
cryptsetup luksFormat --pbkdf pbkdf2)。# cryptsetup -v luksFormat --pbkdf pbkdf2 /dev/md/root # cryptsetup open /dev/md/root root
在解密后的设备上创建文件系统。例如,要创建Ext4文件系统:
# mkfs.ext4 /dev/mapper/root
将根分区挂载到/mnt:
# mount /dev/mapper/root /mnt
对机械硬盘,类似的:
# cryptsetup -v luksFormat /dev/sdc1 # cryptsetup open /dev/sdc1 data # mkfs.ext4 /dev/mapper/data # mount --mkdir /dev/mapper/data /mnt/data
对于UEFI启动的系统,还需设置EFI系统分区:
# mkfs.fat -F32 /dev/md/ESP # mount --mkdir /dev/md/ESP /mnt/efi
对于本例中通过LUKS加密的系统,编辑/etc/default/grub以配置GRUB:
GRUB_CMDLINE_LINUX="cryptdevice=/dev/md/root:root" GRUB_ENABLE_CRYPTODISK=y
对于较新的设备,可能需要使用USB键盘在GRUB中输入密码。这需要启用固件中的”legacy USB support“,或在/etc/default/grub中添加:
GRUB_TERMINAL_INPUT="usb_keyboard" GRUB_PRELOAD_MODULES="usb usb_keyboard ohci uhci ehci"
否则在提示输入LUKS密码时可能无法使用键盘。详见Dm-crypt/系统配置#内核参数、GRUB#加密的/boot。
将GRUB安装到两块SSD上(事实上,仅安装到/dev/sda也是可行的):
# grub-install --target=i386-pc /dev/sda # grub-install --target=i386-pc /dev/sdb # grub-install --target=x86_64-efi --efi-directory=/efi --bootloader-id=GRUB # grub-mkconfig -o /boot/grub/grub.cfg
进行如下步骤可避免在启动时需输入两次密码(第一次发生在GRUB解密LUKS设备,第二次发生在initramfs接管系统时)。首先要创建密钥文件,然后将该密钥文件加入到initramfs镜像中以便encrypt钩子解密根分区。详见dm-crypt/设备加密#在_initramfs_中嵌入密钥文件。
- 创建密钥文件并向其中添加
/dev/md/root的密码。 - 创建另一个密钥文件以便于在启动时解密机械硬盘(
/dev/sdc1)。为了便于以后可能的需要恢复的情况,不要移动/删除上述密钥文件。接下来编辑/etc/crypttab以在启动时解密机械硬盘。详见Dm-crypt/系统配置#使用密钥文件解密。
配置fstab以挂载根分区、data分区、EFI系统分区:
/dev/mapper/root / ext4 rw,noatime 0 1 /dev/mapper/data /data ext4 defaults 0 2 /dev/md/ESP /efi vfat rw,relatime,codepage=437,iocharset=iso8859-1,shortname=mixed,utf8,tz=UTC,errors=remount-ro 0 2
保存RAID配置:
# mdadm --detail --scan >> /etc/mdadm.conf
编辑mkinitcpio.conf,包含密钥文件,并添加所需的钩子:
FILES=(/crypto_keyfile.bin) HOOKS=(base udev autodetect microcode modconf kms keyboard keymap consolefont block mdadm_udev encrypt filesystems fsck)
与LUKS不同,dm-crypt的plain模式无需在加密设备前附加LUKS头,本方案利用该特点在未分区的硬盘上设置加密的系统。对于他人,将无法区分用该方式加密的硬盘与与用随机数据填充的硬盘,即所谓可抵赖加密。详见wikipedia:Disk encryption#Full disk encryption。
注意,除非需要将整个硬盘全部加密,否则,无论是加密整个系统还是部分分区,使用之前小节中介绍的基于LUKS的方法都是更好的选择。因为在plain模式中,无法使用LUKS特有的功能,例如支持多个密码、密钥文件的密钥管理,主密钥备份,原位重新加密。
由于不依赖主密钥,可避免主密钥损坏或被销毁导致的单点故障,plain模式对数据损坏的承受能力更强。此外,若尤为在意对SSD的TRIM支持,也可以使用plain模式。然而,在plain模式下,要到达与LUKS模式相同的加密强度,需要手动配置加密选项。详见静态数据加密#加密的元数据。
- 通过cryptsetup的
--header选项使用分离的LUKS头。注意若使用该方案则不能使用标准的"encrypt"钩子,不过可对该钩子进行修改。 - tcplay 在无LUKS头加密模式下提供了PBKDF2函数。
本方案使用了两个U盘:
- 一个用于引导设备,同时存储用于解密plain加密设备的配置选项;
- 一个用于密钥文件,将按原始比特位存储,故不了解加密方案的攻击者只能看到一串仿佛随机的数据,而非可见的普通文件。详见Wikipedia:Security through obscurity。要准备密钥文件,参见dm-crypt/Device encryption#Keyfiles。
磁盘布局如下:
+----------------------+----------------------+----------------------+ +----------------+ +----------------+ | 逻辑卷 1 | 逻辑卷 2 | 逻辑卷 3 | | 启动设备 | | 密钥 | | | | | | | | 存储设备 | | / | [SWAP] | /home | | /boot | | (在本例中 | | | | | | | | 未分区) | | /dev/MyVolGroup/root | /dev/MyVolGroup/swap | /dev/MyVolGroup/home | | /dev/sdb1 | | /dev/sdc | |----------------------+----------------------+----------------------| |----------------| |----------------| | /dev/sda 使用plain模式加密并配置LVM | | U盘 1 | | U盘 2 | +--------------------------------------------------------------------+ +----------------+ +----------------+
- 也可以只使用一个U盘,如下为两种方式:
- 在U盘(/dev/sdb)的另一个分区(/dev/sdb2)上存储密钥。
- 直接复制密钥文件到initramfs中。例如,在
/etc/mkinitcpio.conf中设置FILES=(/etc/cryptsetup-keys.d/root.key)将复制/etc/cryptsetup-keys.d/root.key密钥文件到initramfs镜像中。要使得encrypt钩子从initramfs镜像中读取密钥文件,在文件名前添加rootfs:前缀,例如,cryptkey=rootfs:/etc/cryptsetup-keys.d/root.key。
- 此外,也可使用足够安全的密码解密。
向解密后的映射设备中填充随机数据是非常重要的。尤其是在本例中。
详见dm-crypt/准备磁盘、dm-crypt/准备磁盘#dm-crypt_专用方案
在本例中,使用/dev/sda,并使用aes-xts加密算法,密钥长度为512位,并使用密钥文件加密:
# cryptsetup open --type plain --cipher=aes-xts-plain64 --offset=0 --key-file=/dev/sdc --key-size=512 --sector-size 4096 /dev/sda cryptlvm
与使用LUKS不同,每次要解密设备时必须使用上述“完整”的命令,故一定要牢记加密算法、密钥文件相关信息。
检查有关/dev/mapper/cryptlvm的映射条目已建立:
# fdisk -l
- 若无需使用LVM提供的功能,cryptsetup FAQ提倡直接在解密后的设备上创建文件系统,而不创建LVM。
- 若LVM卷组中包含ext4文件系统的逻辑卷,为了便于使用e2scrub(8)工具,至少在卷组中保留256MiB的空闲空间。若使用
-l 100%FREE参数创建了最后一个逻辑卷,可以使用lvreduce -L -256M MyVolGroup/home留出256MiB的空闲空间。
接下来,在解密后产生的映射设备上设置LVM逻辑卷,详见Install Arch Linux on LVM:
# pvcreate /dev/mapper/cryptlvm # vgcreate MyVolGroup /dev/mapper/cryptlvm # lvcreate -L 32G MyVolGroup -n root # lvcreate -L 4G MyVolGroup -n swap # lvcreate -l 100%FREE MyVolGroup -n home
格式化并挂载上述分区并激活swap,详见文件系统#创建文件系统。
# mkfs.ext4 /dev/MyVolGroup/root # mkfs.ext4 /dev/MyVolGroup/home # mount /dev/MyVolGroup/root /mnt # mount --mkdir /dev/MyVolGroup/home /mnt/home # mkswap /dev/MyVolGroup/swap # swapon /dev/MyVolGroup/swap
可直接将单独的U盘(通常使用FAT32文件系统)作为/boot分区。或者,若要手动分区,使用分区工具创建大小为1GiB的小分区,并建立文件系统。
# mkfs.fat -F32 /dev/sdb1 # mount --mkdir /dev/sdb1 /mnt/boot
若使用基于busybox的initramfs,在mkinitcpio.conf中添加keyboard、encrypt、lvm2钩子。此外,若要使用非标准键盘布局,添加keymap钩子;若要自定义控制台字体,添加consolefont钩子。
HOOKS=(base udev autodetect microcode modconf kms keyboard keymap consolefont block encrypt lvm2 filesystems fsck)
保存上述修改后,重新生成initramfs。其它可能需要用到的钩子以及配置细节参见Dm-crypt/系统配置#mkinitcpio。
要从加密的根分区启动,需通过引导加载程序设置如下内核参数(注意512位对应64字节):
cryptdevice=/dev/disk/by-id/disk-ID-of-sda:cryptlvm:sector-size=4096 cryptkey=/dev/disk/by-id/disk-ID-of-sdc:0:64 crypto=:aes-xts-plain64:512:0:
disk-ID-of-disk表示相应磁盘的id,详见块设备持久化命名。
对于其它可能需要的内核参数,详见Dm-crypt/系统配置#内核参数。
/boot分区所在的U盘上。
对于BIOS启动的系统:
# grub-install --target=i386-pc --recheck /dev/sdb
对于UEFI启动的系统:
# grub-install --target=x86_64-efi --efi-directory=/boot --removable
或许希望在系统启动后移除启动用的U盘。由于/boot分区并不常用,可在/etc/fstab的相应行中添加noauto选项:
/etc/fstab
# /dev/sdb1 UUID=XXXX-XXXX /boot vfat noauto,rw,noatime 0 2
然而,若需要更新initramfs、内核、引导加载程序使用的相关文件时,则必须挂载/boot分区。由于fstab中存在相关条目,只需执行如下命令即可挂载:
# mount /boot
本配置使用与#在LUKS上配置LVM相同的分区结构和配置。但使用了GRUB引导加载程序,其能从LVM逻辑卷和LUKS加密的/boot上启动系统。详见GRUB#加密的/boot
本例中的磁盘结构如下:
+---------------------+----------------------+----------------------+----------------------+----------------------+ | BIOS boot分区 | EFI系统分区 | 逻辑卷 1 | 逻辑卷 2 | 逻辑卷 3 | | | | | | | | | /efi | / | [SWAP] | /home | | | | | | | | | | /dev/MyVolGroup/root | /dev/MyVolGroup/swap | /dev/MyVolGroup/home | | /dev/sda1 | /dev/sda2 |----------------------+----------------------+----------------------+ | 未加密 | 未加密 | /dev/sda3 使用LUKS加密并配置LVM | +---------------------+----------------------+--------------------------------------------------------------------+
- 所有提供的案例仅用作示例。可按需与其它方案结合使用。此外,可参见#在LUKS上配置LVM中介绍的两种变形。
- 可以使用cryptbootAUR中的
cryptboot脚本简化加密boot分区的管理(包括挂载、卸载、软件包更新)。此外,该脚本与UEFI安全启动配合还可抵御邪恶女佣攻击。更多信息及存在的问题见cryptboot project。
在创建分区前,应先查看dm-crypt/准备磁盘,了解安全地擦除整个磁盘的重要性,并掌握相关方法。
对于UEFI启动的系统,创建大小合适的EFI 系统分区,将挂载该分区到/efi。
对于BIOS + GPT启动的系统,创建大小为1MiB的BIOS启动分区,GRUB将在该分区中存储第二阶段引导加载程序,不要手动挂载该分区。
对于BIOS + MBR启动的系统,无需创建BIOS启动分区。
创建一个类型为8309的分区用于加密的LVM。
创建LUKS加密容器:
cryptsetup luksFormat --pbkdf pbkdf2)。# cryptsetup luksFormat --pbkdf pbkdf2 /dev/sda3
关于加密选项的更多信息,在执行上述命令前参见dm-crypt/设备加密#LUKS 模式的加密选项。
分区结构应与下述相似:
# gdisk -l /dev/sda
... Number Start (sector) End (sector) Size Code Name 1 2048 4095 1024.0 KiB EF02 BIOS boot partition 2 4096 2101247 1024.0 MiB EF00 EFI system partition 3 2101248 69210111 32.0 GiB 8309 Linux LUKS
打开LUKS加密容器:
# cryptsetup open /dev/sda3 cryptlvm
解密后的容器将在/dev/mapper/cryptlvm。
本例中逻辑卷的结构与#在LUKS上配置LVM中的相同。因此,只需遵循#准备逻辑卷中的步骤并按需调整。
对于UEFI启动的系统,将EFI 系统分区挂载到/efi,以与接下来的grub-install指令相匹配。
# mount --mkdir /dev/sda2 /mnt/efi
现在,在/mnt下应挂载有如下分区与逻辑卷:
$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 200G 0 disk
├─sda1 8:1 0 1M 0 part
├─sda2 8:2 0 550M 0 part /mnt/efi
└─sda3 8:3 0 100G 0 part
└─cryptlvm 254:0 0 100G 0 crypt
├─MyVolGroup-swap 254:1 0 4G 0 lvm [SWAP]
├─MyVolGroup-root 254:2 0 32G 0 lvm /mnt
└─MyVolGroup-home 254:3 0 60G 0 lvm /mnt/home
继续执行安装指南#开始安装系统及之后的步骤。请使用本文中的对应内容替换安装指南的Initramfs、安装引导加载程序步骤。
若使用基于busybox的initramfs,在mkinitcpio.conf中添加keyboard、encrypt、lvm2钩子。此外,若要使用非标准键盘布局,添加keymap钩子;若要自定义控制台字体,添加consolefont钩子。
HOOKS=(base udev autodetect microcode modconf kms keyboard keymap consolefont block encrypt lvm2 filesystems fsck)
若使用基于systemd的initramfs,在mkinitcpio.conf中添加keyboard、sd-encrypt、lvm2钩子。此外,若要使用非标准键盘布局,或要自定义控制台字体,添加sd-vconsole钩子。
HOOKS=(base systemd autodetect microcode modconf kms keyboard sd-vconsole block sd-encrypt lvm2 filesystems fsck)
保存上述修改后,重新生成initramfs。其它可能需要用到的钩子以及配置细节参见Dm-crypt/系统配置#mkinitcpio。
配置GRUB以从LUKS加密的/boot启动:
/etc/default/grub
GRUB_ENABLE_CRYPTODISK=y
设置内核参数以便initramfs解密加密的根分区。
若使用encrypt钩子:
/etc/default/grub
GRUB_CMDLINE_LINUX="... cryptdevice=UUID=device-UUID:cryptlvm ..."
若使用sd-encrypt钩子:
/etc/default/grub
GRUB_CMDLINE_LINUX="... rd.luks.name=device-UUID=cryptlvm ..."
详见Dm-crypt/系统配置#内核参数、GRUB#加密的/boot。device-UUID应为LUKS superblock的UUID(在本例中为/dev/sda3,该分区包含了含有根分区的LVM)。详见块设备持久化命名。
对于UEFI启动的系统,安装GRUB到挂载的EFI系统分区:
# grub-install --target=x86_64-efi --efi-directory=/efi --bootloader-id=GRUB --recheck
对于BIOS启动的系统,安装GRUB:
# grub-install --target=i386-pc --recheck /dev/sda
生成GRUB配置文件:
# grub-mkconfig -o /boot/grub/grub.cfg
若上述所有命令都成功执行,在下次重启后GRUB应提示输入密码解锁/dev/sda3。
尽管在上述操作后,GRUB会要求输入密码解密LUKS加密的分区,但密码并不会传递到initramfs中。因此,需要在启动时输入两次密码:一次用于GRUB,一次用于initramfs。
可通过在initramfs中嵌入密钥文件避免输入两次密码。
首先,创建一个密钥文件,将其添加到LUKS key中:
# dd bs=512 count=4 if=/dev/random iflag=fullblock | install -m 0600 /dev/stdin /etc/cryptsetup-keys.d/cryptlvm.key # cryptsetup -v luksAddKey /dev/sda3 /etc/cryptsetup-keys.d/cryptlvm.key
将密钥文件添加到initramfs镜像:
/etc/mkinitcpio.conf
FILES=(/etc/cryptsetup-keys.d/cryptlvm.key)
重新生成initramfs镜像。
设置如下内核参数以通过密钥文件解密LUKS分区。
若使用encrypt钩子:
GRUB_CMDLINE_LINUX="... cryptkey=rootfs:/etc/cryptsetup-keys.d/cryptlvm.key"
若使用sd-encrypt钩子,将默认使用/etc/cryptsetup-keys.d/name.key密钥文件,因此无需手动设置内核参数。
若由于某些原因密钥文件解密boot分区失败,systemd会要求手动输入密码。输入正确的密码后,系统启动将正常进行。
使用存储在单独USB设备上的密钥文件可避免使用密码(若密码太复杂,则难以记忆;若太简单,则容易被猜中)。从安全性角度考虑,在未使用时,存储有密钥文件的USB设备必须与需解密的设备分开保存。
首先,按照#避免需输入两次密码中的步骤创建新的密钥文件。不要复用initramfs中使用的密钥文件,否则,若USB设备丢失或密钥泄露,需要修改嵌入到initramfs中的密钥文件。
将创建的密钥文件复制到USB设备,并创建GRUB配置文件:
/boot/grub/grub-pre.cfg
set crypto_uuid=UUID-of-the-luks-volume set key_disk=UUID-of-the-volume-with-the-key cryptomount -u $crypto_uuid -k ($key_disk)/the-location-of-the-key-on-your-usb set root=UUID-of-the-unlocked-volume-as-in-grub.cfg set prefix=($root)/boot/grub insmod normal normal
创建并安装GRUB镜像(依文件系统设置而定,可能不需要在镜像中包含某些模块):
# grub-mkimage -p /boot/grub -O x86_64-efi -c /boot/grub/grub-pre.cfg -o /tmp/grubx64.efi part_gpt part_msdos cryptodisk luks gcry_rijndael gcry_sha512 lvm ext2 ntfs fat exfat # install -v /tmp/grubx64.efi /efi/EFI/GRUB/grubx64.efi
要将dm-crypt与ZFS一同使用,参见ZFS#Encryption in ZFS using dm-crypt。
此外,ZFS具有原生加密支持,可用于加密根分区(不包含引导加载程序和文件系统元数据)。详见:
对于UEFI启动的系统,在安装后可通过安全启动验证引导加载程序。