<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Secure Boot on Giovanni Bassi</title><link>https://giggio.net/en/blog/tags/secure-boot/</link><image><url>https://giggio.net/images/base/logo-small.png</url><title>Secure Boot on Giovanni Bassi</title><link>https://giggio.net/en/blog/tags/secure-boot/</link></image><description>Secure Boot no site do Giovanni Bassi</description><generator>Hugo</generator><language>en</language><managingEditor>giggio@giggio.net (Giovanni Bassi)</managingEditor><webMaster>giggio@giggio.net (Giovanni Bassi)</webMaster><copyright>© 2025 Giovanni Bassi</copyright><lastBuildDate>Mon, 18 May 2026 11:00:00 -0300</lastBuildDate><atom:link href="https://giggio.net/en/blog/tags/secure-boot/index.xml" rel="self" type="application/rss+xml"/><item><title>NixOS: Installation Guide with RAID 1, encryption, and TPM Unlock (part 5 - unlocking the disk with TPM)</title><link>https://giggio.net/en/blog/nix-os-guia-de-instalacao-com-raid-1-criptografia-e-tpm-unlock-parte-5-destrancando-o-disco-com-tpm/</link><pubDate>Mon, 18 May 2026 11:00:00 -0300</pubDate><author>giggio@giggio.net (Giovanni Bassi)</author><guid>https://giggio.net/en/blog/nix-os-guia-de-instalacao-com-raid-1-criptografia-e-tpm-unlock-parte-5-destrancando-o-disco-com-tpm/</guid><category>infra</category><description>&lt;p&gt;At last, we are going to automatically decrypt the NixOS disk using the TPM!&lt;/p&gt;
&lt;p&gt;This is the fifth post in the series:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://giggio.net/en/blog/nix-os-guia-de-instalacao-com-raid-1-criptografia-e-tpm-unlock-parte-1/"&gt;Preparing the virtual machine and partitioning the disks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://giggio.net/en/blog/nix-os-guia-de-instalacao-com-raid-1-criptografia-e-tpm-unlock-parte-2-disko-luks-e-btrfs/"&gt;Disko, LUKS, and btrfs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://giggio.net/en/blog/nix-os-guia-de-instalacao-com-raid-1-criptografia-e-tpm-unlock-parte-3-instalando-o-so/"&gt;Installing the OS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://giggio.net/en/blog/nix-os-guia-de-instalacao-com-raid-1-criptografia-e-tpm-unlock-parte-4-secure-boot/"&gt;Enabling Secure Boot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Unlocking the disk with TPM (this post)&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Up to now, every boot has required the LUKS password to decrypt the disk. But if the machine’s integrity has not been
compromised, there is no problem in doing this automatically. But how?&lt;/p&gt;
&lt;p&gt;Now it is time to orchestrate everything we have put together so far, connecting LUKS, Secure Boot, and the TPM.&lt;/p&gt;
&lt;h3 id="why-this-is-safe"&gt;
 &lt;a href="#why-this-is-safe" class="site-blog-post-header"&gt;
 &lt;span class="site-blog-post-header-text"&gt;Why this is safe&lt;/span&gt;
 &lt;i class="fa-solid fa-link site-blog-post-header-paragraph"&gt;&lt;/i&gt;
 &lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;Assuming the machine has not been compromised, when the operating system comes up, the only safe way to access it is
with valid credentials — assuming the system has no exploitable vulnerability. That means logging in through the
console, SSH, the graphical interface, or a serial connection. In practice, that means that without a login password
there is no access to the computer, and no privilege is gained.&lt;/p&gt;
&lt;p&gt;Everything works based on this principle: an uncompromised and intact system protects itself, and if it is compromised
(firmware modification, disk removal, etc), encryption protects the data.&lt;/p&gt;
&lt;h3 id="understanding-the-tpm"&gt;
 &lt;a href="#understanding-the-tpm" class="site-blog-post-header"&gt;
 &lt;span class="site-blog-post-header-text"&gt;Understanding the TPM&lt;/span&gt;
 &lt;i class="fa-solid fa-link site-blog-post-header-paragraph"&gt;&lt;/i&gt;
 &lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;The TPM (Trusted Platform Module) is a dedicated processor that stores, in an inviolable way, measurements taken of the
