目录

Arch Linux重装记

使用Arch也有四年左右了,一直比较稳定,只不过最开始出于兜底考虑还是保留着windows+arch双系统(虽说几乎用不到win),而且原来的分区表也比较乱,Arch的分区并不连续,中间隔着windows的150G左右。

先前考察过Btrfs现在比较成熟了,索性趁机把全盘格掉重新分配,windows的部分彻底干掉,全盘改成Btrfs+LUKS。

备份

第二块硬盘依旧做数据盘不动,顺便可以存放备份。

/目录的内容都用rsync备份下来,之后再用rsync恢复,参考rsync全系统备份命令

1
# rsync -aAXHv --exclude='/dev/*' --exclude='/proc/*' --exclude='/sys/*' --exclude='/tmp/*' --exclude='/run/*' --exclude='/mnt/*' --exclude='/media/*' --exclude='/lost+found/' --exclude='/home/dylan/data/*' / /home/dylan/data 

进入安装启动盘

直接用archiso启动,里面包含了我们需要用到的所有工具。

磁盘分区

1
# fdisk /dev/nvme0n1

清除先前的分区,新建两个分区:

1
2
1G的ESP分区
剩余空间全部用作btrfs

原本的目录结构是/efi和/boot是分离的,考虑是不是可以把/boot也作为子卷,因为systemd-boot似乎可以加载驱动 但systemd-boot无法引导esp和boot分离的情况,所以按正常来把esp分区挂载为/boot,原有的内核文件和EFI的内容全部拷贝进去,initramfs重新生成。

加载dm_crypt模块:modprobe dm_crypt

btrfs文件系统需要在加密磁盘之后创建

创建LUKS加密分区

创建加密磁盘:

1
# cryptsetup luksFormat /dev/nvme0n1p2

输入完密码后,检查一下加密分区:

1
# cryptsetup luksDump /dev/nvme0n1p2

密钥写入TPM

systemd-cryptenroll依赖tpm2-tss包来支持TPM密钥写入,Arch中已作为gnupg的依赖包进行了安装。

将密钥绑定到TPM,要用systemd-cryptenroll

先查看当前设备的keyslot:

1
# systemd-cryptenroll /dev/nvme0n1p2
1
2
SLOT TYPE
   0 password

只有密码

查看当前可用的TPM设备:

1
# systemd-cryptenroll --tpm2-device=list
1
2
PATH        DEVICE      DRIVER
/dev/tpmrm0 MSFT0101:00 tpm_crb

将一个随机密钥同时注册到TPM和LUKS卷,并且将这个新的key绑定到PCR7寄存器:

1
# systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs=7 /dev/nvme0n1p2(期间需要输入之前已经配置过的密码)

PCR 常用于在不同引导间检验设备硬件和软件完整性 PCR 7:安全启动状态,包含完整的 PK/KEK/db 内容,以及用于确认每个引导程序的特定证书。

之后再来查看卷的keyslots:

1
2
3
SLOT TYPE
   0 password
   1 tpm2

已添加了tpm2

映射加密卷

测试TPM密钥是否生效:

1
# systemd-cryptsetup attach root /dev/nvme0n1p2 none tpm2-device=auto

可以不用输入密码而自动解密,映射到root设备即为成功。

创建btrfs

创建文件系统之前必须先解密

创建btrfs文件系统:

1
# mkfs.btrfs -L arch_root /dev/mapper/root(root就是解密之后的映射设备)

创建子卷

要创建子卷,必须先挂载该 Btrfs 文件系统以使其要创建的路径可以访问

1
2
3
4
# mount -o subvolid=5 /dev/mapper/root /mnt/
# btrfs subvolume create /mnt/@root
# btrfs subvolume create /mnt/@home
# btrfs subvolume create /mnt/@swap

Btrfs 中子卷名可以是任何有效的目录名,以 @ 符号开头只是timeshift包的命名约定

挂载子卷

先将顶层子卷卸载,用子卷挂载:

