全盘磁盘加密安全启动

来自 Alpine Linux

免责声明:此指南仅供测试目的,请勿直接遵循。当 GRUB 2.12 rc1 可用于 LUKSv2、GRUB 和 FDE 时,此指南将会更新。

本指南逐步解释如何使用 LUKS2 和 LVM (一个物理卷分区和三个逻辑卷分区 (/ /boot 和 swap)) 在 NVMe 驱动器上,通过 UEFI 和安全启动,设置 Alpine Linux 全盘磁盘加密。本指南使用 Alpine Linux Std 3.16.1 编写,如果需要,请调整一些命令。

本指南的目标是遵循 KISS 原则,但也可以使用其他文件系统,如果建议的配置不满足您的要求,也可以添加 /home;/var/log 等的多个分区。

安装软件包

为了方便分区,我们将使用 gdisk

# apk add lsblk gptfdisk

对于加密,我们将使用 cryptsetup

# apk add cryptsetup

对于 LVM

# apk add lvm2

为了使用和管理 UEFI,需要多个软件包

# apk add efibootmgr e2fsprogs grub grub-efi

准备/覆盖磁盘

# apk add haveged

这可能需要很长时间,在我这边,对于 500GB 的 nVME 大约需要 30 分钟。

# haveged -n 0 | dd of=/dev/nvme0n1

磁盘分区

假设磁盘是 /dev/nvme0n1 并且没有分区,我们将创建两个分区

  • 一个用于 UEFI
  • 一个用于 LVM
 # gdisk /dev/nvme0n1
GPT fdisk (gdisk) version 1.0.9.1

Partition table scan:
  MBR: not present
  BSD: not present
  APM: not present
  GPT: not present

Creating new GPT entries in memory.

Command (? for help): n
Partition number (1-128, default 1): 
First sector (34-1000215182, default = 2048) or {+-}size{KMGTP}: 
Last sector (2048-1000215182, default = 1000214527) or {+-}size{KMGTP}: 512M
Current type is 8300 (Linux filesystem)
Hex code or GUID (L to show codes, Enter = 8300): ef00
Changed type of partition to 'EFI system partition'

Command (? for help): n
Partition number (2-128, default 2): 
First sector (34-1000215182, default = 1050624) or {+-}size{KMGTP}: 
Last sector (1050624-1000215182, default = 1000214527) or {+-}size{KMGTP}: 
Current type is 8300 (Linux filesystem)
Hex code or GUID (L to show codes, Enter = 8300): 8309
Changed type of partition to 'Linux LUKS'

Command (? for help): w

Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING
PARTITIONS!!

Do you want to proceed? (Y/N): Y
OK; writing new GUID partition table (GPT) to /dev/nvme0n1.
The operation has completed successfully.

使用新分区填充 /dev

 # partprobe /dev/nvme0n1

配置 LUKS

使用 luks2 (目前 GRUB 不支持)

# cryptsetup -v -c aes-xts-plain64 -s 512 --hash sha512 --pbkdf pbkdf2 --iter-time 1000 --use-random luksFormat /dev/nvme0n1p2

使用 luks1

# cryptsetup -v -c aes-xts-plain64 -s 512 --hash sha512 --iter-time 1000 --use-urandom --type luks1 luksFormat /dev/nvme0n1p2
WARNING!
========
This will overwrite data on /dev/nvme0n1p2 irrevocably.

Are you sure? (Type 'yes' in capital letters): YES
Enter passphrase for /dev/nvme0n1p2: 
Verify passphrase: 
Key slot 0 created.
Command successful.

# cryptsetup luksOpen /dev/nvme0n1p2 lvmcrypt

LVM : 物理卷和逻辑卷创建

# pvcreate /dev/mapper/lvmcrypt
  Physical volume "/dev/mapper/lvmcrypt" successfully created.
# vgcreate vg0 /dev/mapper/lvmcrypt
  Volume group "vg0" successfully created