hardware and software running on the computer. These measurements are stored in &lt;strong&gt;PCRs&lt;/strong&gt; (Platform Configuration
Registers), whose values can be extended, but never set directly. Every value sent to the TPM extends the previous
value and produces a new one. If we were to model this as a formula, it would be something like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;PCR = HASH(PCR || new_measurement)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In other words, the PCR hash is used together with the new measured value to create the new hash.&lt;/p&gt;
&lt;p&gt;You can see the hashes of each PCR on your running TPM (fictitious values):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-console" data-lang="console"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gp"&gt;$&lt;/span&gt; systemd-analyze pcrs
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;NR NAME SHA256
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; 0 platform-code 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; 1 platform-config 123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; 2 external-code 23456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef01
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; 3 external-config 3456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef012
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; 4 boot-loader-code 456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; 5 boot-loader-config 56789abcdef0123456789abcdef0123456789abcdef0123456789abcdef01234
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; 6 host-platform 6789abcdef0123456789abcdef0123456789abcdef0123456789abcdef012345
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; 7 secure-boot-policy 789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; 8 - 89abcdef0123456789abcdef0123456789abcdef0123456789abcdef01234567
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; 9 kernel-initrd 9abcdef0123456789abcdef0123456789abcdef0123456789abcdef012345678
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;10 ima abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;11 kernel-boot 0000000000000000000000000000000000000000000000000000000000000000
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;12 kernel-config 0000000000000000000000000000000000000000000000000000000000000000
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;13 sysexts 0000000000000000000000000000000000000000000000000000000000000000
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;14 shim-policy bcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789a
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;15 system-identity 0000000000000000000000000000000000000000000000000000000000000000
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;16 debug 0000000000000000000000000000000000000000000000000000000000000000
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;17 - ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;18 - ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;19 - ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;20 - ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;21 - ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;22 - ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;23 application-support 0000000000000000000000000000000000000000000000000000000000000000
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Each PCR is independent and is extended freely, without depending on the others. On compatible TPMs there are 24 PCRs;
the &lt;a href="https://uapi-group.org/"&gt;UAPI (Linux Userspace API Group)&lt;/a&gt; in
&lt;a href="https://uapi-group.org/specifications/specs/linux_tpm_pcr_registry/"&gt;its specifications&lt;/a&gt; considers 0–7 to be firmware
and 8–15 to be the range available to the operating system, although the systemd ecosystem also uses specific PCRs for
additional measurements, and PCRs 16–23 are also usable.&lt;/p&gt;
&lt;p&gt;When the computer powers on, all PCRs start out with no value. The firmware then begins extending the PCRs. For example,
PCR 0 depends on the software running in the firmware — what we normally call the BIOS. When you “update the BIOS”,
PCR 0 changes. PCR 1 may change if you replace a hardware component. PCR 4 is tied to the operating system; it measures
the boot loader and additional drivers. And so on.&lt;/p&gt;
&lt;p&gt;PCR 7 depends on the Secure Boot state. Its values are commonly extended using the keys enrolled in Secure Boot, as well
as the Secure Boot Authority. It is this PCR that we will use to unlock the disk, at this moment.&lt;/p&gt;
&lt;p&gt;I will come back to PCRs in the next posts, but it is important to understand what they are for. If you decide to use
what I am proposing in these posts, this knowledge may be useful if you run into trouble.&lt;/p&gt;
&lt;p&gt;You can see all the events that led to PCR extensions by running &lt;code&gt;sudo systemd-pcrlock log&lt;/code&gt;. Using &lt;code&gt;jq&lt;/code&gt;, you can show
only the events that led to PCR 7:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo /run/current-system/systemd/lib/systemd/systemd-pcrlock log --json&lt;span class="o"&gt;=&lt;/span&gt;short 2&amp;gt;/dev/null &lt;span class="p"&gt;|&lt;/span&gt; jq &lt;span class="s1"&gt;&amp;#39;[.log[] | select(.pcr == 7)]&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The result, simplified so it does not get too long, is this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;pcr&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;pcrname&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;secure-boot-policy&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;event&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;efi-variable-driver-config&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;match&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;sha256&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;9f75b6823bff6af1024a4e2036719cdd548d3cbc2bf1de8e7ef4d0ed01f94bf9&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;phase&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;F&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;component&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;description&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Variable: dbx-d719b2cb-3d3a-4596-a3bc-dad00e67656f&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;pcr&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;pcrname&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;secure-boot-policy&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;event&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;efi-variable-authority&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;match&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;sha256&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;f35567246a92b2fcdd2901e4ad2febdfd80173f25527c5a73033bf100a8eb980&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;phase&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;F&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;component&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;description&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Authority: db-d719b2cb-3d3a-4596-a3bc-dad00e67656f&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note that the hash value, stored in the &lt;code&gt;sha256&lt;/code&gt; field, changes with each event. When the TPM receives a request to
decrypt a value, its state must match exactly what was used when the value was encrypted (this is done through TPM
policies). That means a value encrypted early in the boot process may no longer be decryptable at the end of the boot
process, if the PCR has been extended again. This is especially useful for this very reason: allowing a value to be
accessible only at a specific point in the boot sequence, such as during &lt;code&gt;initrd&lt;/code&gt; startup (PCR 11 has measurements that
make this possible).&lt;/p&gt;
&lt;p&gt;Systemd &lt;a href="https://systemd.io/TPM2_PCR_MEASUREMENTS/"&gt;documents&lt;/a&gt; how it uses PCRs, and since nowadays there is practically
no Linux without systemd, it is worth understanding. This document will be useful later, when we look more closely at
PCR 15 (system identity).&lt;/p&gt;
&lt;h3 id="unlocking-the-disk-during-boot"&gt;
 &lt;a href="#unlocking-the-disk-during-boot" class="site-blog-post-header"&gt;
 &lt;span class="site-blog-post-header-text"&gt;Unlocking the disk during boot&lt;/span&gt;
 &lt;i class="fa-solid fa-link site-blog-post-header-paragraph"&gt;&lt;/i&gt;
 &lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;Only one command is needed to make everything happen. In our case, since we have two disks and two partitions, we run
