My avatar

北雁云依的博客

My avatar

北雁云依的博客

决不跪在地上
以显出刽子手们的高大
好阻挡自由的风

RSS
· 浏览

LUKS2 YubiKey全盘加密手稿

本文最近一次更新于2024年8月6日。

前言

自从发现自己随时可能被中华人民共和国人民警察们搜查以来,我的加密偏执就复发了。我决定用LUKS2和YubiKey武装我的电脑。可能的话,我还要把这枚YubiKey改造得易于摧毁。

不过,配置环境起码要两天左右,我手头上的事太多了,中间还有一个半月在医院度过,因此迟迟没有动手。4个月后,我终于有时间了。于是开干。

准备工作

我阅读了几篇文章:

结合各方优劣,得出了自己的方案。事先在虚拟机里尝试了两遍,最终得到了比较满意的结果。

方案介绍

本方案会使用LUKS2加密EFI分区以外的整个硬盘,使用Unified Kernel Image引导。引导+系统启动只需要输入一次密码(使用YubiKey则可配置为不需要密码,也可配置为2FA)。EFI分区中会存在一个 main.efi,里面包含了 initramfsmicrocodekernel。会使用 sbctl 对它们进行签名,从而支持 Secure Boot,最后,配置 YubiKey 用于解密 LUKS2

本方案会使用 linux-zen 而非 linux 内核。

本方案不会使用 TPMTPM 配置不当可能导致你的加密功亏一篑。1如确有需要,可参考“准备工作”一节中的第二篇文章。

尽管我会加入很多可能不必要的细节,但这只是因为我的神经多样性,本文的性质仍然是笔记 / 手稿,不是操作说明。本文中的命令仅作示意,实际操作过程中可能会有所不同。

本文作于2024年2月10日。你阅读这篇文章时,内容可能已经过时。我并不具备足够的安全知识,本文的操作无法确保安全。

安装系统

此时你的Secure Boot应该在关闭状态。我觉得不会有谁想在安装系统时开启Secure Boot。

首先,遵循安装指南,至安装指南#建立硬盘分区为止。

lsblk
cfdisk /dev/nvme0n1

第一个分区会作为EFI分区,分1G或者0.5G即可,后续UKI会占用 ~100MB。

剩下的空间全分给第二个分区,这将是你的加密分区。不再分一个Swap分区的原因是当前btrfs已经支持swapfile,可在btrfs分卷时或完成安装后自行配置,本文不再赘述。

mkfs.vfat -n EFI /dev/nvme0n1p1 # 假设这是第一个分区

创建、挂载、格式化LUKS2容器,默认设置已经基本满足需求:

cryptsetup luksFormat /dev/nvme0n1p2 # 假设这是第二个分区
cryptsetup open /dev/nvme0n1p2 system
mkfs.btrfs --label system /dev/mapper/system

cryptsetup luksFormat /dev/nvme0n1p2 时,会提示你输入密码。这时可以设置一个安装时临时使用的密码,配置完YubiKey后再改。

临时挂载btrfs根,创建subvolume(子卷):

mount /dev/mapper/system /mnt
btrfs subvolume create /mnt/@root
btrfs subvolume create /mnt/@home
btrfs subvolume create /mnt/@var

具体建多少子卷,建哪些,见仁见智。

然后,卸载根、挂载子卷和ESP分区:

umount -R /mnt
mount --mkdir -o noatime,subvol=@root /dev/mapper/system /mnt
mount --mkdir -o noatime,subvol=@home /dev/mapper/system /mnt/home
mount --mkdir -o noatime,subvol=@var /dev/mapper/system /mnt/var
mount --mkdir /dev/nvme0n1p1 /mnt/efi

设置镜像站,安装系统并chroot:

vim /etc/pacman.d/mirrorlist
# 此处 -K的含义是复制keyring
pacstrap -K /mnt base linux-zen linux-firmware intel-ucode btrfs-progs

此后,遵循安装指南#配置系统,对系统进行配置。配置好以后,别急着 umount 和重启。你需要配置引导。

# 如果遵循前述步骤,此时你应该在arch-chroot环境中
pacman -Syu networkmanager base-devel vim sbctl efibootmgr
vim /etc/mkinitcpio.conf

将它的 HOOKS 一栏配置为如下形式:

HOOKS=(base systemd autodetect modconf kms keyboard sd-vconsole block sd-encrypt filesystems fsck)

先不加入 plymouth,等引导成功后再加入,便于观察输出。

vim /etc/mkinitcpio.d/linux-zen.preset

注释 default_image,并取消 default_ukidefault_options 的注释。必要时更改 default_image 的路径。示例:

# mkinitcpio preset file for the 'linux-zen' package

#ALL_config="/etc/mkinitcpio.conf"
ALL_kver="/boot/vmlinuz-linux-zen"

PRESETS=('default' 'fallback')

#default_config="/etc/mkinitcpio.conf"
#default_image="/boot/initramfs-linux-zen.img"
default_uki="/efi/main.efi"
default_options="--splash /usr/share/systemd/bootctl/splash-arch.bmp"

#fallback_config="/etc/mkinitcpio.conf"
#fallback_image="/boot/initramfs-linux-zen-fallback.img"
fallback_uki="/efi/fallback.efi"
fallback_options="-S autodetect"

创建 /etc/kernel/cmdline,写入:

fbcon=nodefer rw rd.luks.allow-discards cryptdevice=/dev/nvme0n1p2:system bgrt_disable root=LABEL=system rootflags=subvol=@root,rw splash vt.global_cursor_default=0

