Merge pull request #209156 from pwaller/issue-114594

nixos/grub: Name initrd-secrets by system, not by initrd

Changed files
+81 -6
nixos
modules
system
boot
loader
virtualisation
tests
+4 -3
nixos/modules/system/boot/loader/grub/install-grub.pl
···
# 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;
···
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);
+18 -3
nixos/modules/virtualisation/qemu-vm.nix
···
${lib.optionalString cfg.useBootLoader
''
-
# Create a writable copy/snapshot of the boot disk.
-
# A writable boot disk can be booted from automatically.
-
${qemu}/bin/qemu-img create -f qcow2 -F qcow2 -b ${bootDisk}/disk.img "$TMPDIR/disk.img"
+
if ${if !cfg.persistBootDevice then "true" else "! test -e $TMPDIR/disk.img"}; then
+
# Create a writable copy/snapshot of the boot disk.
+
# A writable boot disk can be booted from automatically.
+
${qemu}/bin/qemu-img create -f qcow2 -F qcow2 -b ${bootDisk}/disk.img "$TMPDIR/disk.img"
+
fi
NIX_EFI_VARS=$(readlink -f "''${NIX_EFI_VARS:-${cfg.efiVars}}")
···
lib.mdDoc ''
The disk to be used for the root filesystem.
'';
+
};
+
+
virtualisation.persistBootDevice =
+
mkOption {
+
type = types.bool;
+
default = false;
+
description =
+
lib.mdDoc ''
+
If useBootLoader is specified, whether to recreate the boot device
+
on each instantiaton or allow it to persist.
+
'';
};
virtualisation.emptyDiskImages =
···
# * The disks are attached in `virtualisation.qemu.drives`.
# Their order makes them appear as devices `a`, `b`, etc.
# * `fileSystems."/boot"` is adjusted to be on device `b`.
+
# * The disk.img is recreated each time the VM is booted unless
+
# virtualisation.persistBootDevice is set.
# If `useBootLoader`, GRUB goes to the second disk, see
# note [Disk layout with `useBootLoader`].
+1
nixos/tests/all-tests.nix
···
initrd-network-ssh = handleTest ./initrd-network-ssh {};
initrdNetwork = handleTest ./initrd-network.nix {};
initrd-secrets = handleTest ./initrd-secrets.nix {};
+
initrd-secrets-changing = handleTest ./initrd-secrets-changing.nix {};
input-remapper = handleTest ./input-remapper.nix {};
inspircd = handleTest ./inspircd.nix {};
installer = handleTest ./installer.nix {};
+58
nixos/tests/initrd-secrets-changing.nix
···
+
{ system ? builtins.currentSystem
+
, config ? {}
+
, pkgs ? import ../.. { inherit system config; }
+
, lib ? pkgs.lib
+
, testing ? import ../lib/testing-python.nix { inherit system pkgs; }
+
}:
+
+
let
+
secret1InStore = pkgs.writeText "topsecret" "iamasecret1";
+
secret2InStore = pkgs.writeText "topsecret" "iamasecret2";
+
in
+
+
testing.makeTest {
+
name = "initrd-secrets-changing";
+
+
nodes.machine = { ... }: {
+
virtualisation.useBootLoader = true;
+
virtualisation.persistBootDevice = true;
+
+
boot.loader.grub.device = "/dev/vda";
+
+
boot.initrd.secrets = {
+
"/test" = secret1InStore;
+
"/run/keys/test" = secret1InStore;
+
};
+
boot.initrd.postMountCommands = "cp /test /mnt-root/secret-from-initramfs";
+
+
specialisation.secrets2System.configuration = {
+
boot.initrd.secrets = lib.mkForce {
+
"/test" = secret2InStore;
+
"/run/keys/test" = secret2InStore;
+
};
+
};
+
};
+
+
testScript = ''
+
start_all()
+
+
machine.wait_for_unit("multi-user.target")
+
print(machine.succeed("cat /run/keys/test"))
+
machine.succeed(
+
"cmp ${secret1InStore} /secret-from-initramfs",
+
"cmp ${secret1InStore} /run/keys/test",
+
)
+
# Select the second boot entry corresponding to the specialisation secrets2System.
+
machine.succeed("grub-reboot 1")
+
machine.shutdown()
+
+
with subtest("Check that the specialisation's secrets are distinct despite identical kernels"):
+
machine.wait_for_unit("multi-user.target")
+
print(machine.succeed("cat /run/keys/test"))
+
machine.succeed(
+
"cmp ${secret2InStore} /secret-from-initramfs",
+
"cmp ${secret2InStore} /run/keys/test",
+
)
+
machine.shutdown()
+
'';
+
}