MorFans Dev
折腾 - 开发 - 分享

创建支持安全启动(Secure Boot)的 Arch Linux ISO 安装镜像

创建支持安全启动(Secure Boot)的 Arch Linux ISO 安装镜像

前言

由于最近需要用到 Linux 相关的东西,用微软的 WSL2 配上容器总是内存爆满,所以打算安装一个 ArchLinux 到我的电脑中。

但是 ArchLinux iso 大概在 13 年的样子移除了对 安全启动 UEFI Secure Boot 的支持。但我又及其懒惰不愿修改主板配置关闭安全启动。

所以想安装 ArchLinux,还给先对安装媒介下手。

之前我安装的方案是先刻录U盘,然后在U盘中修改EFI分区来添加 Preloader-signed

这样的缺点有很多:

  • 需要一个没开启安全启动的机器或虚拟机
  • 需要新建普通用户,或使用 nobody 来安装 AUR源
  • 可能需要扩容
  • 每次刻录后都需要进行操作

这次趁着要给电脑重装系统的机会,来直接生成一个支持安全启动的 ArchLinux 安装镜像吧。

Archiso

官方有一个用于生成镜像的脚本,可以给我们省下很多时间

本次就使用微软的 WSL2 (archwsl)来制作一个安全启动的 ArchLinux 安装镜像

安装 archiso

安装命令很简单,用 pacmanyay 安装即可:

yay -S archiso

DIY archiso

官方的 Archiso 脚本生成是根据 profile来的,可以基于以下两个来自定义:

  • /usr/share/archiso/configs/releng
  • /usr/share/archiso/configs/baseline

要实现的东西

  • 支持安全启动(preload-signed)
  • 添加 ArchLinuxCN 源(方便装 yaypreload-signed)

自定义 Profile

releng 就是 Arch Linux 每月生成镜像用的,自己DIY就直接基于这个来魔改就好了。

baseline 是极简化的配置,极简就意味着工作量会大,我还没发烧就不用这个

直接复制 releng 来修改:

paxos@Paxos-C26-2021 ~> cp -r /usr/share/archiso/configs/releng/ arch_iso

首先先修改 pacman.conf,加上 archlinuxcn 的地址就行了

[archlinuxcn]
Server = https://mirrors.163.com/archlinux-cn/$arch
Server = https://mirrors.ustc.edu.cn/archlinuxcn/$arch
Server = https://mirrors.tuna.tsinghua.edu.cn/archlinuxcn/$arch

然后添加软件包:

在首行添加 archlinuxcn-keyring 用于导入 archlinuxcn 密钥链。

然后安装位于 aur 的 yay-gitpreloader-signed

paxos@Paxos-C26-2021 ~/arch_iso [1]> diff -u /usr/share/archiso/configs/releng/packages.x86_64 packages.x86_64
--- /usr/share/archiso/configs/releng/packages.x86_64   2021-08-25 21:00:25.000000000 +0800
+++ packages.x86_64     2021-09-06 15:48:43.651396539 +0800
@@ -1,3 +1,4 @@
+archlinuxcn-keyring
 alsa-utils
 amd-ucode
 arch-install-scripts
@@ -116,3 +117,5 @@
 xfsprogs
 xl2tpd
 zsh
+yay-git
+preloader-signed
\ No newline at end of file

接着我们要修改 arch 安装镜像默认的引导程序为 systemd,不知道什么原因,官方在 2022 年六月份把引导改成 grub。grub 不太方便与 preloader 一起使用。所以我们改回来 🙁

修改 releng 中的 profiledef.sh 文件:

...
buildmodes=('iso')
bootmodes=('bios.syslinux.mbr' 'bios.syslinux.eltorito'
           'uefi-x64.systemd-boot.esp' 'uefi-x64.systemd-boot.eltorito')
arch="x86_64"
...

修改 archiso 脚本

我原以为官方的脚本里支持更换 bootloader 或支持在某编译环境时运行DIY脚本,结果都没有。只能通过修改 archiso脚本来修改 bootloader 了

为了脚本的通用,修改脚本的思路如下,非常简单:

  • 先从 packages 里看看有没有 preloader
  • 没有就正常处理 bootloader,有就加入

先找到脚本位置:

paxos@Paxos-C26-2021 ~/arch_iso> whereis mkarchiso | awk 'END {print $2}'
/usr/bin/mkarchiso
paxos@Paxos-C26-2021 ~/arch_iso> whereis mkarchiso | cut -d ' ' -f2
/usr/bin/mkarchiso