这将是你的内核参数,以后需要配置内核参数的话就改这里。mkinitcpio 会自动配置好 microcode。安装 intel-ucodeamd-ucode 即可,无需额外在参数里加上。

创建 /etc/crypttab.initramfs,写入:

system /dev/nvme0n1p2 none timeout=180,fido2-device=auto

这一步是让 initramfs 启动时解密位于 /dev/nvme0n1p2 的LUKS2容器,并挂载到 /dev/mapper/system

创建或编辑 /etc/vconsole.conf

KEYMAP=us
FONT=lat2-16

这将能解决 mkinitcpio 时的警告。

创建密钥并生成Unified Kernel Image,加入引导:

sbctl create-keys
mkinitcpio -P
efibootmgr --disk /dev/nvme0n1 --part 1 --create --label "Arch Linux" --loader /efi/main.efi
exit # 退出chroot
umount -R /mnt
reboot

这次应该能启动进入系统。启动过程中会要求你输入此前 cryptsetup luksFormat 时设置的密码。

进入系统后,可以遵循如下步骤连接到无线网络:

systemctl enable --now NetworkManager
nmtui

设置NTP:

timedatectl set-ntp true

配置YubiKey

按照建议阅读,配置好多用户与桌面。

使用如下命令确保你的YubiKey具备FIDO2功能:

sudo systemd-cryptenroll --fido2-device=list

你将能得到类似下面的输出:

PATH         MANUFACTURER PRODUCT
/dev/hidraw0 Yubico       YubiKey FIDO+CCID

使用如下命令将YubiKey添加到LUKS2容器的解密设备列表:

sudo systemd-cryptenroll /dev/nvme1n1p2 --fido2-device=auto --fido2-with-client-pin=no --fido2-credential-algorithm=eddsa

参数意义如下:

参数说明
/dev/nvme1n1p2设备路径
--fido2-device设备,可用auto,或前面的 /dev/hidraw0
--fido2-with-client-pin默认是 yes,此处置 no,从而开机时只需要触摸YubiKey而不需输入PIN,可自行调整为需要PIN
--fido2-credential-algorithm算法,此处选择 eddsa。我没有打错字,不是 ecdsa

可参考 systemd-cryptenroll#FIDO2_tokens

sudo mkinitcpio -P 后重启系统,确认YubiKey配置成功。

确定YubiKey可以运行后,记得通过 cryptsetup luksChangeKey /dev/nvme0n1p2 来修改此前临时设置的密码。改个强一点、最好你自己也记不住的,然后写在纸上(最好用遇水能洇开的墨水),放在安全但又随手可及的地方。

可以用如下命令生成:

openssl rand -base64 16

配置Plymouth

想看Plymouth的话,此时也可以配置好。我的Plymouth在启动时会出现方块,原因是 initramfs 里没有字体,解决方法为在 mkinitcpio 时加入。照着下面的例子编辑 /etc/mkinitcpio.conf

# 你可以改成别的字体
FILES=(/usr/share/fonts/noto/NotoSans-Regular.ttf)

配置Snapper

Snapper可以对你的btrfs进行定期快照与恢复。我使用图形化的Btrfs Assistant配置,因此这里没什么可以说的。

配置Secure Boot

此步操作不当可能导致你的数据丢失。

把这放到最后一步是因为它最麻烦,并且开了Secure Boot以后,从系统维护盘启动进行修正会变得困难。

不使用TPM的前提下,配置Secure Boot的用处并不大,反而会带来很多麻烦。但如果使用了TPM(把密钥写入了TPM),那么不配置Secure Boot就会导致安全性下降。1我也是因为Windows那边开了Bitlocker(加密系统盘时,会把密钥写入TPM)才想着配置Secure Boot。

如果你的电脑有Windows系统,并且Windows系统盘开启了Bitlocker,那么请备份并保管好恢复密钥,下次启动Windows时很可能会用到。

在BIOS界面,开启Secure Boot,并重置为Setup Mode。重启进入Linux。使用如下命令将密钥安装进Secure Boot:

sbctl enroll-keys -mcft

如果你的Secure Boot没被重置为Setup Mode,那么这一步会报错。请勿强行写入

各参数说明:

参数说明
-mMicrosoft,添加微软密钥,从而使Windows能够启动
-ccustom,添加自定义密钥,从而使你的Linux能够启动
-ffirmware-builtin,添加固件内置密钥
-ttpm-eventlog,添加TPM事件日志

sbctl 有一个 Hook,它会在每次 mkinitcpio 输出镜像时自动签名。因此,你不需要手动更新。你也可以参考 sbctl 的手册页来获得更多用法。例如,使用 sbctlrefindsystemd-boot 进行签名。

当那一天来临

如果需要紧急销毁密钥,正确的步骤是:

  • 找到前述写有密码的纸条,将其销毁。
  • 销毁YubiKey,确保其芯片(内部的硅片)破碎。如果你此前配置的是 --fido2-with-client-pin=no,那么这步应当先做。 YubiKey比较坚固,你可能要用些工具,或在平时就将它改造得易于摧毁。

这以后,就可以微笑着迎接破门而入的军警宪特了。祝你不要有这一天。


Footnotes

  1. 可以参考这篇文章备份链接)和这篇文章备份链接)。如果不想TPM变成突破口,就不要把密钥丢TPM里。 2

分享

复制此页面地址到邦联宇宙搜索框以在邦联宇宙分享本文:https://blog.yunyi.beiyan.us/posts/luksNote

在本站发言,即意味着你同意评论政策(最后更新于2025-06-22)。