LINUX.ORG.RU

Systemd-Ukify: Миграция системы на Secure Boot

 , , , ,


1

1

Secure Boot на линуксе нужен для того, чтобы Windows в дуалбуте была в безопасности, и проходила все тесты на безопасность в Защитнике Windows.
Руководство ориентировано на дистрибутивы из семейства Arch Linux.

ПРЕДИСЛОВИЕ

Описанный ниже метод пока что не поддерживает новые видеокарты Nvidia с GSP Firmware. Если у вас видеокарта 20х серии и выше, или вы используете GSP — этот метод не для вас. Об этой проблеме надо писать автору скрипта Dracut-Ukify.

Для поддержки Early KMS я запаковываю ядро как fallback, в конфиге ниже. В это ядро включены почти все Firmware и драйверы.

UKI-ядра в EFI/Linux подхватываются сами без конфигурации загрузчика.

В процессе выполнения данного гайда перезагружаться нельзя, иначе система превратится в тыкву!

ПРЕЖДЕ ЧЕМ ЧТО-ТО ДЕЛАТЬ, УБЕДИТЕСЬ В ТОМ, ЧТО ВЫ ВСЁ ПОНИМАЕТЕ!!! ВЫ ДЕЛАЕТЕ ЭТО НА СВОЙ СТРАХ И РИСК!

Убедитесь, что у вас на EFI разделе достаточно пространства. ЯДРА ВЕСЯТ ПО 100 МЕГАБАЙТ!!!

https://www.youtube.com/watch?v=8XtTpx_2sKU


УСТАНОВКА НЕОБХОДИМЫХ ПАКЕТОВ И ПОДГОТОВКА

Необходимо поставить скрипт dracut-ukify (из AUR) и утилиты sbctl и sbsigntools. Они нужны для генерации унифицированных образов ядра, генерации ключей и сертификатов, и цифровой подписи.

paru -S dracut sbctl sbsigntools dracut-ukify

Далее нужно открыть /proc/cmdline и скопировать оттуда строку (БЕЗ УКАЗАНИЯ INITRD) в /etc/kernel/cmdline.
Вот пример:

$ cat /proc/cmdline 
                                                                                                                                             
root=UUID=49a19494-cce7-463c-962f-881b70a35560 rw nowatchdog nohpet intel_pstate=passive split_lock_detect=off nvme_load=YES zswap.enabled=1 loglevel=3 lsm=landlock,lockdown,yama,integrity,apparmor,bpf spec_rstack_overflow=microcode


ПОДГОТОВКА BIOS, ГЕНЕРАЦИЯ КЛЮЧЕЙ, ENROLL

Для того, чтобы включить дуалбут для Windows и Linux, необходимо в BIOS закатать собственные ключи ВМЕСТЕ с ключами Майкрософта.

Чтобы в BIOS закатать ключи, нужно Secure Boot перевести в Setup Mode. Для этого сделайте следующее: Откройте в биосе настройки секъюр бута, и переведите его в режим Custom. Затем, выберите опцию Key Management. В появившемся меню отключите опцию Factory Key Provisioning и нажмите кнопку Remove SecureBoot Variables.

Теперь загрузитесь в систему и сделайте:

# Генерацию ключей проведите лишь однажды!
# Их нельзя затирать!
sudo sbctl create-keys 

# Закатываем собственные ключи ВМЕСТЕ С ключами Майкрософт! Нужно для дуалбута с Виндовс!
sudo sbctl enroll-keys --microsoft


ПОДГОТОВКА EFI-РАЗДЕЛА

sudo pacman -Rc grub mkinitcpio
sudo rm -r /boot/efi /boot/grub /boot/initramfs* /boot/vmlinuz*

sudo mkdir /efi
efidevice=$(findmnt /boot/efi -no SOURCE) # запоминаем EFI-раздел
sudo umount /boot/efi
sudo mount ${efidevice} /efi

