在日常使用Linux系统时,大家总会遇到需要保护数据安全的场景。LUKS(Linux Unified Key Setup)作为Linux系统中常用的全盘加密解决方案,能够有效地保护磁盘上的数据。本文将详细介绍如何在Linux系统中使用LUKS进行全盘加密。
LUKS的配置非常灵活,能够进行对已有数据的加密。下面我将介绍如何在已经安装了Linux系统的机器中使用LUKS进行全盘加密。
- 发行版:Arch Linux
- 使用systemd来管理系统服务
- 硬盘:NVMe QLC SSD
- 采用GRUB作为引导加载程序
- 根分区
/dev/nvme0n1p8使用ext4文件系统 - ESP分区
/dev/nvme0n1p6用于存放引导文件
准备工作
在开始之前,我们需要准备好cryptsetup工具。Arch Linux Live环境中已经预装了该工具。
评估加解密性能
首先,我们将测试系统的加解密性能。如果你的电脑的加解密速度还不如硬盘读写速度,应该考虑不要使用LUKS加密。
1 | cryptsetup benchmark |
确认要进行LUKS加密后,启动到Arch Linux Live环境。不要挂载分区,以便进行后续操作。
LUKS2加密推荐保留32 MB的未分配空间来存储加密头信息。准确地说,是LUKS2最小头信息大小的两倍。
在Linux中,分区与文件系统是不同的概念,我们将要缩小文件系统来为LUKS加密腾出空间。这一步可以先缩得小一些,后续可以再扩大。
缩小文件系统,为加密预留空间
例如,我们将ext4格式的根分区/dev/nvme0n1p8缩小到99G,以腾出空间用于存储LUKS加密头信息。
1 | e2fsck -f /dev/nvme0n1p8 |
完成文件系统的缩小后,应尝试启动系统,确保一切正常。
分离/boot与根分区
让GRUB解密磁盘是一件很麻烦的事情。为了使GRUB能够正常启动Linux,我们需要让/boot和/不在同一分区上。
笔者原先只是把ESP分区挂载在/efi,但ESP分区足够大,有1 GB。现在我们可以把/boot中的内容移动到ESP分区,再把/efi所在的分区挂载为/boot。
1 | mount /dev/nvme0n1p8 /mnt |
启动验证与文件系统检查
完成上述步骤后,应再次尝试启动系统,确保一切正常。为保险起见,应再次执行e2fsck检查文件系统。
开始加密
接下来,我们将开始对根分区进行LUKS加密。
务必确保电脑连接稳定的电源。在加密过程中断电可能会导致数据丢失!
执行原地加密
1 | cryptsetup reencrypt --encrypt --reduce-device-size=32m /dev/nvme0n1p8 |
这意味着我们将在分区开头留出32 MB的空间用于存储LUKS加密头信息,加密后的数据将从偏移32 MB处开始存储,整个可用空间减少32 MB。因为我们已经预先缩小了文件系统,所以数据不会超出可用范围,不会丢失。
系统会询问你是否进行加密。因为我们完成了文件系统的缩小,所以不会有内容被抹去,可以输入YES继续。接下来请输入并确认加密密码。
接下来就是漫长的等待时间。笔者在一块使用QLC闪存的硬盘上加密了750 GB的数据,花费了大约3小时2分钟。
打开加密分区并扩展文件系统
完成加密后,应尝试解密分区。
1 | cryptsetup open /dev/nvme0n1p8 crypt_data |
输入密码后,分区将被解密并映射到/dev/mapper/crypt_data。若一切正常,我们可以扩大文件系统以恢复剩余的空间。
1 | resize2fs /dev/mapper/crypt_data |
挂载检查数据完整性
接下来,挂载分区并检查数据是否完好无损。
1 | mount /dev/mapper/crypt_data /mnt |
完成检查后,先不要退出Live环境,接下来我们将进行必要的配置以确保系统能够正常启动。
配置系统
为了使系统能够在启动时解密LUKS分区,我们需要在初始化内存盘中包含系统解密的支持。首先挂载/boot分区,并切换到已安装的系统环境中。
挂载/boot并进入chroot环境
1 | mount /dev/nvme0n1p6 /mnt/boot |
为了使用FIDO2安全密钥进行解密,我们需要使用sd-encrypt钩子,而不是传统的encrypt钩子,即添加sd-encrypt钩子到/etc/mkinitcpio.conf的HOOKS数组中。
更新mkinitcpio钩子
打开/etc/mkinitcpio.conf文件,找到HOOKS行,将原有的udev替换为systemd,再将sd-encrypt添加到filesystems之前的位置,类似下面:
1 | HOOKS=(base systemd autodetect microcode modconf kms keyboard keymap consolefont block sd-encrypt resume filesystems fsck) |
为了在输入口令时启动小键盘数字锁定,可以安装mkinitcpio-sd-numlockAUR包,并将sd-numlock钩子添加到sd-encrypt之前。
保存并退出后,重新生成初始化内存盘:
重新生成initramfs
1 | mkinitcpio -P |
接下来,我们要配置分区的自动挂载。请注意,因为我们加密的是根分区,所以不应在/etc/crypttab中配置,而是要更新GRUB配置。编辑/etc/default/grub文件:
配置GRUB内核参数
编辑/etc/default/grub文件,找到GRUB_CMDLINE_LINUX行,添加rd.luks.name=参数,指定加密分区的UUID和映射名称。可以使用blkid命令获取分区的UUID。
为了方便起见,可以在vim中使用:r !blkid /dev/nvme0n1p8命令来把命令输出插入到文件中,再把光标移到合适的位置,用36x和p命令剪切和粘贴UUID。完成后记得删除插入的行。
增加内核参数,将LUKS分区映射到/dev/mapper/root,并设为根分区。记得把UUID替换为实际的内容,如下所示:
1 | GRUB_CMDLINE_LINUX="... rd.luks.name=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx=root root=/dev/mapper/root ..." |
保存并退出。
更新fstab指向映射设备
需要进一步更新/etc/fstab文件,确保根分区指向解密后的映射设备。应将原有的根分区行中的UUID替换为/dev/mapper/root,例如:
1 | /dev/mapper/root / ext4 rw,relatime 0 1 |
生成GRUB配置并重启
重新生成GRUB配置:
1 | grub-mkconfig -o /boot/grub/grub.cfg |
完成后,退出chroot环境并重启系统:
1 | exit |
在系统启动时,应该会提示输入LUKS加密的密码。输入正确的密码后,系统将继续启动并挂载根分区。
进阶配置
完成加密后,就可以在线使用LUKS分区并进行管理操作了。
更新加密口令
要更新LUKS分区的密码,我们应先添加新密码,再删除旧密码。可以使用以下命令:
1 | sudo cryptsetup luksAddKey /dev/nvme0n1p8 |
注册FIDO2安全密钥
要使用FIDO2安全密钥进行解密,可以使用以下命令将硬件密钥添加到LUKS分区:
1 | sudo systemd-cryptenroll --fido2-device=auto /dev/nvme0n1p8 |
这样,我们就完成了LUKS全盘加密的配置。
至于TPM2.0自动解密,由于涉及到安全启动的配置,笔者因使用NVIDIA硬件难以配置安全启动,故无法测试该功能。
开启TRIM支持
默认情况下,LUKS会阻止TRIM命令传递到底层存储设备,这是为了安全考虑(dm-crypt/特殊应用 § 固态硬盘的Discard/TRIM支持 — Arch Linux 中文维基)。
如果使用的是SSD,开启TRIM支持可以提升性能和延长寿命,还有利于保护对LUKS头的修改。执行:
1 | sudo cryptsetup --allow-discards --persistent refresh root |
请记得启用fstrim.timer systemd服务,以在后台定期运行TRIM操作。
配置交换分区
在使用LUKS时,需要搭配加密交换分区以保护交换数据。此处演示如何将已有的交换分区加密。
创建加密交换分区
首先,卸载已有的交换分区:
1 | sudo swapoff /dev/nvme0n1p7 |
然后,清空并使用LUKS加密交换分区:
1 | sudo cryptsetup luksFormat --label=swap /dev/nvme0n1p7 |
打开该容器,并映射到/dev/mapper/swap:
1 | sudo cryptsetup open /dev/disk/by-label/swap swap |
在映射设备上创建swap文件系统:
1 | sudo mkswap /dev/mapper/swap |
这样我们就完成了加密交换分区的创建。
配置系统使用加密交换分区
编辑/etc/fstab文件,将映射设备添加为交换分区:
1 | /dev/mapper/swap none swap defaults 0 0 |
最后,编辑/etc/default/grub文件,增加一组rd.luks.name=参数,并更改交换分区的resume参数。加密分区的UUID可以通过blkid /dev/nvme0n1p7命令获取。
编辑后的参数类似:
1 | GRUB_CMDLINE_LINUX="... rd.luks.name=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx=swap resume=/dev/mapper/swap ..." |
重新生成GRUB配置:
1 | sudo grub-mkconfig -o /boot/grub/grub.cfg |
这样就完成了加密交换分区的配置。
接下来可以为交换分区更改验证方式,例如添加TPM2.0自动解密,方法与根分区类似。
未雨绸缪
建议创建一个恢复密钥,以便在忘记密码时使用。此外,为了防止加密头信息损坏导致数据无法访问,建议备份LUKS加密头信息。
创建恢复密钥
1 | sudo systemd-cryptenroll --recovery-key /dev/nvme0n1p8 |
请把恢复密钥妥善保管在安全的地方。
备份加密头信息
1 | sudo cryptsetup luksHeaderBackup /dev/nvme0n1p8 --header-backup-file luks_header_backup.img |
结语
数据无价,谨慎操作。
LUKS全盘加密为Linux用户提供了强大的数据保护手段,但在实施过程中务必小心谨慎,确保数据安全。