Arch Linux安全启动的终极方案

共享分区下Ubuntu引导的Arch Linux系统

Posted by wszqkzqk on April 25, 2023
本文字数:5686

前言

Arch Linux是一个非常优秀的Linux发行版,但是它并不支持安全启动。虽然笔者的笔记本的安全启动长期处于关闭状态,但是笔者还是想把自己的移动硬盘打造成随处可用的移动系统,这就需要支持不依赖于特定设备注册是安全启动。因此,笔者就想到了一个办法,就是在Arch Linux上安装Ubuntu,然后使用Ubuntu的grub引导来引导Arch Linux,并直接使用Ubuntu的内核。这样,Arch Linux就可以支持安全启动了😜😜😜。

此外,割区安装另一个系统总需要预留不少空闲,而如果以后不常使用Ubuntu,往往会造成浪费,而如果分配过小,在以后要用时又不方便扩容,较为麻烦。为了最大化利用空间,也简化安装流程,笔者充分利用了Btrfs的子卷功能,将Arch Linux和Ubuntu安装在同一个Btrfs文件系统的不同子卷下,实现了共享分区容量、简化分区布局的效果。

理想方案

由于我们需要Ubuntu作引导,因此在理想情况下,我们应该安装Ubuntu,然后再在已经安装好Ubuntu的分区中创建新子卷安装Arch Linux。Arch Linux安装的灵活性使得这样不仅能够方便引导及子卷的配置,还可以将Arch Linux的安装直接搬到已经安装好的Ubuntu系统下进行,甚至可以省略Arch Linux镜像的下载步骤😋😋😋。

Ubuntu安装

Ubuntu安装较为简单,只需要注意使用Btrfs格式的分区即可,此处不再赘述。

Arch Linux安装

在已经安装有Ubuntu的分区中创建新子卷,可以放在一个目录下,例如:/subsystems/@arch/subsystems/@arch-home/subsystems/@arch-tmp等,安装Arch Linux,需要注意挂载要按照这里设定的子卷布局:

sudo mount /dev/sdXn -o subvol=subsystems/@arch /mnt
sudo mount /dev/sdXn -o subvol=subsystems/@arch-home /mnt/home
sudo mount /dev/sdXn -o subvol=subsystems/@arch-tmp /mnt/var/tmp
...(挂载其他所需子卷)...

此外,由于我们需要使用Ubuntu的内核,我们需要建立一个新的Btrfs子卷,用于挂载Ubuntu和Arch Linux共享的/usr/lib/modules目录,例如,可以在顶级子卷下创建@moudules子卷,然后将当前Ubuntu的/usr/lib/modules目录下的所有内容移动到@modules子卷下,并在/etc/fstab中添加挂载项:

UUID=0f0f0f0f-0f0f-0f0f-0f0f-0f0f0f0f0f0f /usr/lib/modules btrfs lazytime,subvol=/@modules 0 0

然后正常在/mnt挂载点处执行pacstrapArch Linux的一般安装过程,(同样要记得挂载@moudules子卷)完成Arch Linux的基本安装。这样安装的Arch Linux不必再安装内核,直接使用Ubuntu的内核即可。

引导配置

在Arch Linux安装完成后,我们需要配置Ubuntu的grub引导来引导Arch Linux。我们需要在Ubuntu下编辑/etc/grub.d/40_custom文件,在末尾添加如下内容:

uuid="0f0f0f0f-0f0f-0f0f-0f0f-0f0f0f0f0f0f" # 这里的UUID是Arch Linux所在分区的UUID
resume_uuid="0d0d0d0d-0d0d-0d0d-0d0d-0d0d0d0d0d0d" # 这里的UUID是Arch Linux的swap分区的UUID