然后修改的部分如下:

为了方便查看修改的地方,只放了修改的部分的代码

PS:如何获得修改后的脚本

复制下面代码,保存为 文件1,然后在终端下执行 sudo patch -b /usr/bin/mkarchiso 文件1 即可修改 archiso脚本。不需要手动一行行修改。

源文件参考:

--- mkarchiso	2022-08-19 16:44:40.946964396 +0800
+++ mkarchiso.sh	2022-08-19 20:11:03.107466569 +0800
@@ -40,6 +40,8 @@
 sign_netboot_artifacts=""
 declare -A file_permissions=()
 efiboot_files=()
+# Preloader
+preload_signed=false
 # adapted from GRUB_EARLY_INITRD_LINUX_STOCK in https://git.savannah.gnu.org/cgit/grub.git/tree/util/grub-mkconfig.in
 readonly ucodes=('intel-uc.img' 'intel-ucode.img' 'amd-uc.img' 'amd-ucode.img' 'early_ucode.cpio' 'microcode.cpio')
 
@@ -644,15 +646,34 @@
     efiboot_files+=("${work_dir}/BOOTx64.EFI"
                     "${pacstrap_dir}/usr/share/edk2-shell/x64/Shell_Full.efi")
 
+    # Preloader-signed
+    if $preload_signed; then
+        efiboot_files+=("${pacstrap_dir}/usr/share/preloader-signed/HashTool.efi")
+        efiboot_files+=("${pacstrap_dir}/usr/share/preloader-signed/PreLoader.efi")
+    fi
+
     efiboot_imgsize="$(du -bc "${efiboot_files[@]}" \
         2>/dev/null | awk 'END { print $1 }')"
 
     # Create a FAT image for the EFI system partition
     _make_efibootimg "$efiboot_imgsize"
 
-    # Copy grub EFI binary to the default/fallback boot path
-    mcopy -i "${work_dir}/efiboot.img" \
-        "${work_dir}/BOOTx64.EFI" ::/EFI/BOOT/BOOTx64.EFI
+    # Copy Preloader binary to the boot path
+    if $preload_signed;then
+        _msg_info "Setting up Preloader for GRUB UEFI booting..."
+        mcopy -i "${work_dir}/efiboot.img" \
+            "${pacstrap_dir}/usr/share/preloader-signed/PreLoader.efi" ::/EFI/BOOT/BOOTx64.EFI
+        mcopy -i "${work_dir}/efiboot.img" \
+            "${pacstrap_dir}/usr/share/preloader-signed/HashTool.efi" ::/EFI/BOOT/HashTool.efi
+        mcopy -i "${work_dir}/efiboot.img" \
+            "${work_dir}/BOOTx64.EFI" ::/EFI/BOOT/loader.efi
+    else
+        _msg_info "No Preloader for UEFI booting..."
+        _msg_info "Copy GRUB EFI binary to the default/fallback boot path"
+        ## Copy grub EFI binary to the default/fallback boot path
+        mcopy -i "${work_dir}/efiboot.img" \
+            "${work_dir}/BOOTx64.EFI" ::/EFI/BOOT/BOOTx64.EFI
+    fi
 
     _run_once _make_efibootimg_grubcfg
 
@@ -676,9 +697,22 @@
     _msg_info "Preparing an /EFI directory for the ISO 9660 file system..."
     install -d -m 0755 -- "${isofs_dir}/EFI/BOOT"
 
-    # Copy GRUB EFI binary to the default/fallback boot path
-    install -m 0644 -- "${work_dir}/BOOTx64.EFI" \
-        "${isofs_dir}/EFI/BOOT/BOOTx64.EFI"
+    # Copy Preloader binary to the boot path
+    if $preload_signed;then
+        _msg_info "Setting up Preloader for GRUB UEFI booting (ISO 9660 file system)..."
+        install -m 0644 -- "${pacstrap_dir}/usr/share/preloader-signed/PreLoader.efi" \
+            "${isofs_dir}/EFI/BOOT/BOOTx64.EFI"
+        install -m 0644 -- "${pacstrap_dir}/usr/share/preloader-signed/HashTool.efi" \
+            "${isofs_dir}/EFI/BOOT/HashTool.efi"
+        install -m 0644 -- "${work_dir}/BOOTx64.EFI" \
+            "${isofs_dir}/EFI/BOOT/loader.efi"
+    else
+        _msg_info "No Preloader for UEFI booting (ISO 9660 file system)..."
+        _msg_info "Copy GRUB EFI binary to the default/fallback boot path"
+        # Copy GRUB EFI binary to the default/fallback boot path
+        install -m 0644 -- "${work_dir}/BOOTx64.EFI" \
+            "${isofs_dir}/EFI/BOOT/BOOTx64.EFI"
+    fi
 
     # Copy GRUB configuration files
     install -m 0644 -- "${work_dir}/grub.cfg" "${isofs_dir}/EFI/BOOT"
