Publish first article

This commit is contained in:
Thibault “Adædra” Hamel 2024-06-12 21:51:03 +02:00
parent 7803df674c
commit fe9be53de4
3 changed files with 54 additions and 15 deletions

View File

@ -1,4 +1,7 @@
= Arch Linux with UKI & SecureBoot
= Arch Linux with UKI & Secure Boot
:docdate: 2024-06-12
:description: UEFI and UKI allows to boot a Linux Kernel without bootloader. See how to set it up under Arch Linux.
:keywords: Linux, Arch Linux, UEFI, UKI, Secure Boot
The Linux boot sequence can be seen as a bit convoluted, as multiple options exist, and the more recent advent of UEFI has shuffled this space again. While GRUB is still a very popular option, especially since it is compatible with both traditional BIOS boot and more recent UEFI firmwares, it is not the only one.
@ -8,9 +11,9 @@ Arch Linux is a generic distribution geared towards tinkerers. It notably has no
== Prerequisites
We are going to make an Arch Linux installation boot from UEFI. This can be done either from an existing installation or during the initial installation process. The only true requirement is to be on an UEFI-compatible machine and https://wiki.archlinux.org/title/Installation_guide#Verify_the_boot_mode[booting into this mode]. Of course, this also means having an https://wiki.archlinux.org/title/EFI_system_partition[UEFI boot partition]. In this guide, I have mounted mine at `+/boot/efi+`, although some installs mount it directly into `+/boot+`. It doesnt matter much, but you might have to correct some paths if its the case for you.
We are going to make an Arch Linux installation boot from UEFI. This can be done either from an existing installation, or during the initial installation process. The only true requirement is to be on an UEFI-compatible machine and https://wiki.archlinux.org/title/Installation_guide#Verify_the_boot_mode[booting into this mode]. Of course, this also means having an https://wiki.archlinux.org/title/EFI_system_partition[UEFI boot partition]. In this article, I have mounted mine at `+/boot/efi+`, although some installs mount it directly into `+/boot+`. It doesnt matter much, but you might have to correct some paths if its the case for you.
This guide will also show how to make it compatible with https://wiki.archlinux.org/title/Unified_Extensible_Firmware_Interface/Secure_Boot[SecureBoot]. SecureBoot is a bit of a problematic point in the Linux community and some people prefer to leave it out. I am not going to argue for or against it, I am just presenting how to make it compatible, but this part is completely optional. However, if you want to go with SecureBoot, you need to boot your machine with SecureBoot enabled and in setup mode.
This guide will also show how to make it compatible with https://wiki.archlinux.org/title/Unified_Extensible_Firmware_Interface/Secure_Boot[Secure Boot]. Secure Boot is a bit of a problematic feature in the Linux community, and some people prefer to leave it out. I am not going to argue for or against it, I am just presenting how to make it compatible, but this part is completely optional. However, if you want to go with Secure Boot, you need to boot your machine with Secure Boot enabled and in Setup mode.
Note: Arch Linux now provides multiple choices for the https://wiki.archlinux.org/title/Arch_boot_process#initramfs[initramfs]. https://wiki.archlinux.org/title/Mkinitcpio[mkinitcpio] has been the historical and still default choice today, but it is also possible to use https://wiki.archlinux.org/title/Dracut[dracut] or https://wiki.archlinux.org/title/Booster[booster]. dracut supports making an UKI image directly, and there is `+systemd-ukify+` that can make an UKI image from separate kernel and initramfs. However, this article will focus on mkinitcpio.
@ -18,7 +21,7 @@ Note: Arch Linux now provides multiple choices for the https://wiki.archlinux.or
=== mkinitcpio
On your existing system, or on a system at the boot loader phase of the install, we will need to configure mkinitcpio to write to an UKI image. Ensure the `+mkinitcpio+` package is installed. Then, we will edit the preset file for mkinitcpio, located at `+/etc/mkinitcpio.d/linux.preset+` (or a similar name depending on your kernel flavour of choice like `+linux-lts.preset+`). Disable the classical initramfs generation by commenting the `+default_image+` and `+fallback_image+` options, then enable UKI generation by uncommenting the `+default_uki+` and `+fallback_uki+` options. Also, ensure the paths are correct. For a UEFI boot partition mounted at `+/boot/efi+`:
On your existing system, or on a system at the boot loader phase of the install, we will need to configure mkinitcpio to write to an UKI image. Ensure the `+mkinitcpio+` package is installed. Then, we will edit the preset file for mkinitcpio, located at `+/etc/mkinitcpio.d/linux.preset+` (or a similar name depending on your kernel flavour of choice like `+linux-lts.preset+`). Disable the classical initramfs generation by commenting the `+default_image+` and `+fallback_image+` options, then enable UKI generation by uncommenting the `+default_uki+` and `+fallback_uki+` options. Ensure the paths are correct. For a UEFI boot partition mounted at `+/boot/efi+`:
[source,bash]
----
@ -26,11 +29,11 @@ default_uki="/boot/efi/EFI/Linux/arch-linux.efi"
fallback_uki="/boot/efi/EFI/Linux/arch-linux-fallback.efi"
----
Also, mkinitcpio expects the parent folder to already exist which is not by default the case. Use `+mkdir+` to ensure the folder is created.
Finally, mkinitcpio expects the parent folder to already exist which is not by default the case. Use `+mkdir+` to ensure the folder is created.
=== Command Line
In traditional Linux setup, the kernel options or command line is stored and passed by the bootloader, and usually configured there. Here, we have no bootloader, but still need to provide the command line options.
In a traditional Linux setup, the kernel options (or _command line_) is stored and passed by the bootloader, and usually configured there. Here, we have no bootloader, but still need to provide the command line options.
The UKI build process assemble the command line from files in `+/etc/cmdline.d+`. You can create `+.conf+` files in this folder containing command line arguments (which also allows you to group related arguments together). Simplest example is to create a `+/etc/cmdline.d/root.conf+` with the root configuration:
@ -59,19 +62,21 @@ efibootmgr --create --disk=/dev/vda --part=1 --label="Arch Linux" --loader='\EFI
efibootmgr --create-only --disk=/dev/vda --part=1 --label="Arch Linux Fallback" --loader='\EFI\Linux\arch-linux-fallback.efi'
....
Note that the second command for the fallback image is created with `+--create-only+` instead of `+--create+`. This way, it will not be booted automatically, but still be available as a boot option.
=== Rebooting
Everything is set up! Now you can finalise the installation steps (if applicable) and reboot your machine, then check that your system boots directly into Arch Linux. You can also trigger the UEFI boot menu to check for the additional entry for the fallback image.
Everything is set up! Now, you can finalise the installation steps (if applicable) and reboot your machine, then check that your system boots directly into Arch Linux. You can also trigger the UEFI boot menu to check for the additional entry for the fallback image.
Congratulations! You now boot entirely through your UKI image.
== SecureBoot
== Secure Boot
Note: As said above, this step is optional, if you do not want to use SecureBoot.
Note: As said above, this step is optional, if you do not want to use Secure Boot.
SecureBoot is an addition to UEFI that ensures that your boot sequence has not been tampered with, by requiring all boot images to be signed with a valid certificate. By default, machines have two Microsoft-provided certificates, one for Windows, one for third party systems, that some distributions use to provide some level of support to SecureBoot. You can also register your own certificate into the machine to sign your own binaries, which is what we are going to setup here. Once setup correctly, the signing process is automatic.
Secure Boot is an addition to UEFI that ensures that your boot sequence has not been tampered with, by requiring all boot images to be signed with a valid certificate. By default, machines have two Microsoft-provided certificates, one for Windows, one for third party systems, the latter being used by some distributions to provide some level of support to Secure Boot. You can also register your own certificate into the machine to sign your own binaries, which is what we are going to set up here. Once setup correctly, the signing process is automatic.
Install the `+sbctl+` package. Ensure that your machine has SecureBoot is in setup mode by issuing `+sbctl status+`:
Install the `+sbctl+` package. Ensure that your machine has Secure Boot is in setup mode by issuing `+sbctl status+`:
....
Installed: ✓ sbctl is installed
@ -83,7 +88,9 @@ Vendor Keys: none
Note: `+sbctl+` might also indicate that it is _not_ installed, but this will correct itself in the next steps.
If it is not, you will have to reboot your machine into the firmware interface to enable it. `+sbctl+` is a nice command to simplify the process of dealing with SecureBoot. To create a certificate and record it into our firmware, we issue the following commands:
If it is not, you will have to reboot your machine into the firmware interface to enable it. Some firmware will go into Setup mode by choosing to erase all certificates.
`+sbctl+` is a nice command to simplify the process of dealing with Secure Boot. To create a certificate and record it into our firmware, we issue the following commands:
....
sbctl create-keys
@ -126,11 +133,11 @@ While this is enough for a functional setup, I have some personal tweaks to this
=== Automatic root decryption
Note: Requires SecureBoot, a TPM, and a LUKS 2 encrypted root.
Note: Requires Secure Boot, a https://wiki.archlinux.org/title/Trusted_Platform_Module[TPM], and a LUKS 2 encrypted root.
If your root partition is encrypted, you have to enter the passphrase at every boot. If you have a TPM, you can use it to automatically provide this passphrase to the system. While this seem like a downgrade in security, your system is normally still password protected at the login prompt, so your data should be safe, but it is your choice between more security and ease of use. However, it becomes dangerous if coupled with auto-login!
The boot process and the TPM will ensure that your system has not been tempered with. It means that it will compare SecureBoot certificates at boot and will refuse to use the saved credentials if they are modified.
The boot process and the TPM will ensure that your system has not been tempered with. It means that it will compare Secure Boot certificates at boot and will refuse to use the saved credentials if they are modified, which is even stronger than the base Secure Boot check.
Note: This does not save your passphrase in the firmware. It uses a different LUKS slot with its own data saved into the TPM. The safety of the passphrase itself is not affected.
@ -179,4 +186,4 @@ PRESETS=('fallback' 'default')
You can now close the preset file. Recreate the parent folder with `+mkdir+`, then run `+mkinitcpio -P+` to re-create the images in the right order.
Note: If you have SecureBoot set up, do not forget to sign its binary with `+sbctl+`.
Note: If you have Secure Boot set up, do not forget to sign its image with `+sbctl+`.