# 以Ubuntu的内核引导Arch Linux,支持安全启动
menuentry 'Arch Linux DDE with Ubuntu Kernel (Support Secure Boot)' {
        insmod part_gpt
        insmod btrfs
        search --no-floppy --fs-uuid --set=root ${uuid}
        echo   'Loading Linux kernel...'
        linux  /@/boot/vmlinuz root=UUID=${uuid} rw rootflags=subvol=subsystems/@arch loglevel=3 resume=UUID=${resume_uuid} # 假设Ubuntu的根分区是/@
        echo   'Loading initramfs...'
        initrd /@/boot/initrd.img # 假设Ubuntu的根分区是/@
}

如果还要引导更多以这种方式安装的操作系统,或者也需要在关闭安全启动时使用Arch Linux的内核,可以在/etc/grub.d/40_custom文件中添加更多的引导项。

# 原生的Arch Linux引导,默认不支持安全启动
menuentry "Arch Linux" {
    insmod part_gpt
    insmod btrfs
    search --no-floppy --fs-uuid --set=root ${uuid}
    echo   'Loading Linux kernel...'
    linux /subsystems/@arch/boot/vmlinuz-linux* root=UUID=${uuid} rw rootflags=subvol=subsystems/@arch loglevel=3  resume=UUID=${resume_uuid} # vmlinuz-linux*可以替换为实际内核文件名,这里用通配符`*`匹配
    initrd /subsystems/@arch/boot/initramfs-linux*.img # initramfs-linux*.img可以替换为实际initramfs镜像文件名,这里用通配符`*`匹配
}

然后执行sudo update-grub,重启即可。

先安装Arch Linux再安装Ubuntu

如果在之前已经安装了Arch Linux,后续再安装Ubuntu也可以实现引导,但是由于Ubuntu安装一般不方便自定义子卷,因此需要先改变Btrfs子卷布局。

改变Btrfs子卷布局

在另一个Linux系统或者Linux Live CD中,挂载Arch Linux所在分区,然后在顶级子卷下创建新的subsystems子卷,然后将原来的子卷移动到subsystems子卷下,例如:

sudo mount /dev/sdXn /mnt
sudo btrfs subvolume create /mnt/subsystems
sudo mv /mnt/@ /mnt/subsystems/@arch
sudo mv /mnt/@home /mnt/subsystems/@arch-home
sudo mv /mnt/@tmp /mnt/subsystems/@arch-tmp
...(移动其他所需子卷)...

此外,为了共用内核,我们还需要在顶级子卷下创建@modules子卷,然后将原来的/usr/lib/modules目录下的内容移动到@modules子卷下。

编辑Arch Linux的fstab文件

编辑Arch Linux的fstab文件,将原来的子卷挂载点改为/subsystems/@arch等。由于我们将改用Ubuntu引导,需要删除efi分区在Arch Linux下的挂载项:

UUID=0f0f0f0f-0f0f-0f0f-0f0f-0f0f0f0f0f0f / btrfs lazytime,subvol=/subsystems/@arch 0 0
UUID=0f0f0f0f-0f0f-0f0f-0f0f-0f0f0f0f0f0f /home btrfs lazytime,subvol=/subsystems/@arch-home 0 0
UUID=0f0f0f0f-0f0f-0f0f-0f0f-0f0f0f0f0f0f /var/tmp btrfs lazytime,subvol=/subsystems/@arch-tmp 0 0
UUID=0f0f0f0f-0f0f-0f0f-0f0f-0f0f0f0f0f0f /usr/lib/modules btrfs lazytime,subvol=/@modules 0 0
...(挂载其他所需子卷)...

安装Ubuntu

Ubuntu安装较为简单,此处只需要注意安装时不要格式化原来的分区,而是安装到原有分区的新子卷中。

引导配置

在Ubuntu安装完成后,我们需要配置Ubuntu的grub引导来引导Arch Linux。我们需要在Ubuntu下编辑/etc/grub.d/40_custom文件,添加如下内容:

uuid="0f0f0f0f-0f0f-0f0f-0f0f-0f0f0f0f0f0f" # 这里的UUID是Arch Linux所在分区的UUID
resume_uuid="0d0d0d0d-0d0d-0d0d-0d0d-0d0d0d0d0d0d" # 这里的UUID是Arch Linux的swap分区的UUID

