diff --git a/nixos/modules/system/activation/top-level.nix b/nixos/modules/system/activation/top-level.nix index 84c23bed3e3..e9897cc01b6 100644 --- a/nixos/modules/system/activation/top-level.nix +++ b/nixos/modules/system/activation/top-level.nix @@ -53,6 +53,8 @@ let ln -s ${config.system.build.initialRamdisk}/initrd $out/initrd + ln -s ${config.system.build.initialRamdiskSecretAppender}/bin/append-initrd-secrets $out + ln -s ${config.hardware.firmware}/lib/firmware $out/firmware ''} diff --git a/nixos/modules/system/boot/stage-1-init.sh b/nixos/modules/system/boot/stage-1-init.sh index f0699ad9832..c75e637124a 100644 --- a/nixos/modules/system/boot/stage-1-init.sh +++ b/nixos/modules/system/boot/stage-1-init.sh @@ -8,6 +8,14 @@ export LD_LIBRARY_PATH=@extraUtils@/lib export PATH=@extraUtils@/bin ln -s @extraUtils@/bin /bin +# Copy the secrets to their needed location +if [ -d "@extraUtils@/secrets" ]; then + for secret in $(cd "@extraUtils@/secrets"; find . -type f); do + mkdir -p $(dirname "/$secret") + ln -s "@extraUtils@/secrets/$secret" "$secret" + done +fi + # Stop LVM complaining about fd3 export LVM_SUPPRESS_FD_WARNINGS=true diff --git a/nixos/modules/system/boot/stage-1.nix b/nixos/modules/system/boot/stage-1.nix index 61def24efd8..e3a3b6f88cf 100644 --- a/nixos/modules/system/boot/stage-1.nix +++ b/nixos/modules/system/boot/stage-1.nix @@ -82,6 +82,17 @@ let copy_bin_and_libs ${pkgs.e2fsprogs}/sbin/resize2fs ''} + # Copy secrets if needed. + ${optionalString (!config.boot.loader.supportsInitrdSecrets) + (concatStringsSep "\n" (mapAttrsToList (dest: source: + let source' = if source == null then dest else source; in + '' + mkdir -p $(dirname "$out/secrets/${dest}") + cp -a ${source'} "$out/secrets/${dest}" + '' + ) config.boot.initrd.secrets)) + } + ${config.boot.initrd.extraUtilsCommands} # Copy ld manually since it isn't detected correctly @@ -242,6 +253,52 @@ let ]; }; + # Script to add secret files to the initrd at bootloader update time + initialRamdiskSecretAppender = + pkgs.writeScriptBin "append-initrd-secrets" + '' + #!${pkgs.bash}/bin/bash -e + function usage { + echo "USAGE: $0 INITRD_FILE" >&2 + echo "Appends this configuration's secrets to INITRD_FILE" >&2 + } + + if [ $# -ne 1 ]; then + usage + exit 1 + fi + + if [ "$1"x = "--helpx" ]; then + usage + exit 0 + fi + + ${lib.optionalString (config.boot.initrd.secrets == {}) + "exit 0"} + + export PATH=${pkgs.coreutils}/bin:${pkgs.cpio}/bin:${pkgs.gzip}/bin:${pkgs.findutils}/bin + + function cleanup { + if [ -n "$tmp" -a -d "$tmp" ]; then + rm -fR "$tmp" + fi + } + trap cleanup EXIT + + tmp=$(mktemp -d initrd-secrets.XXXXXXXXXX) + + ${lib.concatStringsSep "\n" (mapAttrsToList (dest: source: + let source' = if source == null then dest else toString source; in + '' + mkdir -p $(dirname "$tmp/${dest}") + cp -a ${source'} "$tmp/${dest}" + '' + ) config.boot.initrd.secrets) + } + + (cd "$tmp" && find . | cpio -H newc -o) | gzip >>"$1" + ''; + in { @@ -370,6 +427,25 @@ in example = "xz"; }; + boot.initrd.secrets = mkOption + { internal = true; + default = {}; + type = types.attrsOf (types.nullOr types.path); + description = + '' + Secrets to append to the initrd. The attribute name is the + path the secret should have inside the initrd, the value + is the path it should be copied from (or null for the same + path inside and out). + ''; + example = literalExample + '' + { "/etc/dropbear/dropbear_rsa_host_key" = + ./secret-dropbear-key; + } + ''; + }; + boot.initrd.supportedFilesystems = mkOption { default = [ ]; example = [ "btrfs" ]; @@ -377,6 +453,18 @@ in description = "Names of supported filesystem types in the initial ramdisk."; }; + boot.loader.supportsInitrdSecrets = mkOption + { internal = true; + default = false; + type = types.bool; + description = + '' + Whether the bootloader setup runs append-initrd-secrets. + If not, any needed secrets must be copied into the initrd + and thus added to the store. + ''; + }; + fileSystems = mkOption { options.neededForBoot = mkOption { default = false; @@ -404,9 +492,8 @@ in } ]; - system.build.bootStage1 = bootStage1; - system.build.initialRamdisk = initialRamdisk; - system.build.extraUtils = extraUtils; + system.build = + { inherit bootStage1 initialRamdisk initialRamdiskSecretAppender extraUtils; }; system.requiredKernelConfig = with config.lib.kernelConfig; [ (isYes "TMPFS")