最近為自己的 Arch Linux 配置了安全啟動 (security boot),在此記錄一下流程以及遇到的問題。
實現安全啟動#
關於安全啟動的實現方法,Arch Wiki內有完整的描述,但由於其採用 wiki 方式寫作,對流程描述較為複雜。本節旨在描述實現安全啟動的最簡方法,跳過更加詳細深入的概念性內容。
注:本文僅描述了為 Arch Linux 設置安全啟動,關於進一步的實現與 Windows 安全啟動共存,請自行閱讀 Arch Wiki相應條目。
生成 Key#
安全啟動的實現包括四種 Key:
- Platform Key(PK)
- Key Exchange Key(KEK)
- Signature Database(db)
- Forbidden Signatures Database(dbx)
為了正常使用安全啟動,我們至少需要前三種 Key。為了方便,我們可以使用腳本自動生成:
# 後文自動處理內核更新等操作的 sbupdate 工具默認使用位於/etc/efi-keys的Key。
# 為了方便,這裡直接創建此目錄並在該目錄生成Key
mkdir /etc/efi-keys
cd !$
curl -L -O https://www.rodsbooks.com/efi-bootloaders/mkkeys.sh
chmod +x mkkeys.sh
./mkkeys.sh
<隨意輸入一個嵌入在key中的名字,例如"Secure Boot">
自動簽名#
為了在內核、引導更新時自動簽名,我們可以使用 sbupdate 工具。
安裝#
通過如下命令安裝:
yay -S sbupdate-git
配置#
安裝後,我們需要為其寫入配置,指明需要自動簽名的內容。
打開 /etc/sbupdate.conf,修改配置文件,以下給出我的設置樣例以及選項說明:
# Key所在的目錄
KEY_DIR="/etc/efi-keys"
# EFI引導分區位置
ESP_DIR="/boot"
# 生成的單獨EFI引導文件位置
OUT_DIR="EFI/Linux"
# 生成的單獨EFI引導文件所攜帶的默認內核參數
CMDLINE_DEFAULT="loglevel=3 quiet nomce rw"
# 需要額外簽名的文件,一般包括自己的啟動加載器文件
# 理論上內核是自動簽名的,但不知道為什麼我的vmlinuz-linux-zen不行,因此我也把內核文件寫在了這裡
EXTRA_SIGN=('/boot/EFI/BOOT/BOOTX64.EFI' '/boot/EFI/systemd/systemd-bootx64.efi' '/boot/vmlinuz-linux-zen')
# 內核單獨配置
INITRD["linux-zen"]="/boot/initramfs-linux-zen.img"
# 如果不進行內核參數的配置,默認使用上面的CMDLINE_DEFAULT
CMDLINE["linux-zen"]="root=PARTUUID=db9157b1-bed4-fa44-a715-5c1bfc8bdfb4 quiet nomce loglevel=3 rw"
以下對內核單獨配置做特別說明:
sbupdate 會為每個內核生成一個直接的引導文件(位於 ${ESP_DIR}/${OUT_DIR},文件名為 ${kernel_name}-signed.efi),其中包含了內核參數和臨時文件系統的配置(分別對應配置文件中的 CMDLINE [${kernel_name}] 與 INITRD [${kernel_name}])。
用戶可以使用的引導方法有三種:
- 使用 boot loader(例如 grub/systemd-boot 等)的既有配置進行引導
- 直接使用該文件進行引導
- 使用 boot loader 調用該文件完成間接引導
用戶當前使用的往往是第一種方法。在這種方法沒有問題的情況下,其實是沒有使用這個直接引導文件的必要的。即:
可以忽略上面的 OUT_DIR、CMDLINE_DEFAULT 和內核單獨配置。
簽名#
第一次配置完畢後,需要自己手動執行一下簽名指令:
sudo sbupdate
在將來內核更新時,該工具會自動為其簽名。
對於 systemd-boot 自動簽名的特殊處理#
對於其他引導方法,可能上面配置方法已經足夠,但如果你使用 systemd-boot 作為 boot loader,可能還需要進一步的配置。
hooks 執行順序的處理#
關於這種情況的解釋:
一般情況下,我們只需要在更新內核、systemd 時使用 pacman hook 更新簽名,但在使用 systemd-boot 的情況下,我們同樣需要在更新 systemd 時更新引導(即sudo bootctl update
,該命令會替換 /boot/EFI/BOOT/BOOTX64.EFI 和 /boot/EFI/systemd/systemd-bootx64.efi 到最新版本),因此這時 hooks 的執行順序成為了一個很大的問題 —— 我們需要確保引導的更新先於簽名過程。
想必使用 systemd-boot 的用戶應該了解使用 pacman hook 進行自動更新的方式(參見systemd boot - 自動更新)。在文檔中給出的方法有兩種:
- 安裝 systemd-boot-pacman-hook(本質是下載了 systemd-boot.hook)
- 自己手動在 /etc/pacman.d/hooks/100-systemd-boot.hook 寫入所給內容。
我們可以看到,sbupdate 自帶的用於更新簽名的 hook 名稱為 95-sbupdate.hook,而根據alpm-hooks 文檔所言:
Hooks are run in alphabetical order of their file name, where the ordering ignores the suffix.
鉤子按其文件名的字母順序運行,該順序忽略後綴。
按照該規則,無論是方法 1 得到的 system-boot.hook 還是方法 2 寫入的 100-systemd-boot.hook,都無法滿足先於簽名 hook 執行的需求。我的解決方法是使用方法 2,但將文件名修改為 90-systemd-boot.hook,使其滿足順序需求。
額外簽名 boot loader 的處理#
我們已經解決了第一個障礙,不過不要急,這裡還有一個問題。
我們把需要額外簽名的 boot loader 文件寫在了 sbupdate 的 EXTRA_SIGN 裡,但注意到在 95-sbupdate.hook 中,更新簽名使用的命令是/usr/bin/sbupdate -k
,通過查看 sbupdate 源碼66-72 行、195-205 行可以得知,-k 參數表明 sbupdate 是被 hook 調用的,而為了安全原因,使用 hook 調用 sbupdate 會跳過 EXTRA_SIGN 中的內容,這顯然不是我們期望的。
解決方法也很簡單,打開 /usr/share/libalpm/hooks/95-sbupdate.hook,將 - k 參數去除即可。
寫入 Key 到 Bios#
完成上面的步驟後,已經萬事具備,只欠東風了,最後我們只需要將 Key 寫入到 Bios。
刪除既有 Key#
Bios 默認會自帶微軟 Key,為了寫入我們自己的 Key,需要將原有的 Key 刪除。
在這一步驟中,需要進入 Bios,找到安全啟動的證書管理選項,在裡面選擇刪除即可。
寫入新的 Key#
利用sbsigntools
簡化 Key 的寫入過程。
首先我們需要一個這樣的目錄:
/etc/secureboot/keys
├── db
├── dbx
├── KEK
└── PK
執行如下命令進行創建:
mkdir -p /etc/secureboot/keys/{db,dbx,KEK,PK}
接著將之前位於/etc/efi-keys
的*.auth
文件拷貝到對應的目錄(沒有 dbx 是正常的)。
最後需要執行如下命令:
sbkeysync --verbose
sbkeysync --verbose --pk
如果有幸沒有報錯,恭喜你,已經完成了 Arch Linux 的安全啟動配置,這就到 Bios 中開啟安全啟動選項並啟動吧!
結語#
在本文中,我羅列了自己為本機配置安全啟動做的所有操作。儘管如此,我並不能保證讀者們能夠復現我的成功步驟。
如果你在執行文章中的某些步驟時出現差錯,推薦閱讀 Arch Wiki 的原文。原文中包括了同一步驟的多種實現方式,且給出了詳細的錯誤處理,比該文更具有代表性。