# lvcreate -L 20G vg0 -n swap (I have a 16GB RAM laptop)
  Logical volume "swap" created.
# lvcreate -l 100%FREE vg0 -n root
  Logical volume "root" created.

检查创建

# lvscan
  ACTIVE            '/dev/vg0/swap' [20.00 GiB] inherit
  ACTIVE            '/dev/vg0/root' [455.92 GiB] inherit

挂载点和文件系统

为 UEFI 分区创建 vfat 文件系统

# mkfs.vfat /dev/nvme0n1p1

为 / 分区创建 ext4 文件系统

# mkfs.ext4 /dev/vg0/root

激活 SWAP

# mkswap /dev/vg0/swap
# swapon /dev/vg0/swap

将 / 分区挂载到 /mnt

# mount -t ext4 /dev/vg0/root /mnt

创建 /boot/efi

# mkdir /mnt/boot/efi -p

将 UEFI 分区挂载到 /mnt/boot/efi

# mount -t vfat /dev/nvme0n1p1 /mnt/boot/efi

检查分区方案

# lsblk
nvme0n1        259:0    0 476.9G  0 disk  
├─nvme0n1p1    259:1    0   511M  0 part  /mnt/boot/efi
└─nvme0n1p2    259:2    0 476.4G  0 part  
  └─lvmcrypt   253:0    0 476.4G  0 crypt 
    ├─vg0-swap 253:1    0    20G  0 lvm   [SWAP]
    └─vg0-root 253:2    0 456.4G  0 lvm   /mnt

安装 Alpine

# setup-disk -m sys /mnt/

mkinitfs 设置和模块

编辑 /mnt/etc/mkinitfs/mkinitfs.conf 文件,并将模块附加到 features 参数 (如果您的键盘不是 QWERTY,则只需要 keymap)

features="ata base ide scsi usb virtio ext4 lvm nvme keymap cryptsetup cryptkey resume"

重新生成 initram

# mkinitfs -c /mnt/etc/mkinitfs/mkinitfs.conf -b /mnt/ $(ls /mnt/lib/modules/)

Grub 设置

创建 crypto_keyfile.bin 以避免在启动过程中输入两次密码 (一个用于 Grub 分区,一个用于 Alpine 分区)

# touch /mnt/crypto_keyfile.bin
# chmod 600 /mnt/crypto_keyfile.bin
# dd if=/dev/random bs=512 count=4 | xxd -p -c999 | tr -d '\n' > /mnt/crypto_keyfile.bin
# cryptsetup luksAddKey /dev/nvme0n1p2 /mnt/crypto_keyfile.bin

然后,让我们挂载并 chroot 到我们全新的安装

# mount -t proc /proc /mnt/proc
# mount --rbind /dev /mnt/dev
# mount --make-rslave /mnt/dev
# mount --rbind /sys /mnt/sys
# chroot /mnt

编辑 /etc/default/grub,并在 cryptdm=root 参数后添加 cryptkey,像这样

GRUB_TIMEOUT=2
GRUB_DISABLE_SUBMENU=y
GRUB_DISABLE_RECOVERY=true
GRUB_CMDLINE_LINUX_DEFAULT="modules=sd-mod,usb-storage,ext4,nvme cryptroot=UUID=XXXX cryptdm=lvmcrypt cryptkey quiet rootfstype=ext4"

XXXX 可以使用 blkid 命令找到

添加一个新的 GRUB_PRELOAD_MODULES 行,像这样

GRUB_PRELOAD_MODULES="luks cryptodisk part_gpt lvm"

最后,添加 cryptodisk 参数

GRUB_ENABLE_CRYPTODISK=y

让我们显示我们分区方案的 UUID

# lsblk -f