В fstab необходимо теперь /boot/efi заменить на /efi !


УСТАНОВКА ЗАГРУЗЧИКА

Установка Systemd-Boot

sudo bootctl install
sudo sbctl sign -s /efi/EFI/BOOT/bootx64.efi
/efi/loader/loader.conf (конфиг загрузчика Systemd-Boot)
default  @saved
timeout  8
console-mode max
editor   no

ИЛИ, Установка rEFInd

paru -S refind
sudo refind-install --usedefault $(findmnt /efi -no SOURCE)
sudo sbctl sign -s /efi/EFI/BOOT/bootx64.efi
sudo sbctl sign -s /efi/EFI/BOOT/drivers_x64/ext4_x64.efi


НАСТРОЙКА DRACUT-UKIFY И ПЕРЕУСТАНОВКА ЯДЕР

/etc/dracut-ukify.conf

# Configuration file for dracut-ukify package

# Should dracut-ukify colorize its output?
# Can be auto, true or false
colorize=auto

# Kernel package to be set as default in systemd-boot
# eg. setting this to 'linux' is equivalent of calling
# 'bootctl set-default ENTRY_ID_FOR_LINUX' after each upgrade of corresponding package
#default_kernel_package='linux'

# Add global ukify flags to each invocation
# See '/usr/lib/systemd/ukify --help' for an available flags
# 1. Specify cmdline

# ССЫЛКА НА КОМАНДНУЮ СТРОКУ ЯДРА В СИСТЕМЕ
ukify_global_args+=(--cmdline "@/etc/kernel/cmdline")
# 2. Sign UKI image for use with UEFI Secure Boot
#    Note you don't need --sign-kernel here, it will do not what you expect probably

# ПУТИ К КЛЮЧАМ, МЕНЯТЬ НЕ НУЖНО
ukify_global_args+=(--secureboot-private-key /usr/share/secureboot/keys/db/db.key --secureboot-certificate /usr/share/secureboot/keys/db/db.pem)
# 3. Add splash image (only BMP supported!)
#ukify_global_args+=(--splash /etc/boot/splash.bmp)

# Build variants can be declared here
# ukify_variants is are associative array where the key is variant name and value is dracut options to pass during generation
# Note the "default" key is special - it will be omitted in the resulting image name
# It can be used to create fallback images, for example:
#ukify_variants=(
#  [default]="--hostonly"
#  [fallback]="--no-hostonly"
#)

# ВКЛЮЧИТЬ ВСЕ ДРАЙВЕРЫ И FIRMWARE
ukify_variants=(
  [default]="--no-hostonly"
)

# Override UKI image path for each variant
# Available variables:
# ${name} - package name (linux, linux-lts, linux-zen, etc)
# ${version} - package version
# ${machine_id} - machine id (taken from /etc/machine-id)
# ${build_id} - build id (taken from /etc/os-release, for ArchLinux it's always 'rolling')
# ${id} - os id (taken from /etc/os-release, for ArchLinux it's always 'arch')
# Note: that's not real shell variable expansion, it's just string substitution, so the parentheses are required
# Note 2: unless you're using only one kernel package, you must provide unique paths for each package,
#         so either ${name} or ${version} is strongly recommended to use here
#ukify_install_path=(
#  [default]='EFI/Linux/linux-${version}-${machine_id}-${build_id}.efi'
#  [fallback]='EFI/Linux/linux-${version}-${machine_id}-${build_id}-fallback.efi'
#)

# ПОСТОЯННОЕ ИМЯ ЯДРА ИЗ ИМЕНИ ПАКЕТА
ukify_install_path=(
  [default]='EFI/Linux/${name}.efi'
)

После завершения конфигурации переустановим все ядра