the command once for each of them (you will need to enter your LUKS password for the process to complete):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemd-cryptenroll --tpm2-device&lt;span class="o"&gt;=&lt;/span&gt;auto --tpm2-pcrs&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;7&lt;/span&gt; /dev/disk/by-label/NIXLUKS1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemd-cryptenroll --tpm2-device&lt;span class="o"&gt;=&lt;/span&gt;auto --tpm2-pcrs&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;7&lt;/span&gt; /dev/disk/by-label/NIXLUKS2
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When this command runs, the volume master key is obtained using your password. It is then encrypted (sealed) using the
TPM, and this sealed value is stored in the LUKS volume header. In this case, only PCR 7 is being used to seal the
value, meaning only the Secure Boot state. That means if the Secure Boot state changes (if it is reset, or if a new key
is removed or added), the TPM’s PCR 7 state will also change, and the disk will no longer be decrypted during boot. In
this post, the goal is to tie automatic disk decryption to the Secure Boot state, and that is what we have done.&lt;/p&gt;
&lt;p&gt;You can see the details stored in the LUKS volume header by running the following command after &lt;code&gt;systemd-cryptenroll&lt;/code&gt;
has been executed:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo cryptsetup luksDump /dev/disk/by-label/NIXLUKS1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Notice the &lt;code&gt;Tokens&lt;/code&gt; field, with the first one being &lt;code&gt;systemd-tpm2&lt;/code&gt;, with a &lt;code&gt;Keyslot&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Tokens:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 0: systemd-tpm2
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Keyslot: 1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To see more details about the sealed value, run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo cryptsetup luksDump --dump-json-metadata /dev/disk/by-label/NIXLUKS1 &lt;span class="p"&gt;|&lt;/span&gt; jq -r &lt;span class="s1"&gt;&amp;#39;.tokens.&amp;#34;0&amp;#34;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The result will look something like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;systemd-tpm2&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;keyslots&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;1&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;tpm2-blob&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&amp;lt;a base64 value&amp;gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;tpm2-pcrs&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;tpm2-pcr-bank&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;sha256&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;tpm2-policy-hash&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&amp;lt;a hash&amp;gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;tpm2_srk&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&amp;lt;another base64 value&amp;gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;tpm2-blob&lt;/code&gt; contains the value encrypted by the TPM (plus metadata). Using the tools from the
&lt;a href="https://github.com/tpm2-software/tpm2-tools"&gt;tpm2-tools&lt;/a&gt; package and root access, you could recover the master password
from this value. That is not a security problem: the system is already running and the disk is already decrypted. The
purpose of TPM protection is not to protect a healthy running system from its administrator, but to protect against
integrity violations that happen before, during, and after boot.&lt;/p&gt;
&lt;p&gt;With just these two commands, the TPM will start unlocking both LUKS volumes. Reboot to confirm that it no longer asks
for the password. If it does, inspect the boot logs with &lt;code&gt;sudo journalctl --boot&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="is-it-secure"&gt;
 &lt;a href="#is-it-secure" class="site-blog-post-header"&gt;
 &lt;span class="site-blog-post-header-text"&gt;Is it secure?&lt;/span&gt;
 &lt;i class="fa-solid fa-link site-blog-post-header-paragraph"&gt;&lt;/i&gt;
 &lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;Not yet.&lt;/p&gt;