@@ -702,21 +736,44 @@
             _available_ucodes+=("${pacstrap_dir}/boot/${_file}")
         fi
     done
+
+    # Preloader-signed
+    preload_signed_files=()
+    if $preload_signed; then
+        _msg_info "Loading Preloader files..."
+        preload_signed_files+=("${pacstrap_dir}/usr/share/preloader-signed/HashTool.efi")
+        preload_signed_files+=("${pacstrap_dir}/usr/share/preloader-signed/PreLoader.efi")
+    fi
+
     # Calculate the required FAT image size in bytes
     efiboot_files+=("${pacstrap_dir}/usr/lib/systemd/boot/efi/systemd-bootx64.efi"
                     "${pacstrap_dir}/usr/share/edk2-shell/x64/Shell_Full.efi"
                     "${profile}/efiboot/"
                     "${pacstrap_dir}/boot/vmlinuz-"*
                     "${pacstrap_dir}/boot/initramfs-"*".img"
+                    "${preload_signed_files[@]}" \
                     "${_available_ucodes[@]}")
     efiboot_imgsize="$(du -bc "${efiboot_files[@]}" \
         2>/dev/null | awk 'END { print $1 }')"
     # Create a FAT image for the EFI system partition
     _make_efibootimg "$efiboot_imgsize"
 
-    # Copy systemd-boot EFI binary to the default/fallback boot path
-    mcopy -i "${work_dir}/efiboot.img" \
-        "${pacstrap_dir}/usr/lib/systemd/boot/efi/systemd-bootx64.efi" ::/EFI/BOOT/BOOTx64.EFI
+    # Copy Preloader binary to the boot path
+    if $preload_signed;then
+        _msg_info "Setting up Preloader for UEFI booting..."
+        mcopy -i "${work_dir}/efiboot.img" \
+            "${pacstrap_dir}/usr/share/preloader-signed/PreLoader.efi" ::/EFI/BOOT/BOOTx64.EFI
+        mcopy -i "${work_dir}/efiboot.img" \
+            "${pacstrap_dir}/usr/share/preloader-signed/HashTool.efi" ::/EFI/BOOT/HashTool.efi
+        mcopy -i "${work_dir}/efiboot.img" \
+            "${pacstrap_dir}/usr/lib/systemd/boot/efi/systemd-bootx64.efi" ::/EFI/BOOT/loader.efi
+    else
+        _msg_info "No Preloader for UEFI booting..."
+        _msg_info "Copy systemd-boot EFI binary to the default/fallback boot path"
+        # Copy systemd-boot EFI binary to the default/fallback boot path
+        mcopy -i "${work_dir}/efiboot.img" \
+            "${pacstrap_dir}/usr/lib/systemd/boot/efi/systemd-bootx64.efi" ::/EFI/BOOT/BOOTx64.EFI
+    fi
 
     # Copy systemd-boot configuration files
     mmd -i "${work_dir}/efiboot.img" ::/loader ::/loader/entries
@@ -753,9 +810,21 @@
     _msg_info "Preparing an /EFI directory for the ISO 9660 file system..."
     install -d -m 0755 -- "${isofs_dir}/EFI/BOOT"
 
-    # Copy systemd-boot EFI binary to the default/fallback boot path
-    install -m 0644 -- "${pacstrap_dir}/usr/lib/systemd/boot/efi/systemd-bootx64.efi" \
-        "${isofs_dir}/EFI/BOOT/BOOTx64.EFI"
+    if $preload_signed;then
+        _msg_info "Setting up Preloader for the ISO 9660 file system..."
+        install -m 0644 -- "${pacstrap_dir}/usr/share/preloader-signed/PreLoader.efi" \
+            "${isofs_dir}/EFI/BOOT/BOOTx64.EFI"
+        install -m 0644 -- "${pacstrap_dir}/usr/share/preloader-signed/HashTool.efi" \
+            "${isofs_dir}/EFI/BOOT/HashTool.efi"
+        install -m 0644 -- "${pacstrap_dir}/usr/lib/systemd/boot/efi/systemd-bootx64.efi" \
+            "${isofs_dir}/EFI/BOOT/loader.efi"
+    else
+        _msg_info "No Preloader for UEFI booting..."
+        _msg_info "Copy systemd-boot EFI binary to the default/fallback boot path"
+        # Copy systemd-boot EFI binary to the default/fallback boot path
+        install -m 0644 -- "${pacstrap_dir}/usr/lib/systemd/boot/efi/systemd-bootx64.efi" \
+            "${isofs_dir}/EFI/BOOT/BOOTx64.EFI"
+    fi
 
     # Copy systemd-boot configuration files
     install -d -m 0755 -- "${isofs_dir}/loader/entries"