sudo rm /efi/EFI/Linux/*
sudo dracut-ukify -a


PACMAN HOOKS

Если у вас rEFInd:
/etc/pacman.d/hooks/10-refind-signed.hook

[Trigger]
Operation=Upgrade
Type=Package
Target=refind

[Action]
Description = Updating rEFInd on ESP
When=PostTransaction
Exec=/bin/bash -c "refind-install --usedefault $(findmnt /efi -no SOURCE) && sbctl sign -s /efi/EFI/BOOT/bootx64.efi && sbctl sign -s /efi/EFI/BOOT/drivers_x64/ext4_x64.efi"


Если у вас Systemd-Boot:
/etc/pacman.d/hooks/10-sdboot-signed.hook
[Trigger]
Operation=Upgrade
Type=Package
Target=systemd

[Action]
Description = Updating Systemd-Boot on ESP
When=PostTransaction
Exec=/bin/bash -c "bootctl install && sbctl sign -s /efi/EFI/BOOT/bootx64.efi"


WINDOWS

Чтобы Systemd-Boot мог грузить Windows, нужно примонтировать в /mnt виндовый EFI-раздел, и скопировать содержимое его папки EFI в папку EFI ... На EFI-разделе Linux

REFInd же подхватывает все пункты загрузки автоматически.



Проверено: hobbit ()
Последнее исправление: hobbit (всего исправлений: 36)

@hobbit Спаси! У меня кончились буквы :-(

Если серьёзно, то я не могу разбавить текст речевыми оборотами и описанием процедур. Я могу только сухо излагать факты.

Set440
() автор топика
Ответ на: комментарий от Set440

Я почитаю, но сегодня не обещаю, я редактированием своей собственной статьи (не для ЛОРа и вообще не для интернета) уже мозг залил. :\

hobbit ★★★★★
()
Ответ на: комментарий от hobbit

А, хорошо, наверное. (Что мозги запарил – плохо, а вот за внимание – спасибо :) )

Если что-то заметишь, то правь смело.

Set440
() автор топика
Ответ на: комментарий от hobbit

Я вообще-то не требовал «здесь и сейчас». Я просто подумал, может ты в течении трёх недель поможешь как-то.

В статье куча сухих фактов и не хватает человеческого описания, но меня замкнуло, и сам я пока это сделать не могу…

Set440
() автор топика
Ответ на: комментарий от MEZON

Виларибо & Вилабаджо, Кипячение или СМЕРТЬ

Set440
() автор топика

Зачем /boot/efi менять на /efi? У меня примерно так же все настроено (только с booster), но я не менял директории.

Athor ★★
()
Ответ на: комментарий от hobbit

Граб вроде бы не умеет работать с UKI и подхватывать их из папки EFI/Linux

Set440
() автор топика
Ответ на: комментарий от Psilocybe

Вот, кстати, да. Неплохо бы начать с того, что мы имеем, что хотим получить, и что это нам даст.

Заодно это и меня промотивирует на редактирование и подтверждение. Разбавить текст речевыми оборотами не диво, диво понять, к чему всё это.

hobbit ★★★★★
()
Последнее исправление: hobbit (всего исправлений: 1)
Ответ на: комментарий от Werenter

Теги поправил. Хотел ещё вставить тег systemd (ибо в статье в качестве рабочих вариантов предлагаются rEFInd ЛИБО systemd-boot), но ограничение на 5 тегов, увы, что-то из оставшегося выкидывать уже жалко.

hobbit ★★★★★
()
Ответ на: комментарий от hobbit

NB: Секъюрбут на линуксе нужен для того, чтобы Windows в дуалбуте была в безопасности, и проходила все тесты на безопасность в Защитнике Windows.

Записал

Set440
() автор топика
Ответ на: комментарий от Set440

Неправильно понял. Секьюрбут вообще не нужен, нигде, ни на винде, ни на линуксе.

Werenter ★★★
()
Ответ на: комментарий от Werenter

С тоской за себя, что руки никак не дойдут. Может, сегодня или завтра вечером. Подтвердить-то дело недолгое, но автор просил чуток язык разбавить…

hobbit ★★★★★
()
Ответ на: комментарий от Set440

Ещё раз перечитав, я внезапно подумал, что как раз разбавление речевыми оборотами в данном тексте не обязательно, их вполне хватает. Вот как раз сухих фактов кому-то может не хватить. :) Поэтому подтвердил, только порихтовал орфографию с пунктуацией и преамбулу выделил. Приношу извинения за долгое ожидание.

hobbit ★★★★★
()

Смысл ставить отдельный загрузчик, когда пользуешься UKI? Да и способ с хуками пакмана не совсем корректный - в рач уже некоторое время как завезли более правильные хуки в /etc/initcpio, работающие конкретно на этапе вызова mkinitcpio.

TL;DR по (на данный момент + ИМХО) пацанскому способу настройки сесурбута:

  • прописал commandline ядра в /etc/kernel/cmdline
  • прописал в настройках профиля mkinitcpio генерацию UKI вместо обычного initrd, например:
# mkinitcpio preset file for the 'linux-cachyos-lto' package

ALL_config=(/etc/mkinitcpio.conf)
ALL_kver=(/boot/vmlinuz-linux-cachyos-lto)

PRESETS=('default')

default_uki=(/efi/EFI/Linux/linux.efi)

  • создал загрузочный пункт через efibootmgr: efibootmgr --create --disk /dev/nvme0n1 --part 1 --label "Arch Linux" --loader 'EFI\Linux\linux.efi' --verbose
  • нагенерил самоподписанные ключи через sbkeys где-нибудь в /etc/secureboot с правильным chmod+chown, при желании сделал с мелкософтовским барахлом через флаг -m
  • добавил ключи в фирмварь через условный sbkeysync --keystore /etc/secureboot --pk (на этом этапе может возникнуть прикол с ридонли-переменными EFI, лечение расписано в арчвики)
  • прописал в /etc/initcpio/post/secureboot что-то типа
#!/bin/sh -Eeu

sbsign --key /etc/secureboot/DB.key --cert /etc/secureboot/DB.crt --output "${3}" "${3}" > /dev/null 2>&1 || exit 1
  • запустил mkinitcpio -P и обрадовался подписанному UKI

Пердоллинг с точками монтирования ESP тут опущен. ЕМНИП /boot/efi перевели на /efi просто как правило хорошего тона (или обновились стандарты файловой иерархии в Linux? не помню, да и мне как-то индифферентно вспомнил: это сделано для того, чтобы образы ядра хранить в корневом /boot, а финальное EFI-барахло складировать в ESP в отдельном каталоге /efi на, соответственно, другой ФС; сделано для того, чтобы не захламлять ESP дублирующимися данными: раньше туда клалось и ядро, и UKI (это ядро содержащее), а теперь там остался только UKI).

В качестве загрузчика спокойно используется встроенное загрузочное меню (U)EFI, где в случае дуалбута продолжает спокойно висеть ещё и Windows Boot Manager; в случае же правильной (tm) конфигурации будет один лишь пункт под пингвин.

Использовал и использовал такую штуку с полнодисковым LUKS2 как с, так и без TPM - полёт нормальный. Печально, что на той же арчвики статья написана крайне сумбурно, когда по факту всё достаточно просто.

mradermaxlol
()
Последнее исправление: mradermaxlol (всего исправлений: 4)
Ответ на: комментарий от mradermaxlol

нагенерил самоподписанные ключи через sbkeys где-нибудь в /etc/secureboot с правильным chmod+chown, при желании сделал с мелкософтовским барахлом через флаг -m

Таки есть sbctl который и ключи сгенерит, и поставит их, и хуки на подпись новых файлов добавит.

MagicMirror
()
Ответ на: комментарий от MagicMirror

По сути да, но на правах ИМХО считаю, что ручной способ даёт (немного) больше гибкости и, пожалуй, какое-никакое понимание процесса. Автоматизация и упрощение - круто, но ещё круче, если ты хотя бы разок прошёл путь самостоятельно.

Ну и всё же хуки прописать бы руками. Хуки пакетного менеджера как бы не сильно в курсе контекста генерации initrd, да и их порядок висит на честном слове - сегодня тебе достаточно префика 10- в названии файла, а завтра после очередного сеанса пердоллинга будь добр телепатией допереть до того, что префикс нужен побольше. Так что man /etc/initcpio остаётся в силе, не надо тут тыкать палкой пакман :)

К слову, из ридми sbctl:

Note: It is generally recommended to use the initramfs generator for this. mkinitcpio and dracut support this through their respective –uki and –uefi flags, or the ukify tool from systemd.

This feature is considered a second class citizen in sbctl.

КМК при использовании UKI лучше пока что руками интегрировать вместе более простые велосипеды, чем натягивать одну комбайносову на глобус целиком.

mradermaxlol
()
Ответ на: комментарий от mradermaxlol

Note: It is generally recommended to use the initramfs generator for this. mkinitcpio and dracut support this through their respective –uki and –uefi flags, or the ukify tool from systemd. This feature is considered a second class citizen in sbctl.

Так .efi генерирует mkinitcpio/dracut, sbctl только подписывает готовые файлы.

Я раньше тоже руками писал скрипты и хуки, но это в итоге оказалось гиблое дело с большой чередой не очевидных ошибок.

MagicMirror
()
Ответ на: комментарий от kixx09

sbctl сам умеет делать .efi

Умеет, но ему это делать не за чем.

MagicMirror
()

Secure Boot на линуксе нужен для того, чтобы Windows в дуалбуте была в безопасности, и проходила все тесты на безопасность в Защитнике Windows.

Вообще Secure boot нужен не для этого. Он Нужен для обеспесения безопасности на физическом уровне для предовращения доступа к данным на дисках. Это нужно на ноутах.

vpnvpnvpn
()
Ответ на: комментарий от mradermaxlol

Возвращаясь к старой теме: а как при Вашем подходе иметь несколько ядер, грубо говоря, «последнее» и «предыдущее» ? Или всегда верим что свежеустановленное ядро обязательно загрузится?

AlexM ★★★★★
()
Ответ на: комментарий от AlexM

Лично я решаю это наличием LTS-ядра рядом с основным - одно условно «старое»/fallback’овое, если в новом что-то отвалится; другое - основное. Ну и два загрузочных пункта в EFI, соответственно.

mradermaxlol
()
Ответ на: комментарий от mradermaxlol

А как боролись с стандартными libalpm-овыми хуками для mkinitcpio и прочими? Или, может, не боролись, а дорабатывали?

Стандартный хук при установке новой major-minor версии ядра формирует новый пресет, в котором uki выключен. Пресет формируется на основе /usr/share/mkinitcpio/hook.preset , который не помечен как конфиг.

Может быть, кто-то уже модифицировал пакеты для того, чтобы установка проходила более-менее автоматизированно?

AlexM ★★★★★
()
Ответ на: комментарий от AlexM

Я вроде бы и расписал, как сделать так, чтобы с хуками всё было в порядке. TL;DR: создание UKI прописывается в пресете, подпись Secure Boot на каждую пересборку initrd (т.е. не просто при обновлении пакетным менеджером, а и при ручном вызове mkinitcpio -P, например) прописывается в /etc/initcpio/post/secureboot.

Насчёт обновления пресетов - очень странное наблюдение, на всём своём зоопарке арчесистем файлы /etc/mkinitcpio.d/linux*.preset создаются один раз при установке пакета и никогда не обновляются пакетным менеджером (в крайнем случае рядом кладутся файлы .pacnew), сохраняя все прописанные руками наработки.

Возможно, я неправильно читаю вопрос; если имеется ввиду «при установке НОВОГО (отсутствовавшего ранее в системе) пакета с ядром (например, стоял linux, а рядом поставили linux-lts) пресет для него создаётся дефолтный» - да, так и должно быть, разочек придётся залезть в пресет-файл. Не вижу в этом проблемы - зачем может понадобиться на каждый чих ставить разные вариации ядер? Один раз поставил-настроил нужный набор и забыл.

mradermaxlol
()
Ответ на: комментарий от mradermaxlol

Нет, имеется в виду немного другая проблема, чем установка другого типа ядра. Речь про установку другой версии, что случается гораздо чаще.

Дело в том, что стандартный пакмановский (libalpm-ный) скрипт пакета mkinitcpio (/usr/share/libalpm/scripts/mkinitcpio, запускается соответствующими хуками из /usr/share/libalpm/hooks). Этот скрипт формирует при установке пакета с ядром (например, linuxXY) из шаблона /usr/share/mkinitcpio/hook.preset файлик с именем /etc/mkinitcpio.d/linuxXY.preset, который потом и используется как конфиг при запуске mkinitcpio. При установке ядра с новым major.minor файлик пресета сгенерируется наново, и нужно будет руками подчищать после установки ядра. Возможности «штатно» влиять на то, как генерируется этот файлик я не увидел.

Понятно, что можно написать свой пресет, а неподходящие пресеты, генерирующиеся автоматом, удалять. Или как-то модифицировать пакет mkinitcpio, чтобы он не был таким дубовым. Я хотел лишь узнать, может быть, кто-то уже пробежал этот путь вместо меня :-)

AlexM ★★★★★
()
Ответ на: комментарий от AlexM

УМВР:

peppermint@protomartyr ~> stat --printf "birth: %w\naccess: %x\nmodification: %y\nchange: %z\n" /etc/mkinitcpio.d/linux-cachyos-lto.preset
birth: 2024-01-17 14:31:03.678796391 +0300
access: 2024-04-15 08:37:44.789854324 +0300
modification: 2024-03-05 08:25:55.362116788 +0300
change: 2024-04-15 08:37:44.788854319 +0300
peppermint@protomartyr ~> pacman -Qi linux-cachyos-lto | grep Date
Build Date      : Sat 13 Apr 2024 05:29:20 PM MSK
Install Date    : Mon 15 Apr 2024 08:37:19 AM MSK

Access и change - скорее всего артефакт touch’а при установке новой версии. Modification - фактическое ковыряние файла руками (комментил что-то скорее всего).

Сам preset-файл:

peppermint@protomartyr ~> cat /etc/mkinitcpio.d/linux-cachyos-lto.preset 
# mkinitcpio preset file for the 'linux-cachyos-lto' package

ALL_config=(/etc/mkinitcpio.conf)
ALL_kver=(/boot/vmlinuz-linux-cachyos-lto)

PRESETS=('default')

default_uki=(/efi/EFI/Linux/linux.efi)

Не знаю, по какой причине у вас перезаписывается preset-файл на тот, что поставляет пакет. В штатной поставке обыкновенного арча (или CachyOS FWIW) такого поведения не замечено примерно ни разу; а если бы оно и было замечено, то получалась бы гигантская несостыковочка с тем, что написано в вики - в той же статье про UKI прямым текстом написано «подредачьте свой пресет».

Опять же: при обновлении (например, linux-6.7.1 => linux-6.8.0) пресет с изменениями сохраняется; в крайнем случае рядом с ним окажется файл .pacnew с обновлённой версией из пакета - точно так же, как и с другими конфигами (pacman.conf.pacnew, mkinitcpio.conf.pacnew и т.д.)

Вы уверены, что у вас в системе нет каких улучшайзеров для работы с ядрами или чего-то подобного? И мы ведь говорим о чистом арче, а не о производных типа манжары? (в принципе производные от арча обычно не меняют фундаментальщину; однако, манжара в этом вопросе умудрилась отличиться)

mradermaxlol
()
Последнее исправление: mradermaxlol (всего исправлений: 1)
Для того чтобы оставить комментарий войдите или зарегистрируйтесь.