&lt;p&gt;There are two vulnerabilities, and I will address them in the next posts. Neither is trivial, but someone who
understands how all of this works could gain access to the data in a short amount of time. None of the work done so far
will be lost; we will build on the current solution. The good news is that both issues are easy to fix.&lt;/p&gt;
&lt;p&gt;That said, it is fair assume that most people, including technicians who are not systems penetration experts, would no
longer be able to read the disk of a computer encrypted this way. In other words, sending a laptop for repair with this
configuration would probably not present a risk. But that is still not good enough.&lt;/p&gt;
&lt;p&gt;In the next post we will start closing the gaps.&lt;/p&gt;</description></item><item><title>NixOS: Installation Guide with RAID 1, encryption, and TPM Unlock (part 4 - Secure Boot)</title><link>https://giggio.net/en/blog/nix-os-guia-de-instalacao-com-raid-1-criptografia-e-tpm-unlock-parte-4-secure-boot/</link><pubDate>Thu, 14 May 2026 11:00:00 -0300</pubDate><author>giggio@giggio.net (Giovanni Bassi)</author><guid>https://giggio.net/en/blog/nix-os-guia-de-instalacao-com-raid-1-criptografia-e-tpm-unlock-parte-4-secure-boot/</guid><category>infra</category><description>&lt;p&gt;In the fourth post of our series, we are going to configure Secure Boot to ensure that only trusted operating
systems can be executed.&lt;/p&gt;
&lt;p&gt;This is the fourth post of the series:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://giggio.net/en/blog/nix-os-guia-de-instalacao-com-raid-1-criptografia-e-tpm-unlock-parte-1/"&gt;Preparing the virtual machine and partitioning the disks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://giggio.net/en/blog/nix-os-guia-de-instalacao-com-raid-1-criptografia-e-tpm-unlock-parte-2-disko-luks-e-btrfs/"&gt;Disko, LUKS, and btrfs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://giggio.net/en/blog/nix-os-guia-de-instalacao-com-raid-1-criptografia-e-tpm-unlock-parte-3-instalando-o-so/"&gt;Installing the OS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enabling Secure Boot (this post)&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Secure Boot is a fundamental component for tightening the security, especially when using the TPM to automatically
decrypt the disk. I will explain what it is, what it’s for, and how to implement it in NixOS using Lanzaboote.&lt;/p&gt;
&lt;h3 id="understanding-secure-boot"&gt;
 &lt;a href="#understanding-secure-boot" class="site-blog-post-header"&gt;
 &lt;span class="site-blog-post-header-text"&gt;Understanding Secure Boot&lt;/span&gt;
 &lt;i class="fa-solid fa-link site-blog-post-header-paragraph"&gt;&lt;/i&gt;
 &lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;Secure Boot is a protocol that is part of the UEFI (Unified Extensible Firmware Interface). When enabled, it verifies if