@@ -1515,6 +1584,9 @@
     # Set variables that do not have overrides
     [[ -n "$airootfs_image_type" ]] || airootfs_image_type="squashfs"
     [[ -n "$iso_name" ]] || iso_name="${app_name}"
+
+    _msg_info "check preloader-signed Package..."
+    [[ `grep -c 'preloader-signed' $packages` != '0' ]] && preload_signed=true || preload_signed=false
 }
 
 _export_gpg_publickey() {

生成 Arch Linux 安装镜像

修改完生成镜像的脚本和配置,就可以生成我们的镜像了

命令解释:

  • -v verbose 模式
  • -w 指定工作目录,可以指定到 tmpfs,这样可能会快点
  • -o 输出目录,这里随便,不写也行
  • 最后接上 profile 目录,就是之前我们添加软件包修改的那个
paxos@Paxos-C26-2021 ~> sudo mkarchiso -v -w /tmp/arch-iso-tmp2 -o /home/paxos/iso /home/paxos/arch_iso
编译Arch Linux 安装镜像
编译Arch Linux 安装镜像

测试Arch Linux 安全启动 (Secure Boot

刻录U盘,启动就行了

测试 Arch Linux 安全启动
测试 Arch Linux 安全启动
赞赏
魔帆博客,版权所有 | 如未注明,均为原创
本站均采用 BY-NC-ND 协议 (署名-非商业性使用-禁止演绎) 进行授权。
转载请注明来自本站文章:创建支持安全启动(Secure Boot)的 Arch Linux ISO 安装镜像(https://www.morfans.cn/archives/3002)

野小新

文章作者

野小新很野~

发表回复

textsms
account_circle
email

  • DJW

    我查看了相关的官方Wiki,preloader可能对Windows更新产生影响,所以我想采用shim方案,但尝试shim的时候发现一些自相矛盾的地方(仅对我的情况),grub相关模组签名也没弄好,现在开机连grub都没了,要不是win11不开安全启动无法更新都不想折腾了,想放弃Windows了

    1年前 回复
    • 野小新

      @DJW: 你是 Windows 和 Linux 共用一个 EFI 分区吗?我不是很建议这样使用的喔,windows 更新有时候会覆盖掉 EFI 分区的一些内容,会影响到 Linux 的 boot。
      而分开 EFI 分区使用 PreLoader 是没有任何事情的,我两台设备上都是这样配置的双系统,目前还没遇到过问题。

      1年前 回复
  • DJW

    这样安装之后的系统支持安全启动吗

    1年前 回复
    • 野小新

      @DJW: 本文只是生成一个支持在启用了安全启动的电脑上能直接运行的 ArchLinux 的安装镜像。不是安装系统哟~

      如果你想让安装后的系统支持安全启动,需要在安装系统时候对 boot 这部分进行一些操作,比如用上本文中所用的 preloader。

      1年前 回复
  • 求助者1号

    现在archiso更新了,patch命令执行后生成的文件执行报错,能否更新一下呢,谢谢大佬

    2年前 回复
  • Peakstep

    那么基于archlinux的发行版也可以这样魔改吗(

    2年前 回复
    • 野小新

      @Peakstep: 可以,不过你已经安装了系统,想要支持安全启动就只要处理 efi 就好了,用的东西也是 AUR 的 preloader-signed,参考文章中那个diff脚本文件的代码 和 archwiki,有不懂的欢迎评论 🙂

      2年前 回复
  • Hello World

    3年前 回复

创建支持安全启动(Secure Boot)的 Arch Linux ISO 安装镜像
前言 由于最近需要用到 Linux 相关的东西,用微软的 WSL2 配上容器总是内存爆满,所以打算安装一个 ArchLinux 到我的电脑中。 但是 ArchLinux iso 大概在 13 年的样子移除了对 安全…
扫描二维码继续阅读
2021-09-06