View File

@ -24,6 +24,11 @@ const FONT_PRESETS = {
mono: { ranges: ["20-7F", "2E22-2E25", "2713", "2717"] },
text: { ranges: ["20-7F", "A0-FF", "2000-206F", "20AC"] },
};
const SITE_DESCRIPTION = [
"Ad\xE6dra",
"Software Developper in Paris, France",
"Rust, Ruby, Typescript, Linux",
].join(" \u2022 ");
const Asciidoctor = asciidoctor();
@ -93,6 +98,20 @@ const renderArticle = () => {
const content = renderLayout({
asset,
title: article.getDoctitle(),
meta: {
description: article.getAttribute("description"),
keywords: article.getAttribute("keywords"),
"og:title": article.getDoctitle(),
"og:type": "article",
"og:article:published_time": article.getAttribute("docdate"),
"og:url": `https://adaedra.eu/${slug}/`,
"og:image":
"https://adaedra.blob.core.windows.net/blog-assets/cariboudev.avif",
"og:image:alt": "Ad\xE6dra's mascot",
"og:description": article.getAttribute("description"),
"og:locale": "en_GB",
"og:site_name": "Ad\xE6dra",
},
render() {
return renderArticleLayout({
asset,
@ -119,6 +138,17 @@ const renderArticle = () => {
const renderIndex = pug.compileFile("src/index.pug");
const contents = renderLayout({
asset,
meta: {
description: SITE_DESCRIPTION,
"og:title": "Ad\xE6dra",
"og:type": "website",
"og:url": `https://adaedra.eu/`,
"og:image":
"https://adaedra.blob.core.windows.net/blog-assets/cariboudev.avif",
"og:image:alt": "Ad\xE6dra's mascot",
"og:description": SITE_DESCRIPTION,
"og:locale": "en_GB",
},
render() {
return renderIndex({ articles: allArticles, asset });
},

View File

@ -8,6 +8,8 @@ html(lang="en")
| Adædra's blog
meta(name="viewport" content="width=device-width, initial-scale=1")/
meta(name="theme-color" content="#DDCBA3")/
- for([name, content] of Object.entries(meta))
meta(name=name content=content)/
link(rel="stylesheet" type="text/css" href=asset('index.css'))/
body: .main
!= render()