the operating system&amp;rsquo;s bootloader has a valid digital signature recognized by the keys registered in the motherboard&amp;rsquo;s
firmware.&lt;/p&gt;
&lt;p&gt;This prevents boot-level malware (rootkits) or unauthorized operating systems from loading. Additionally, the TPM uses
the Secure Boot state as one of the metrics to decide whether or not to release the disk encryption keys.&lt;/p&gt;
&lt;p&gt;There are three main ways to manage Secure Boot keys:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Factory default keys:&lt;/strong&gt; Usually the Microsoft keys that come with almost every computer;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Custom keys (User Mode):&lt;/strong&gt; You remove the Microsoft keys and install only your own;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hybrid Mode:&lt;/strong&gt; You keep the Microsoft keys (for dual-booting with Windows) and add your own.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If you don&amp;rsquo;t intend to run Windows, the second option is the most restrictive and secure. If you need dual boot, the
third is mandatory. It&amp;rsquo;s worth noting that NixOS does not have a bootloader signed by Microsoft (unlike Ubuntu or
Fedora), so we always need to generate our own keys.&lt;/p&gt;
&lt;p&gt;And why Microsoft keys, specifically? Because they were the first company to push Secure Boot as mandatory, and they
hold the largest share of the PC market.
&lt;a href="https://en.wikipedia.org/wiki/UEFI#Secure_Boot_criticism"&gt;There is quite a bit of controversy regarding this&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The important thing for our setup is knowing that once you define how Secure Boot will be used, it cannot be changed
without breaking the automatic decryption process (which will be done with the help of the TPM). In our case, we will
use the third option (mixing Microsoft keys with our own). If Secure Boot is turned off on the machine or a new platform
key is loaded, the TPM will refuse to decrypt the disk. I’ll explain this in future posts, so for now, what matters is
enabling Secure Boot.&lt;/p&gt;
&lt;h3 id="putting-the-firmware-into-setup-mode"&gt;
 &lt;a href="#putting-the-firmware-into-setup-mode" class="site-blog-post-header"&gt;
 &lt;span class="site-blog-post-header-text"&gt;Putting the Firmware into Setup Mode&lt;/span&gt;
 &lt;i class="fa-solid fa-link site-blog-post-header-paragraph"&gt;&lt;/i&gt;
 &lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;In the first post, we cleared the keys in the VM&amp;rsquo;s boot menu to enter Setup Mode. This is essential: for us to write
our keys via software, the firmware must be &amp;ldquo;open&amp;rdquo; to new signatures.&lt;/p&gt;
&lt;p&gt;Confirm the status by running:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-console" data-lang="console"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gp"&gt;$&lt;/span&gt; sudo bootctl status
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;Secure Boot: disabled (setup)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If &lt;code&gt;disabled (setup)&lt;/code&gt; appears, we are ready to proceed.&lt;/p&gt;
&lt;h3 id="generating-keys-with-sbctl"&gt;
 &lt;a href="#generating-keys-with-sbctl" class="site-blog-post-header"&gt;
 &lt;span class="site-blog-post-header-text"&gt;Generating Keys with sbctl&lt;/span&gt;
 &lt;i class="fa-solid fa-link site-blog-post-header-paragraph"&gt;&lt;/i&gt;
 &lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;We will use &lt;a href="https://github.com/Foxboron/sbctl/"&gt;sbctl&lt;/a&gt; to create and register our keys. Since it isn&amp;rsquo;t installed by
default, let&amp;rsquo;s use &lt;code&gt;nix-shell&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nix-shell -p sbctl
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: In NixOS, you can bring any application into your terminal&amp;rsquo;s context using &lt;code&gt;nix-shell&lt;/code&gt;. With this, the &lt;code&gt;sbctl&lt;/code&gt;
command becomes available in a subshell — to exit, just run &lt;code&gt;exit&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To generate the keys, we will run the &lt;code&gt;create-keys&lt;/code&gt; subcommand:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo sbctl create-keys
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The keys will be generated in &lt;code&gt;/var/lib/sbctl/&lt;/code&gt;. You can see the structure with the &lt;code&gt;tree&lt;/code&gt; command:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-console" data-lang="console"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gp"&gt;$&lt;/span&gt; tree /var/lib/sbctl/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;/var/lib/sbctl/
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;├── GUID
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;└── keys
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; ├── db
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; │   ├── db.key
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; │   └── db.pem
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; ├── KEK
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; │   ├── KEK.key
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; │   └── KEK.pem
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; └── PK
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; ├── PK.key
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt; └── PK.pem
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Install the keys into the machine&amp;rsquo;s firmware with &lt;code&gt;enroll-keys&lt;/code&gt;. This will use the keys we created earlier with &lt;code&gt;sbctl&lt;/code&gt;.
With the &lt;code&gt;--microsoft&lt;/code&gt; argument, Microsoft&amp;rsquo;s platform keys will also be installed:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo sbctl enroll-keys --microsoft
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Verify that Secure Boot has been re-enabled with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo bootctl status
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It should show &lt;code&gt;Secure Boot: enabled (user)&lt;/code&gt;. It might not show as enabled yet until the next boot, showing up as
&lt;code&gt;Secure Boot: disabled&lt;/code&gt;, but without &lt;code&gt;setup&lt;/code&gt;. But don&amp;rsquo;t reboot just yet!&lt;/p&gt;
&lt;h3 id="signing-the-boot-with-lanzaboote"&gt;
 &lt;a href="#signing-the-boot-with-lanzaboote" class="site-blog-post-header"&gt;
 &lt;span class="site-blog-post-header-text"&gt;Signing the Boot with Lanzaboote&lt;/span&gt;
 &lt;i class="fa-solid fa-link site-blog-post-header-paragraph"&gt;&lt;/i&gt;
 &lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;At this point, if you restart the machine, NixOS will no longer boot, as the NixOS bootloader is not yet signed with the
