summary refs log tree commit diff
path: root/nixos/modules/system/boot/loader
diff options
context:
space:
mode:
authorPeter Waller <p@pwaller.net>2023-01-05 12:28:32 +0000
committerPeter Waller <p@pwaller.net>2023-01-21 17:19:26 +0000
commit678eed323ffd90117472cd432ebe85dddaff07f1 (patch)
treed04c5d9c342d7eadb8fc5db8e7e57989d530178a /nixos/modules/system/boot/loader
parent0fe643128c5c67a0549a6d27cc34da4702605ed9 (diff)
downloadnixpkgs-678eed323ffd90117472cd432ebe85dddaff07f1.tar
nixpkgs-678eed323ffd90117472cd432ebe85dddaff07f1.tar.gz
nixpkgs-678eed323ffd90117472cd432ebe85dddaff07f1.tar.bz2
nixpkgs-678eed323ffd90117472cd432ebe85dddaff07f1.tar.lz
nixpkgs-678eed323ffd90117472cd432ebe85dddaff07f1.tar.xz
nixpkgs-678eed323ffd90117472cd432ebe85dddaff07f1.tar.zst
nixpkgs-678eed323ffd90117472cd432ebe85dddaff07f1.zip
nixos/grub: Name initrd-secrets by system, not by initrd
Previously, secrets were named according to the initrd they were
associated with. This created a problem: If secrets were changed whilst
the initrd remained the same, there were two versions of the secrets
with one initrd. The result was that only one version of the secrets would
by recorded into the /boot partition and get used. AFAICT this would
only be the oldest version of the secrets for the given initrd version.

This manifests as #114594, which I found frustrating while trying to use
initrd secrets for the first time. While developing the secrets I found
I could not get new versions of the secrets to take effect.
Additionally, it's a nasty issue to run into if you had cause to change
the initrd secrets for credential rotation, etc, if you change them and
discover you cannot, or alternatively that you can't roll back as you
would expect.

Additional changes in this patch.

* Add a regression test that switching to another grub configuration
  with the alternate secrets works. This test relies on the fact that it
  is not changing the initrd. I have checked that the test fails if I
  undo my change.

* Persist the useBootLoader disk state, similarly to other boot state.
  * I had to do this, otherwise I could not find a route to testing the
    alternate boot configuration. I did attempt a few different ways of
    testing this, including directly running install-grub.pl, but what
    I've settled on is most like what a user would do and avoids
    depending on lots of internal details.
  * Making tests that test the boot are a bit tricky (see hibernate.nix
    and installer.nix for inspiration), I found that in addition to
    having to copy quite a bit of code I still couldn't get things to
    work as desired since the bootloader state was being clobbered.

My change to persist the useBootLoader state could break things,
conceptually. I need some help here discovering if that is the case,
possibly by letting this run through a staging CI if there is one.

Fix #114594.

cc potential reviewers:

@lopsided98 (original implementer) @joachifm (original reviewer),
@wkennington (numerous fixes to grub-install.pl), @lheckemann (wrote
original secrets test).
Diffstat (limited to 'nixos/modules/system/boot/loader')
-rw-r--r--nixos/modules/system/boot/loader/grub/install-grub.pl7
1 files changed, 4 insertions, 3 deletions
diff --git a/nixos/modules/system/boot/loader/grub/install-grub.pl b/nixos/modules/system/boot/loader/grub/install-grub.pl
index d5f019423b6..54e267ecf97 100644
--- a/nixos/modules/system/boot/loader/grub/install-grub.pl
+++ b/nixos/modules/system/boot/loader/grub/install-grub.pl
@@ -450,8 +450,9 @@ sub addEntry {
 
     # Include second initrd with secrets
     if (-e -x "$path/append-initrd-secrets") {
-        my $initrdName = basename($initrd);
-        my $initrdSecretsPath = "$bootPath/kernels/$initrdName-secrets";
+        # Name the initrd secrets after the system from which they're derived.
+        my $systemName = basename(Cwd::abs_path("$path"));
+        my $initrdSecretsPath = "$bootPath/kernels/$systemName-secrets";
 
         mkpath(dirname($initrdSecretsPath), 0, 0755);
         my $oldUmask = umask;
@@ -463,7 +464,7 @@ sub addEntry {
         if (-e $initrdSecretsPathTemp && ! -z _) {
             rename $initrdSecretsPathTemp, $initrdSecretsPath or die "failed to move initrd secrets into place: $!\n";
             $copied{$initrdSecretsPath} = 1;
-            $initrd .= " " . ($grubBoot->path eq "/" ? "" : $grubBoot->path) . "/kernels/$initrdName-secrets";
+            $initrd .= " " . ($grubBoot->path eq "/" ? "" : $grubBoot->path) . "/kernels/$systemName-secrets";
         } else {
             unlink $initrdSecretsPathTemp;
             rmdir dirname($initrdSecretsPathTemp);