# 以Ubuntu的内核引导Arch Linux,支持安全启动
menuentry 'Arch Linux DDE with Ubuntu Kernel (Support Secure Boot)' {
        insmod part_gpt
        insmod btrfs
        search --no-floppy --fs-uuid --set=root ${uuid}
        echo   'Loading Linux kernel...'
        linux  /@/boot/vmlinuz root=UUID=${uuid} rw rootflags=subvol=subsystems/@arch loglevel=3 resume=UUID=${resume_uuid} # 假设Ubuntu的根分区是/@
        echo   'Loading initramfs...'
        initrd /@/boot/initrd.img # 假设Ubuntu的根分区是/@
}

# 原生的Arch Linux引导,默认不支持安全启动
menuentry "Arch Linux" {
    insmod part_gpt
    insmod btrfs
    search --no-floppy --fs-uuid --set=root ${uuid}
    echo   'Loading Linux kernel...'
    linux /subsystems/@arch/boot/vmlinuz-linux* root=UUID=${uuid} rw rootflags=subvol=subsystems/@arch loglevel=3  resume=UUID=${resume_uuid} # vmlinuz-linux*可以替换为实际内核文件名,这里用通配符`*`匹配
    initrd /subsystems/@arch/boot/initramfs-linux*.img # initramfs-linux*.img可以替换为实际initramfs镜像文件名,这里用通配符`*`匹配
}

然后执行sudo update-grub,重启即可。

后续整理

如果我们不怕折腾想要干净统一的子卷布局,也可以用类似的方法,将Ubuntu的子卷移动到subsystems子卷下。

首先当然是移动Ubuntu子卷,这个过程可以在已经安装好的Arch Linux下进行,也可以在其他Linux系统或者Live CD中进行。

sudo mount /dev/sdXn /mnt
sudo mv /mnt/@ /mnt/subsystems/@ubuntu
sudo mv /mnt/@home /mnt/subsystems/@ubuntu-home
...((移动其他所需子卷)...

然后编辑Ubuntu的fstab文件,将子卷改为新的位置:

UUID=0F0F-0F0F /boot/efi vfat lazytime,umask=0077 0 0 # 这里的efi分区不需要改变
UUID=0f0f0f0f-0f0f-0f0f-0f0f-0f0f0f0f0f0f / btrfs lazytime,subvol=/subsystems/@ubuntu 0 0
UUID=0f0f0f0f-0f0f-0f0f-0f0f-0f0f0f0f0f0f /home btrfs lazytime,subvol=/subsystems/@ubuntu-home 0 0
UUID=0f0f0f0f-0f0f-0f0f-0f0f-0f0f0f0f0f0f /usr/lib/modules btrfs lazytime,subvol=/@modules 0 0
...(挂载其他所需子卷)...

卸载/mnt下的分区,并重新挂载为Ubuntu所在的子卷:

sudo umount /mnt
sudo mount /dev/sdXn -o subvol=/subsystems/@ubuntu /mnt
sudo mount /dev/sdXn -o subvol=/subsystems/@ubuntu-home /mnt/home
sudo mount /dev/sdXn -o subvol=/modules /mnt/usr/lib/modules
...(挂载其他所需子卷)...

然后使用Arch Linux自带的arch-install-scripts工具chroot到Ubuntu子卷中,重新构建Ubuntu的grub引导,如果没有安装arch-install-scripts,可以使用sudo pacman -S arch-install-scripts安装。

sudo arch-chroot /mnt

chroot环境中执行:

/sbin/update-grub

以更新Ubuntu的引导信息,最后重启即可。

风险

这样做可能会遇到部分Arch Linux的内核模块无法加载的情况,最好要/etc/mkinitcpio.conf文件的MODULES=(...)项中添加uinput mousedev,以确保鼠标和键盘的正常使用。