创建 /root/grub-pre.cfg,并将 <XXXX-UUID_WITHOUT_HYPHENS> 替换为您的加密 LVM 分区 UUID (此处为 /dev/nvme0n1p2),不带连字符,将 <YYYY> 替换为来自 vgdisplay 的 VG UUID,并将 <ZZZZ> 替换为来自 lvdisplay 的 /dev/vg0/root 的 LV UUID

set crypto_uuid=<XXXX-UUID_WITHOUT_HYPHENS>
cryptomount -u $crypto_uuid
set root='lvmid/<YYYY>/<ZZZZ>'
set prefix=($root)/boot/grub
insmod normal
normal

配置安全启动

# apk add efi-mkkeys efibootmgr sbsigntool
# efi-mkkeys -s "Your Name" -o /etc/uefi-keys

重新安装 Grub

# mkdir /boot/efi/EFI/AlpineLinuxSecureBoot
# grub-mkimage -p /boot/grub -O x86_64-efi -c /root/grub-pre.cfg -o /tmp/grubx64.efi luks2 part_gpt cryptodisk lvm ext2 gcry_rijndael pbkdf2 gcry_sha512
# install -v /tmp/grubx64.efi /boot/efi/EFI/AlpineLinuxSecureBoot/
# sed -i 's/SecureBoot/SecureB00t/' /boot/efi/EFI/AlpineLinuxSecureBoot/grubx64.efi
# cd /boot/efi/EFI/AlpineLinuxSecureBoot/
# sbsign --key /etc/uefi-keys/db.key --cert /etc/uefi-keys/db.crt --output grubx64.efi.signed grubx64.efi
# grub-mkconfig -o /boot/grub/grub.cfg
# efibootmgr --disk /dev/nvme0n1p1 --part 1 --create --label 'Alpine Linux Secure Boot Signed' --load /EFI/AlpineLinuxSecureBoot/grubx64.efi.signed --verbose

检查您的 .efi 是否已签名

 # sbverify --cert /etc/uefi-keys/db.crt /boot/efi/EFI/AlpineLinuxSecureBoot/grubx64.efi.signed 
Signature verification OK
# sbverify --list /boot/efi/EFI/AlpineLinuxSecureBoot/grubx64.efi.signed
signature 1
image signature issuers:
 - /CN="Your Name" (db)
image signature certificates:
 - subject: /CN="Your Name" (db)
   issuer:  /CN="Your Name" (db)

将 db.auth、KEK.auth 和 PK.auth 文件从 /etc/uefi-keys 复制到 FAT 格式的文件系统。

重启并进入您的 UEFI (Fx 键取决于您的笔记本电脑)

导入密钥到 UEFI

这只是一个来自 XPS 笔记本电脑的例子,每个 UEFI 都是独一无二的。

  1. 进入 Boot Configuration > Secure Boot
  2. Enable Secure Boot 更改为 ON
  3. Secure Boot Mode 更改为 Deployed Mode
  4. Enable Custom Mode 更改为 ON
  5. 进入 Custom Mode Key Management
    • 重置所有密钥
    • Select Key Database 选择 db > Replace from file > 选择您的闪存驱动器 > 选择 db.auth
    • Select Key Database 选择 KEK > Replace from file > 选择您的闪存驱动器 > 选择 KEK.auth
    • Select Key Database 选择 PK > Replace from file > 选择您的闪存驱动器 > 选择 PK.auth
  6. APPLY CHANGES > EXIT

检查安全启动状态

# apk add mokutil
# mokutil --sb-state
SecureBoot enabled

恭喜!

在加密的 LVM 交换分区上休眠

找到您的 vg0-swap UUID

lsblk -f

将 resume 参数添加到您的 /etc/default/grub

GRUB_CMDLINE_LINUX_DEFAULT=....resume=UUID=<UUID of your vg0-swap partition>

在您的 /etc/fstab 中添加一行

/dev/vg0/swap   none            swap     sw    0 0

在启动期间启用 swap 服务

rc-update add swap default

安装 zzz 并测试它

# apk add zzz
zzz- Z

完成并恭喜!