Secure Boot keys we created in the previous step. That’s where &lt;a href="https://github.com/nix-community/lanzaboote"&gt;Lanzaboote&lt;/a&gt;
comes in. It automates the signing of NixOS generations. It replaces the default &lt;code&gt;systemd-boot&lt;/code&gt; manager with one that
handles the keys generated by &lt;code&gt;sbctl&lt;/code&gt;. Once enabled, whenever a new bootloader is created in the &lt;code&gt;/boot&lt;/code&gt; directory, it
will be signed with the keys located in &lt;code&gt;/var/lib/sbctl&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To enable Lanzaboote and then sign the files, first go to the configuration directory that was copied in previous posts
to &lt;code&gt;/etc/nixos&lt;/code&gt;, and check out the correct commit. Be careful not to forget the &lt;code&gt;git checkout&lt;/code&gt;, or it won&amp;rsquo;t work:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /etc/nixos
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# ensuring the current user owns the files:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo chown -R giggio:users .
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# checkout with the message &amp;#34;Enable lanzaboote&amp;#34;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git checkout dab0fd4
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The change in your &lt;code&gt;configuration.nix&lt;/code&gt; disables the native &lt;code&gt;systemd-boot&lt;/code&gt; and activates &lt;code&gt;lanzaboote&lt;/code&gt;, pointing to the
keys directory:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-nix" data-lang="nix"&gt;&lt;span class="line hl"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;boot&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;systemd-boot&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;enable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;boot&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lanzaboote&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line hl"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;enable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;pkiBundle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;/var/lib/sbctl&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The Lanzaboote configuration was already present; it was just disabled. And with it enabled, &lt;code&gt;systemd-boot&lt;/code&gt; can be
disabled. Note also that the keys directory, defined in the &lt;code&gt;pkiBundle&lt;/code&gt; attribute, is already correctly pointed to
&lt;code&gt;/var/lib/sbctl&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s all; now just install the new configurations, which take effect immediately and will also be effective on the
next boot:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo nixos-rebuild switch
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="validating-the-signature"&gt;
 &lt;a href="#validating-the-signature" class="site-blog-post-header"&gt;
 &lt;span class="site-blog-post-header-text"&gt;Validating the Signature&lt;/span&gt;
 &lt;i class="fa-solid fa-link site-blog-post-header-paragraph"&gt;&lt;/i&gt;
 &lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;To ensure Lanzaboote did its job and signed the &lt;code&gt;.efi&lt;/code&gt; binaries, run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-console" data-lang="console"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gp"&gt;$&lt;/span&gt; sudo sbctl verify
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;Verifying file database and EFI images in /boot...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;✓ /boot/EFI/BOOT/BOOTX64.EFI is signed
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;✓ /boot/EFI/Linux/nixos-generation-1-xxx.efi is signed
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;✓ /boot/EFI/Linux/nixos-generation-2-yyy.efi is signed
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;✗ /boot/EFI/nixos/kernel-7.0-zzz.efi is not signed
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="go"&gt;✓ /boot/EFI/systemd/systemd-bootx64.efi is signed
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Note about the Kernel:&lt;/strong&gt; It is normal to see an &lt;code&gt;✗&lt;/code&gt; on the isolated kernel file. What matters are the files inside
&lt;code&gt;/boot/EFI/&lt;/code&gt; and the boot managers. Lanzaboote creates a &lt;strong&gt;Unified Kernel Image (UKI)&lt;/strong&gt;, which bundles the kernel and
the initrd into a single signed executable that the UEFI can run directly.&lt;/p&gt;
&lt;p&gt;Now you can reboot. If everything went well, the system will come up normally and &lt;code&gt;bootctl status&lt;/code&gt; will confirm: &lt;code&gt;Secure Boot: enabled (user)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The machine still asks for the password to decrypt the disk. This is expected, as we haven&amp;rsquo;t yet implemented the
structure for automatic decryption with the TPM.&lt;/p&gt;
&lt;h3 id="troubleshooting-secure-boot"&gt;
 &lt;a href="#troubleshooting-secure-boot" class="site-blog-post-header"&gt;
 &lt;span class="site-blog-post-header-text"&gt;Troubleshooting Secure Boot&lt;/span&gt;
 &lt;i class="fa-solid fa-link site-blog-post-header-paragraph"&gt;&lt;/i&gt;
 &lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;If something goes wrong and the VM won&amp;rsquo;t start, you can reset the NVRAM (the VM&amp;rsquo;s &amp;ldquo;BIOS&amp;rdquo;). On your host, turn off the VM
