<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>luks &amp;mdash; Sebastian Wiesner</title>
    <link>https://swsnr.writeas.com/tag:luks</link>
    <description>System engineer for satellite mission planning. Gnome. Rust. Arch.  </description>
    <pubDate>Sat, 09 May 2026 12:26:37 +0000</pubDate>
    <image>
      <url>https://i.snap.as/9knB2j11.jpg</url>
      <title>luks &amp;mdash; Sebastian Wiesner</title>
      <link>https://swsnr.writeas.com/tag:luks</link>
    </image>
    <item>
      <title>Unlock LUKS rootfs with TPM2 key</title>
      <link>https://swsnr.writeas.com/unlock-luks-rootfs-with-tpm2-key?pk_campaign=rss-feed</link>
      <description>&lt;![CDATA[#dracut #luks #sbctl #archlinux #systemd #secureboot&#xA;&#xA;a href=&#34;https://remark.as/p/swsnr/unlock-luks-rootfs-with-tpm2-key&#34;Discuss.../a &#xA;&#xA;Historically cryptsetup and LUKS only supported good old passwords; however recent systemd versions extend cryptsetup with additional key types such as FIDO tokens and TPM devices.&#xA;&#xA;I like the idea of encrypting the rootfs with a TPM2 key; it allows booting without ugly LUKS password prompts but still it keeps data encrypted at rest, and when combined with secure boot also still protects the running system against unauthorized access.&#xA;&#xA;Secure boot will prevent others from placing custom kernels on the unencrypted EFI system partition and booting these, or changing the kernel cmdline, in order to obtain root access to the unlocked rootfs.  LUKS encryption with a TPM-based key bound to secure boot state protects the data if someone removes the hard disk and attempts to access it offline, or tries to disable secure boot in order to boot a custom kernel.&#xA;&#xA;I’ve covered secure boot setup in a past article; this article talks about the TPM2-based encryption.&#xA;&#xA;!--more--&#xA;&#xA;Enroll TPM key&#xA;&#xA;Check that the system supports TPM2:&#xA;&#xA;$ systemd-cryptenroll --tpm2-device=list&#xA;PATH        DEVICE      DRIVER &#xA;/dev/tpmrm0 MSFT0101:00 tpmcrb&#xA;&#xA;Then enroll a new TPM2 key (use the appropriate block device path of course):&#xA;&#xA;$ systemd-cryptenroll --tpm2-device=auto /dev/disk/by-partlabel/linux &#xA;New TPM2 token enrolled as key slot 1.&#xA;&#xA;Then add recovery key:&#xA;&#xA;$ systemd-cryptenroll --recovery-key  /dev/disk/by-partlabel/linux&#xA;🔐 Please enter current passphrase for disk /dev/disk/by-partlabel/linux: &#xA;A secret recovery key has been generated for this volume:&#xA;&#xA;    🔐 efcfbdlt-rhkdjjul-inbhbvhi-nfkvbbbv-didjbjel-butkrrig-ugbrivdd-evnkkkgn&#xA;&#xA;Please save this secret recovery key at a secure location. It may be used to&#xA;regain access to the volume if the other configured access credentials have&#xA;been lost or forgotten. The recovery key may be entered in place of a password&#xA;whenever authentication is requested.&#xA;New recovery key enrolled as key slot 2.&#xA;&#xA;As suggested save this key in a secure location outside of the system. If TPM2 unlocking fails systemd will prompt for a password where you can enter this key.  This lets us access the data even if the TPM2 key became invalid (e.g. when the secure boot configuration changes).&#xA;&#xA;Configure dracut&#xA;&#xA;Force dracut to include the TPM2 software stack, by adding /etc/dracut.conf.d/tpm.conf:&#xA;&#xA;adddracutmodules+=&#34; tpm2-tss &#34;&#xA;And add files dracut currently fails to add, see&#xA;https://github.com/dracutdevs/dracut/issues/1676&#xA;install_items+=&#34; /usr/lib/cryptsetup/libcryptsetup-token-systemd-tpm2.so &#34;&#xA;&#xA;The last line adds necessary cryptsetup plugins which dracut doesn’t yet add (see https://github.com/dracutdevs/dracut/issues/1676).&#xA;&#xA;Make sure to use dracut newer than 055-106-g813577e2; dracut 55 has a typo in the tpm2-tss module dependencies which breaks the module (see https://github.com/dracutdevs/dracut/pull/1526), and another issue with systemd-sysusers which interferes with TPM2 support in early boot (see https://github.com/dracutdevs/dracut/pull/1658).  As of Dec 2021 you’ll need to install dracut-git from AUR.&#xA;&#xA;Reboot and cleanup&#xA;&#xA;Reboot to verify that the system now boots without a LUKS prompt.  Afterwards remove the password key from the rootfs:&#xA;&#xA;$ systemd-cryptenroll --wipe-slot=password /dev/disk/by-partlabel/linux&#xA;&#xA;Now the system only unlocks with the TPM2 key or the recovery key.&#xA;&#xA;Tighten security&#xA;&#xA;Check that&#xA;&#xA;secure boot is enabled (bootctl status or sbctl status),&#xA;secure boot uses custom keys,&#xA;all kernels are signed (sbctl verify; also check the firmware updater and other relevant EFI binaries), and&#xA;no unsigned initramfs or microcode image is used (at best use bundled UEFI executables).&#xA;&#xA;For users consider to use systemd-homed which offers per-user encrypted home “areas”, backed by LUKS encrypted loopback files.&#xA;&#xA;a href=&#34;https://remark.as/p/swsnr/unlock-luks-rootfs-with-tpm2-key&#34;Discuss.../a ]]&gt;</description>
      <content:encoded><![CDATA[<p><a href="https://swsnr.writeas.com/tag:dracut" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">dracut</span></a> <a href="https://swsnr.writeas.com/tag:luks" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">luks</span></a> <a href="https://swsnr.writeas.com/tag:sbctl" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">sbctl</span></a> <a href="https://swsnr.writeas.com/tag:archlinux" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">archlinux</span></a> <a href="https://swsnr.writeas.com/tag:systemd" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">systemd</span></a> <a href="https://swsnr.writeas.com/tag:secureboot" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">secureboot</span></a></p>

<p><a href="https://remark.as/p/swsnr/unlock-luks-rootfs-with-tpm2-key" rel="nofollow">Discuss...</a></p>

<p>Historically cryptsetup and LUKS only supported good old passwords; however recent systemd versions extend cryptsetup with <a href="https://0pointer.net/blog/unlocking-luks2-volumes-with-tpm2-fido2-pkcs11-security-hardware-on-systemd-248.html" rel="nofollow">additional key types</a> such as FIDO tokens and TPM devices.</p>

<p>I like the idea of encrypting the rootfs with a TPM2 key; it allows booting without ugly LUKS password prompts but still it keeps data encrypted at rest, and when combined with secure boot also still protects the running system against unauthorized access.</p>

<p>Secure boot will prevent others from placing custom kernels on the unencrypted EFI system partition and booting these, or changing the kernel cmdline, in order to obtain root access to the unlocked rootfs.  LUKS encryption with a TPM-based key bound to secure boot state protects the data if someone removes the hard disk and attempts to access it offline, or tries to disable secure boot in order to boot a custom kernel.</p>

<p>I’ve covered <a href="2021-04-01-secure-boot-on-arch-linux-with-sbctl-and-dracut.md" rel="nofollow">secure boot setup in a past article</a>; this article talks about the TPM2-based encryption.</p>



<h2 id="enroll-tpm-key" id="enroll-tpm-key">Enroll TPM key</h2>

<p>Check that the system supports TPM2:</p>

<pre><code class="language-console">$ systemd-cryptenroll --tpm2-device=list
PATH        DEVICE      DRIVER 
/dev/tpmrm0 MSFT0101:00 tpm_crb
</code></pre>

<p>Then enroll a new TPM2 key (use the appropriate block device path of course):</p>

<pre><code class="language-console">$ systemd-cryptenroll --tpm2-device=auto /dev/disk/by-partlabel/linux 
New TPM2 token enrolled as key slot 1.
</code></pre>

<p>Then add recovery key:</p>

<pre><code class="language-console">$ systemd-cryptenroll --recovery-key  /dev/disk/by-partlabel/linux
🔐 Please enter current passphrase for disk /dev/disk/by-partlabel/linux: 
A secret recovery key has been generated for this volume:

    🔐 efcfbdlt-rhkdjjul-inbhbvhi-nfkvbbbv-didjbjel-butkrrig-ugbrivdd-evnkkkgn

Please save this secret recovery key at a secure location. It may be used to
regain access to the volume if the other configured access credentials have
been lost or forgotten. The recovery key may be entered in place of a password
whenever authentication is requested.
New recovery key enrolled as key slot 2.
</code></pre>

<p>As suggested save this key in a secure location outside of the system. If TPM2 unlocking fails systemd will prompt for a password where you can enter this key.  This lets us access the data even if the TPM2 key became invalid (e.g. when the secure boot configuration changes).</p>

<h2 id="configure-dracut" id="configure-dracut">Configure dracut</h2>

<p>Force dracut to include the TPM2 software stack, by adding /etc/dracut.conf.d/tpm.conf:</p>

<pre><code class="language-console">add_dracutmodules+=&#34; tpm2-tss &#34;
# And add files dracut currently fails to add, see
# https://github.com/dracutdevs/dracut/issues/1676
install_items+=&#34; /usr/lib/cryptsetup/libcryptsetup-token-systemd-tpm2.so &#34;
</code></pre>

<p>The last line adds necessary cryptsetup plugins which dracut doesn’t yet add (see <a href="https://github.com/dracutdevs/dracut/issues/1676" rel="nofollow">https://github.com/dracutdevs/dracut/issues/1676</a>).</p>

<p>Make sure to use dracut newer than 055-106-g813577e2; dracut 55 has a typo in the tpm2-tss module dependencies which breaks the module (see <a href="https://github.com/dracutdevs/dracut/pull/1526" rel="nofollow">https://github.com/dracutdevs/dracut/pull/1526</a>), and another issue with systemd-sysusers which interferes with TPM2 support in early boot (see <a href="https://github.com/dracutdevs/dracut/pull/1658" rel="nofollow">https://github.com/dracutdevs/dracut/pull/1658</a>).  As of Dec 2021 you’ll need to install <a href="https://aur.archlinux.org/packages/dracut-git" rel="nofollow">dracut-git from AUR</a>.</p>

<h3 id="reboot-and-cleanup" id="reboot-and-cleanup">Reboot and cleanup</h3>

<p>Reboot to verify that the system now boots without a LUKS prompt.  Afterwards remove the password key from the rootfs:</p>

<pre><code class="language-console">$ systemd-cryptenroll --wipe-slot=password /dev/disk/by-partlabel/linux
</code></pre>

<p>Now the system only unlocks with the TPM2 key or the recovery key.</p>

<h3 id="tighten-security" id="tighten-security">Tighten security</h3>

<p>Check that</p>
<ul><li>secure boot is enabled (<code>bootctl status</code> or <code>sbctl status</code>),</li>
<li>secure boot uses custom keys,</li>
<li>all kernels are signed (<code>sbctl verify</code>; also check the firmware updater and other relevant EFI binaries), and</li>
<li>no unsigned initramfs or microcode image is used (at best use bundled UEFI executables).</li></ul>

<p>For users consider to use systemd-homed which offers per-user encrypted home “areas”, backed by LUKS encrypted loopback files.</p>

<p><a href="https://remark.as/p/swsnr/unlock-luks-rootfs-with-tpm2-key" rel="nofollow">Discuss...</a></p>
]]></content:encoded>
      <guid>https://swsnr.writeas.com/unlock-luks-rootfs-with-tpm2-key</guid>
      <pubDate>Sun, 26 Dec 2021 23:00:00 +0000</pubDate>
    </item>
    <item>
      <title>Arch Linux with LUKS and (almost) no configuration</title>
      <link>https://swsnr.writeas.com/arch-linux-with-luks-and-almost-no-configuration?pk_campaign=rss-feed</link>
      <description>&lt;![CDATA[#systemd #luks #dracut #archlinux&#xA;&#xA;a href=&#34;https://remark.as/p/swsnr/arch-linux-with-luks-and-almost-no-configuration&#34;Discuss.../a &#xA;&#xA;Installing Arch on a LUKS-encrypted dsik traditionally required a few careful configuration steps to configure the proper root device for booting; if any of these steps was omitted or done wrongly the system would fail to boot. With systemd and dracut however a LUKS-encrypted Arch system can boot safely and reliably without any configuration:&#xA;&#xA;Dracut builds a unified EFI kernel image including microcode and a generic initrd with systemd and cryptsetup.&#xA;systemd-boot automatically discovers unified kernel images installed by dracut and automatically adds them to the boot menu without explicit boot loader configuration.&#xA;At boot systemd automatically discovers and mounts the root file system following its DISCOVERABLE PARTITIONS specification.&#xA;&#xA;The following commands demonstrate a fresh Arch installation from the Arch installation media into a libvirt VM. Installing to a pristine physical machine or a different virtual machine provider should require only minimal changes; adapting an existing system may be more difficult and require more work.&#xA;&#xA;!--more--&#xA;&#xA;Prepare the disk&#xA;&#xA;$ sgdisk &#xA;    -n1:0:+500M  -t1:ef00 -c1:EFISYSTEM &#xA;    -n2:0:+1000M -t2:ea00 -c2:XBOOTLDR &#xA;    -N3          -t3:8304 -c3:linux &#xA;    /dev/vda&#xA;$ mkfs.fat -F32 -n EFISYSTEM /dev/disk/by-partlabel/EFISYSTEM&#xA;$ mkfs.fat -F32 -n XBOOTLDR /dev/disk/by-partlabel/XBOOTLDR&#xA;$ cryptsetup luksFormat /dev/disk/by-partlabel/linux&#xA;$ cryptsetup luksOpen /dev/disk/by-partlabel/linux root&#xA;$ mkfs.btrfs -L linux /dev/mapper/root&#xA;&#xA;This creates a 500M EFI system partition for the boot loader and the kernel, a 1000M extended boot loader partition for systemd-boot (entirely optional, but helpful for rescue systems or Windows dual-boot), and fills the rest of the partition with a LUKS parition holding a btrfs filesystem. Each partition gets the proper type code (-t) corresponding to the discoverable partition GUID (e.g. 8304 refers to the “Linux x86-64 root (/)” partition); this enables systemd to automatically mount the partition. For convenience each partition also gets a GPT partition label (-c) which we can use to refer to the partition by name under /dev/disk/by-partlabel instead of remembering the numeric order of partitions as in /dev/vda1.&#xA;&#xA;Install and configure the base system&#xA;&#xA;We now install a base Arch system on top of the new file system:&#xA;&#xA;$ mount /dev/mapper/root/ /mnt&#xA;$ mkdir /mnt/{boot,efi}&#xA;$ btrfs subvolume create /mnt/var&#xA;$ btrfs subvolume create /mnt/home&#xA;$ mount /dev/disk/by-partlabel/EFISYSTEM /mnt/efi&#xA;$ mount /dev/disk/by-partlabel/XBOOTLDR /mnt/boot&#xA;$ reflector --save /etc/pacman.d/mirrorlist --protocol https --latest 5 --sort age&#xA;$ pacstrap /mnt base linux linux-lts linux-firmware intel-ucode btrfs-progs dracut neovim&#xA;$ arch-chroot /mnt&#xA;$ ln -sf /usr/share/zoneinfo/UTC /etc/localtime&#xA;$ nvim /etc/locale.gen /etc/locale.conf /etc/vconsole.conf /etc/hostname /etc/hosts&#xA;$ locale-gen&#xA;$ passwd&#xA;&#xA;Note that we explicitly do not create /etc/fstab.&#xA;&#xA;Generate unified kernel image&#xA;&#xA;While still in chroot we install the optional dependencies dracut requires to build unified kernel images and then run dracut for all kernels we installed above.&#xA;&#xA;$ pacman -S --asdeps binutils elfutils&#xA;$ for kver in /lib/modules/; do dracut -f --uefi --kver &#34;${kver##/}&#34;; done&#xA;&#xA;Install the boot loader&#xA;&#xA;Next we install the systemd-boot boot loader, again still from chroot; we need no further configuration as we mount the EFI and boot loader paritions at their standard paths /efi and /boot respectively.&#xA;&#xA;$ bootctl install&#xA;&#xA;Continue installation&#xA;&#xA;At this point we can install additional packages and enable services; for the purpose of this demonstration we’ll add a simple network configuration:&#xA;&#xA;$ cat   /etc/systemd/network/20-wired.network &lt;&lt;EOF&#xA;[Match]&#xA;Name=enp1s0&#xA;&#xA;[Network]&#xA;DHCP=yes&#xA;EOF&#xA;$ umount /etc/resolve.conf&#xA;$ ln -sf /run/systemd/resolve/stub-resolve.conf /etc/resolve.conf&#xA;$ systemctl enable systemd-network.service&#xA;$ systemctl enable systemd-timesyncd.service&#xA;$ systemctl enable systemd-resolved.service&#xA;&#xA;At the time of writing arch-chroot bind-mounts the live disk resolve.conf into the chroot; we need to unmount it explicitly before we can setup the systemd stub resolver for the new installation.&#xA;&#xA;For a real server or desktop installation we would likely install more packages and services and setup user accounts at this point to boot into a fully working system. I usually run my arch/install.bash script when installing a desktop system (for servers I tend to use other distributions, or one of the Arch Linux cloud images)&#xA;&#xA;Reboot into the new system&#xA;&#xA;$ exit&#xA;$ poweroff&#xA;&#xA;Now we can remove the installation media and start the system again; by holding the space key during boot we make the boot menu appear to verify that the generated unified kernel images are indeed recognized by systemd-boot:&#xA;&#xA;Boot menu with UKIs&#xA;&#xA;systemd-boot seems to pick the image with the highest version number automatically. Upon boot the image automatically discovers the LUKS root partition and offers to unlock it:&#xA;&#xA;Auto-discovered LUKS partition&#xA;&#xA;All this happens automatically; we did not have to configure /etc/fstab and /etc/crypttab.initramfs to specify the root filesystem, nor /etc/mkinitcpio.conf to include the right systemd and cryptsetup hooks.&#xA;&#xA;Configuring for more convenience&#xA;&#xA;At this point the system boots perfectly fine without any configuration, but nonetheless there are a few relevant configuration switches.&#xA;&#xA;Generate kernel images upon installation&#xA;&#xA;Currently the dract package includes no libalpm hooks to build new EFISTUB binaries on kernel updates. The Arch wiki documents the hooks necessary to make this happen; I use dracut-hook-uefi-systemd from AUR to automate this.&#xA;&#xA;Optimize the initrd&#xA;&#xA;By default dracut builds a generic initrd which works on any hardware and system; this mode is intended for distribution vendors which ship a prebuilt initrd as a package. Arch however builds the initrd on the system after installation; this allows us to enable host-only mode to reduce the size of the image and embed host-specific kernel flags. Dracuts reads configuration files from /etc/dracut.conf.d, e.g. /etc/dracut.conf.d/50-host-only.conf:&#xA;&#xA;Hide all systemd messages at startup&#xA;kernelcmdline=&#34;quiet&#34;&#xA;Use hostonly to exclude unnecessary modules, but do not include the hostonly&#xA;cmdline in the image, because at the time of writing it has a few issues with&#xA;discoverable partitions.&#xA;# See https://github.com/dracutdevs/dracut/issues/723#issuecomment-792248568&#xA;hostonly=&#34;yes&#34;&#xA;hostonlycmdline=&#34;no&#34;&#xA;&#xA;Configure the boot menu&#xA;&#xA;systemd-boot enables the kernel command line editor by default, to aid with fixing unbootable systems. With physical access to the machine we can gain root access by booting into /bin/sh with proper kernel parameters. In our system the impact of this security hole is limited since the attacker cannot unlock the encrypted root disk to do anything with the system, but nonetheless it’s recommended to disable the editor in /efi/loader/loader.conf. At this place we can also change the boot menu timeout, and set the default kernel.&#xA;&#xA;Disable the editor to improve security a bit.&#xA;editor no&#xA;Directly boot the default kernel; to make the boot menu appear&#xA;press any key during the firmware splash screen.&#xA;timeout 0&#xA;Boot the LTS kernel by default.&#xA;default linux--lts-&#xA;&#xA;The default stanza supports glob patterns; systemd boot then picks the matching image with the highest version. The pattern in the above example matches the linux LTS kernel.&#xA;&#xA;Conclusion&#xA;&#xA;This setup now boots seamlessly into the getty prompt:&#xA;&#xA;Auto-discovered boot&#xA;&#xA;a href=&#34;https://remark.as/p/swsnr/arch-linux-with-luks-and-almost-no-configuration&#34;Discuss.../a ]]&gt;</description>
      <content:encoded><![CDATA[<p><a href="https://swsnr.writeas.com/tag:systemd" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">systemd</span></a> <a href="https://swsnr.writeas.com/tag:luks" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">luks</span></a> <a href="https://swsnr.writeas.com/tag:dracut" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">dracut</span></a> <a href="https://swsnr.writeas.com/tag:archlinux" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">archlinux</span></a></p>

<p><a href="https://remark.as/p/swsnr/arch-linux-with-luks-and-almost-no-configuration" rel="nofollow">Discuss...</a></p>

<p>Installing Arch on a LUKS-encrypted dsik traditionally required a few careful configuration steps to configure the proper root device for booting; if any of these steps was omitted or done wrongly the system would fail to boot. With systemd and dracut however a LUKS-encrypted Arch system can boot safely and reliably without any configuration:</p>
<ul><li>Dracut builds a unified EFI kernel image including microcode and a generic initrd with systemd and cryptsetup.</li>
<li>systemd-boot automatically discovers unified kernel images installed by dracut and automatically adds them to the boot menu without explicit boot loader configuration.</li>
<li>At boot systemd automatically discovers and mounts the root file system following its <a href="https://systemd.io/DISCOVERABLE_PARTITIONS/" rel="nofollow">DISCOVERABLE PARTITIONS</a> specification.</li></ul>

<p>The following commands demonstrate a fresh Arch installation from the Arch installation media into a libvirt VM. Installing to a pristine physical machine or a different virtual machine provider should require only minimal changes; adapting an existing system may be more difficult and require more work.</p>



<h2 id="prepare-the-disk" id="prepare-the-disk">Prepare the disk</h2>

<pre><code class="language-console">$ sgdisk 
    -n1:0:+500M  -t1:ef00 -c1:EFISYSTEM 
    -n2:0:+1000M -t2:ea00 -c2:XBOOTLDR 
    -N3          -t3:8304 -c3:linux 
    /dev/vda
$ mkfs.fat -F32 -n EFISYSTEM /dev/disk/by-partlabel/EFISYSTEM
$ mkfs.fat -F32 -n XBOOTLDR /dev/disk/by-partlabel/XBOOTLDR
$ cryptsetup luksFormat /dev/disk/by-partlabel/linux
$ cryptsetup luksOpen /dev/disk/by-partlabel/linux root
$ mkfs.btrfs -L linux /dev/mapper/root
</code></pre>

<p>This creates a 500M EFI system partition for the boot loader and the kernel, a 1000M extended boot loader partition for systemd-boot (entirely optional, but helpful for rescue systems or Windows dual-boot), and fills the rest of the partition with a LUKS parition holding a btrfs filesystem. Each partition gets the proper type code (<code>-t</code>) corresponding to the <a href="https://systemd.io/DISCOVERABLE_PARTITIONS/" rel="nofollow">discoverable partition GUID</a> (e.g. <code>8304</code> refers to the “Linux x86-64 root (/)” partition); this enables systemd to automatically mount the partition. For convenience each partition also gets a GPT partition label (<code>-c</code>) which we can use to refer to the partition by name under <code>/dev/disk/by-partlabel</code> instead of remembering the numeric order of partitions as in <code>/dev/vda1</code>.</p>

<h2 id="install-and-configure-the-base-system" id="install-and-configure-the-base-system">Install and configure the base system</h2>

<p>We now install a base Arch system on top of the new file system:</p>

<pre><code class="language-console">$ mount /dev/mapper/root/ /mnt
$ mkdir /mnt/{boot,efi}
$ btrfs subvolume create /mnt/var
$ btrfs subvolume create /mnt/home
$ mount /dev/disk/by-partlabel/EFISYSTEM /mnt/efi
$ mount /dev/disk/by-partlabel/XBOOTLDR /mnt/boot
$ reflector --save /etc/pacman.d/mirrorlist --protocol https --latest 5 --sort age
$ pacstrap /mnt base linux linux-lts linux-firmware intel-ucode btrfs-progs dracut neovim
$ arch-chroot /mnt
$ ln -sf /usr/share/zoneinfo/UTC /etc/localtime
$ nvim /etc/locale.gen /etc/locale.conf /etc/vconsole.conf /etc/hostname /etc/hosts
$ locale-gen
$ passwd
</code></pre>

<p>Note that we explicitly do <em>not</em> create <code>/etc/fstab</code>.</p>

<h2 id="generate-unified-kernel-image" id="generate-unified-kernel-image">Generate unified kernel image</h2>

<p>While still in <code>chroot</code> we install the optional dependencies <code>dracut</code> requires to build unified kernel images and then run dracut for all kernels we installed above.</p>

<pre><code class="language-console">$ pacman -S --asdeps binutils elfutils
$ for kver in /lib/modules/*; do dracut -f --uefi --kver &#34;${kver##*/}&#34;; done
</code></pre>

<h2 id="install-the-boot-loader" id="install-the-boot-loader">Install the boot loader</h2>

<p>Next we install the <code>systemd-boot</code> boot loader, again still from <code>chroot</code>; we need no further configuration as we mount the EFI and boot loader paritions at their standard paths <code>/efi</code> and <code>/boot</code> respectively.</p>

<pre><code class="language-console">$ bootctl install
</code></pre>

<h2 id="continue-installation" id="continue-installation">Continue installation</h2>

<p>At this point we can install additional packages and enable services; for the purpose of this demonstration we’ll add a simple network configuration:</p>

<pre><code class="language-console">$ cat &gt; /etc/systemd/network/20-wired.network &lt;&lt;EOF
[Match]
Name=enp1s0

[Network]
DHCP=yes
EOF
$ umount /etc/resolve.conf
$ ln -sf /run/systemd/resolve/stub-resolve.conf /etc/resolve.conf
$ systemctl enable systemd-network.service
$ systemctl enable systemd-timesyncd.service
$ systemctl enable systemd-resolved.service
</code></pre>

<p>At the time of writing <code>arch-chroot</code> bind-mounts the live disk <code>resolve.conf</code> into the chroot; we need to unmount it explicitly before we can setup the systemd stub resolver for the new installation.</p>

<p>For a real server or desktop installation we would likely install more packages and services and setup user accounts at this point to boot into a fully working system. I usually run my <a href="https://github.com/lunaryorn/dotfiles/blob/f40ea05cd64dc90ba5ed1824eeca2ee4c657f11b/arch/install.bash" rel="nofollow"><code>arch/install.bash</code></a> script when installing a desktop system (for servers I tend to use other distributions, or one of the Arch Linux cloud images)</p>

<h2 id="reboot-into-the-new-system" id="reboot-into-the-new-system">Reboot into the new system</h2>

<pre><code class="language-console">$ exit
$ poweroff
</code></pre>

<p>Now we can remove the installation media and start the system again; by holding the space key during boot we make the boot menu appear to verify that the generated unified kernel images are indeed recognized by systemd-boot:</p>

<p><img src="https://i.snap.as/qvW71UXG.png" alt="Boot menu with UKIs"/></p>

<p>systemd-boot seems to pick the image with the highest version number automatically. Upon boot the image automatically discovers the LUKS root partition and offers to unlock it:</p>

<p><img src="https://i.snap.as/s6S40UCu.png" alt="Auto-discovered LUKS partition"/></p>

<p>All this happens automatically; we did not have to configure <code>/etc/fstab</code> and <code>/etc/crypttab.initramfs</code> to specify the root filesystem, nor <code>/etc/mkinitcpio.conf</code> to include the right systemd and cryptsetup hooks.</p>

<h2 id="configuring-for-more-convenience" id="configuring-for-more-convenience">Configuring for more convenience</h2>

<p>At this point the system boots perfectly fine without any configuration, but nonetheless there are a few relevant configuration switches.</p>

<h3 id="generate-kernel-images-upon-installation" id="generate-kernel-images-upon-installation">Generate kernel images upon installation</h3>

<p>Currently the dract package includes no libalpm hooks to build new EFISTUB binaries on kernel updates. The Arch wiki documents the <a href="https://wiki.archlinux.org/index.php/Dracut#Generate_a_new_initramfs_on_kernel_upgrade" rel="nofollow">hooks necessary to make this happen</a>; I use <code>dracut-hook-uefi-systemd</code> from AUR to automate this.</p>

<h3 id="optimize-the-initrd" id="optimize-the-initrd">Optimize the initrd</h3>

<p>By default dracut builds a generic initrd which works on any hardware and system; this mode is intended for distribution vendors which ship a prebuilt initrd as a package. Arch however builds the initrd on the system after installation; this allows us to enable host-only mode to reduce the size of the image and embed host-specific kernel flags. Dracuts reads configuration files from <code>/etc/dracut.conf.d</code>, e.g. <code>/etc/dracut.conf.d/50-host-only.conf</code>:</p>

<pre><code class="language-ini"># Hide all systemd messages at startup
kernel_cmdline=&#34;quiet&#34;
# Use hostonly to exclude unnecessary modules, but do not include the hostonly
# cmdline in the image, because at the time of writing it has a few issues with
# discoverable partitions.
# See &lt;https://github.com/dracutdevs/dracut/issues/723#issuecomment-792248568&gt;
hostonly=&#34;yes&#34;
hostonly_cmdline=&#34;no&#34;
</code></pre>

<h3 id="configure-the-boot-menu" id="configure-the-boot-menu">Configure the boot menu</h3>

<p>systemd-boot enables the kernel command line editor by default, to aid with fixing unbootable systems. With physical access to the machine we can gain root access by booting into <code>/bin/sh</code> with proper kernel parameters. In our system the impact of this security hole is limited since the attacker cannot unlock the encrypted root disk to do anything with the system, but nonetheless it’s recommended to disable the editor in <code>/efi/loader/loader.conf</code>. At this place we can also change the boot menu timeout, and set the default kernel.</p>

<pre><code class="language-ini"># Disable the editor to improve security a bit.
editor no
# Directly boot the default kernel; to make the boot menu appear
# press any key during the firmware splash screen.
timeout 0
# Boot the LTS kernel by default.
default linux-*-lts-*
</code></pre>

<p>The <code>default</code> stanza supports glob patterns; systemd boot then picks the matching image with the highest version. The pattern in the above example matches the linux LTS kernel.</p>

<h2 id="conclusion" id="conclusion">Conclusion</h2>

<p>This setup now boots seamlessly into the getty prompt:</p>

<p><img src="https://i.snap.as/DTUQ4QGe.webp" alt="Auto-discovered boot"/></p>

<p><a href="https://remark.as/p/swsnr/arch-linux-with-luks-and-almost-no-configuration" rel="nofollow">Discuss...</a></p>
]]></content:encoded>
      <guid>https://swsnr.writeas.com/arch-linux-with-luks-and-almost-no-configuration</guid>
      <pubDate>Fri, 26 Mar 2021 23:00:00 +0000</pubDate>
    </item>
  </channel>
</rss>