1
2
3
# umount /mnt
# mount -o subvol=/@root,compress=zstd /dev/mapper/root /mnt/
# mount --mkdir -o subvol=/@home,compress=zstd /dev/mapper/root /mnt/home

创建启用交换分区:

1
2
3
4
# mount -o subvolid=5 /dev/mapper/root /mnt/
# btrfs filesystem mkswapfile --size 10g --uuid clear /mnt/swap/swapfile
# chattr +C /mnt/swap/swapfile # 已自动设置
# mount --mkdir -o subvol=/@swap /dev/mapper/root /mnt/swap # 挂载回swap

这里为什么又挂载了一次root: 如果先前挂载了swap子卷再去mkswapfile,其自动设置swapfile的+C属性会出现错误:Invalid argument 尚不清楚是否与swap子卷挂载的compress=zstd:3属性有关 但是即便是我指定了mount的属性:compress=no,实际挂载依旧会启用compress,创建也即报错,这应该与compress的作用范围有关 所以按照ArchWiki上的说明,无需挂载子卷直接创建是可行的。

我这里没有其他需要安装的依赖包了,btrfs-progs已经被libguestfs依赖了

恢复文件

恢复文件之前先将挂载点补齐,比如将esp挂载到/mnt/boot

rsync将之前备份的文件恢复回新的目录,命令和备份一样,只是源和目的调换。恢复之后把数据盘再挂载回新目录结构里。

重建fstab

1
# genfstab -U /mnt/ > /mnt/etc/fstab

这里因为之前遗漏了swapon,所以可能没有自动生成swap的条目,后续手动添加。

chroot进新的目录

到这里可以进入新的目录里执行剩余的工作了:

1
# arch-chroot /mnt/

合并原有的efi和boot

由于新系统合并了efi和boot的内容,我们把原来/efi的内容拷贝进新的/boot目录:

1
# rsync -aAXHv /efi/ /boot/

重新创建initramfs

根据ArchWiki,如果我们使用的是systemd-cryptenroll创建的TPM密钥,应该要用基于systemd的initramfs。

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

systemd-cryptsetup-generator来做加密设备的解锁,它将在initramfs过程被执行。

需要在系统里创建/etc/crypttab.initramfs配置,以便指定需要解密的设备,这个文件会拷贝为initramfs里的/etc/crypttabsystemd-cryptsetup-generator通过读取这个文件来决定解密哪些设备,如果没有这个文件,就需要在内核参数里写入解密设备的选项。

1
root	UUID=a80745b4-f21b-4494-a356-5b51bd225b0e	none	tpm2-device=auto

重新生成映像:

1
# mkinitcpio -P

安装引导程序

原本系统使用的GRUB作为引导。

安装systemd-boot

1
# bootctl install

创建启动项:

1
2
3
4
5
title	Arch Linux
linux	/vmlinuz-linux
initrd	/amd-ucode.img
initrd	/initramfs-linux.img
options	root=UUID=0c5b23f7-c204-45d0-9474-aff976fd0e4a rootflags=subvol=/@root rw

这里root必须是解密之后的设备ID,否则无法引导。

不使用crypttab.initramfs的情况

如果前面不创建crypttab.initramfs文件,生成initramfs的时候就不会在里面包含crypttab文件,那systemd-cryptsetup-generator就只能通过rd.luks.*这些内核参数来确定要解密哪些设备。

下面两个参数选其一即可: rd.luks.uuid=<加密设备的UUID> rd.luks.name=<加密设备的UUID>=<解密之后的设备名>

如果用uuid,在没有crypttab文件的情况下,会把解密之后的设备命名为luks-UUID,设备路径在/dev/mapper/luks-UUID

一定注意内核参数还是需要指定root=

参考

https://wiki.archlinuxcn.org/wiki/Dm-crypt/%E8%AE%BE%E5%A4%87%E5%8A%A0%E5%AF%86 https://wiki.archlinuxcn.org/wiki/Dm-crypt/%E7%B3%BB%E7%BB%9F%E9%85%8D%E7%BD%AE https://wiki.archlinuxcn.org/wiki/Btrfs https://man.archlinux.org/man/systemd-cryptsetup-generator.8