and run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# on the host:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;virsh start &amp;lt;vm_name&amp;gt; --reset-nvram
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This will start the virtual machine normally, but with all the firmware boot settings lost, including Secure Boot
settings.&lt;/p&gt;
&lt;p&gt;The following commands will re-apply the boot settings to the firmware&amp;rsquo;s non-volatile memory and the disk:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# on the vm:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# registering platform keys in the firmware again:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo sbctl enroll-keys --microsoft
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# installing the boot menu option:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo bootctl install
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# re-signing the UKIs:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo nixos-rebuild switch
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Why run switch again&lt;/strong&gt;: When running &lt;code&gt;bootctl install&lt;/code&gt;, the files &lt;code&gt;/boot/EFI/systemd/systemd-bootx64.efi&lt;/code&gt; and
&lt;code&gt;/boot/EFI/BOOT/BOOTX64.EFI&lt;/code&gt; will not be signed, so it is necessary to run &lt;code&gt;switch&lt;/code&gt; so that these two files become
signed again.&lt;/p&gt;
&lt;h3 id="declarative-approach"&gt;
 &lt;a href="#declarative-approach" class="site-blog-post-header"&gt;
 &lt;span class="site-blog-post-header-text"&gt;Declarative Approach&lt;/span&gt;
 &lt;i class="fa-solid fa-link site-blog-post-header-paragraph"&gt;&lt;/i&gt;
 &lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;Lanzaboote allows generating platform keys automatically via Nix config:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-nix" data-lang="nix"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;boot&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lanzaboote&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;autoGenerateKeys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;enable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;autoEnrollKeys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;enable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;autoReboot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is described in more detail in the
&lt;a href="https://github.com/nix-community/lanzaboote/blob/079c608988c2747db3902c9de033572cd50e8656/docs/explanation/automatic-provisioning.md"&gt;docs on automatic provisioning&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;While practical for testing, I don&amp;rsquo;t recommend using this in production systems. The ideal approach is to generate keys
manually (as I demonstrated here) and store them securely somewhere. A good option is to use
&lt;a href="https://github.com/Mic92/sops-nix/"&gt;sops-nix&lt;/a&gt;, keeping the keys encrypted within the repository itself. The
inconvenience would be during application, where you would always need the keys or devices to decrypt the &lt;code&gt;sops&lt;/code&gt; secrets
at every &lt;code&gt;nixos-rebuild&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="next-up-using-tpm-to-decrypt-the-disk"&gt;
 &lt;a href="#next-up-using-tpm-to-decrypt-the-disk" class="site-blog-post-header"&gt;
 &lt;span class="site-blog-post-header-text"&gt;Next Up: Using TPM to Decrypt the Disk&lt;/span&gt;
 &lt;i class="fa-solid fa-link site-blog-post-header-paragraph"&gt;&lt;/i&gt;
 &lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;Secure Boot is active. The disk is encrypted. But we still have to type the LUKS password at every boot.&lt;/p&gt;
&lt;p&gt;If someone tries to start another operating system, it will need to be signed with your platform key or Microsoft&amp;rsquo;s. You
can make the system more secure by removing the &lt;code&gt;--microsoft&lt;/code&gt; option from the &lt;code&gt;enroll-keys&lt;/code&gt; command and not allowing any
other operating system.&lt;/p&gt;
&lt;p&gt;In the next post, we will configure the &lt;strong&gt;TPM (Trusted Platform Module)&lt;/strong&gt; so that it &amp;ldquo;measures&amp;rdquo; the Secure Boot state
and releases the encryption key automatically if the system hasn&amp;rsquo;t been tampered with. Maximum security with
convenience.&lt;/p&gt;
&lt;p&gt;See you then!&lt;/p&gt;</description></item></channel></rss>