diff --git a/nixos/modules/system/boot/luksroot.nix b/nixos/modules/system/boot/luksroot.nix index b8f36538e70..cc320a04c70 100644 --- a/nixos/modules/system/boot/luksroot.nix +++ b/nixos/modules/system/boot/luksroot.nix @@ -146,6 +146,7 @@ let csopen = "cryptsetup luksOpen ${dev.device} ${dev.name}" + optionalString dev.allowDiscards " --allow-discards" + optionalString dev.bypassWorkqueues " --perf-no_read_workqueue --perf-no_write_workqueue" + + optionalString dev.disableKeyring " --disable-keyring" + optionalString (dev.header != null) " --header=${dev.header}"; cschange = "cryptsetup luksChangeKey ${dev.device} ${optionalString (dev.header != null) "--header=${dev.header}"}"; fido2luksCredentials = dev.fido2.credentials ++ optional (dev.fido2.credential != null) dev.fido2.credential; @@ -243,6 +244,26 @@ let do_open_passphrase fi fi + '' else if (dev.masterKeyFile != null) then '' + if wait_target "key file" ${dev.masterKeyFile}; then + ${csopen} --master-key-file=${dev.masterKeyFile} + cs_status=$? + if [ $cs_status -ne 0 ]; then + echo "Key File ${dev.masterKeyFile} failed!" + if ! try_empty_passphrase; then + ${if dev.fallbackToPassword then "echo" else "die"} "${dev.masterKeyFile} is unavailable" + echo " - failing back to interactive password prompt" + do_open_passphrase + fi + fi + else + # If the key file never shows up we should also try the empty passphrase + if ! try_empty_passphrase; then + ${if dev.fallbackToPassword then "echo" else "die"} "${dev.masterKeyFile} is unavailable" + echo " - failing back to interactive password prompt" + do_open_passphrase + fi + fi '' else '' if ! try_empty_passphrase; then do_open_passphrase @@ -625,6 +646,15 @@ in ''; }; + masterKeyFile = mkOption { + default = null; + type = types.nullOr types.str; + description = lib.mdDoc '' + The name of the file (can be a raw device or a partition) that + should be used as the master decryption key for the encrypted device. + ''; + }; + tryEmptyPassphrase = mkOption { default = false; type = types.bool; @@ -700,6 +730,15 @@ in ''; }; + disableKeyring = mkOption { + default = false; + type = types.bool; + description = lib.mdDoc '' + Disables using the kernel keyring for LUKS2 disks. + This is already the default behavior for LUKS1 + ''; + }; + fallbackToPassword = mkOption { default = false; type = types.bool; diff --git a/nixos/modules/tasks/auto-upgrade.nix b/nixos/modules/tasks/auto-upgrade.nix index 29e3e313336..050bf09c208 100644 --- a/nixos/modules/tasks/auto-upgrade.nix +++ b/nixos/modules/tasks/auto-upgrade.nix @@ -4,7 +4,8 @@ with lib; let cfg = config.system.autoUpgrade; -in { +in +{ options = { @@ -22,7 +23,7 @@ in { }; operation = mkOption { - type = types.enum ["switch" "boot"]; + type = types.enum [ "switch" "boot" ]; default = "switch"; example = "boot"; description = lib.mdDoc '' @@ -86,14 +87,14 @@ in { ''; }; - allowReboot = mkOption { + allowKexec = mkOption { default = false; type = types.bool; description = lib.mdDoc '' - Reboot the system into the new generation instead of a switch + kexec the system into the new generation instead of a switch if the new generation uses a different kernel, kernel modules or initrd than the booted system. - See {option}`rebootWindow` for configuring the times at which a reboot is allowed. + See {option}`kexecWindow` for configuring the times at which a kexec is allowed. ''; }; @@ -109,25 +110,25 @@ in { ''; }; - rebootWindow = mkOption { + kexecWindow = mkOption { description = lib.mdDoc '' Define a lower and upper time value (in HH:MM format) which - constitute a time window during which reboots are allowed after an upgrade. - This option only has an effect when {option}`allowReboot` is enabled. - The default value of `null` means that reboots are allowed at any time. + constitute a time window during which kexecs are allowed after an upgrade. + This option only has an effect when {option}`allowKexec` is enabled. + The default value of `null` means that kexecs are allowed at any time. ''; default = null; example = { lower = "01:00"; upper = "05:00"; }; type = with types; nullOr (submodule { options = { lower = mkOption { - description = lib.mdDoc "Lower limit of the reboot window"; + description = lib.mdDoc "Lower limit of the kexec window"; type = types.strMatching "[[:digit:]]{2}:[[:digit:]]{2}"; example = "01:00"; }; upper = mkOption { - description = lib.mdDoc "Upper limit of the reboot window"; + description = lib.mdDoc "Upper limit of the kexec window"; type = types.strMatching "[[:digit:]]{2}:[[:digit:]]{2}"; example = "05:00"; }; @@ -165,12 +166,12 @@ in { }]; system.autoUpgrade.flags = (if cfg.flake == null then - [ "--no-build-output" ] ++ optionals (cfg.channel != null) [ - "-I" - "nixpkgs=${cfg.channel}/nixexprs.tar.xz" - ] - else - [ "--flake ${cfg.flake}" ]); + [ "--no-build-output" ] ++ optionals (cfg.channel != null) [ + "-I" + "nixpkgs=${cfg.channel}/nixexprs.tar.xz" + ] + else + [ "--flake ${cfg.flake}" ]); systemd.services.nixos-upgrade = { description = "NixOS Upgrade"; @@ -195,54 +196,56 @@ in { config.programs.ssh.package ]; - script = let - nixos-rebuild = "${config.system.build.nixos-rebuild}/bin/nixos-rebuild"; - date = "${pkgs.coreutils}/bin/date"; - readlink = "${pkgs.coreutils}/bin/readlink"; - shutdown = "${config.systemd.package}/bin/shutdown"; - upgradeFlag = optional (cfg.channel == null) "--upgrade"; - in if cfg.allowReboot then '' - ${nixos-rebuild} boot ${toString (cfg.flags ++ upgradeFlag)} - booted="$(${readlink} /run/booted-system/{initrd,kernel,kernel-modules})" - built="$(${readlink} /nix/var/nix/profiles/system/{initrd,kernel,kernel-modules})" - - ${optionalString (cfg.rebootWindow != null) '' - current_time="$(${date} +%H:%M)" - - lower="${cfg.rebootWindow.lower}" - upper="${cfg.rebootWindow.upper}" - - if [[ "''${lower}" < "''${upper}" ]]; then - if [[ "''${current_time}" > "''${lower}" ]] && \ - [[ "''${current_time}" < "''${upper}" ]]; then - do_reboot="true" + script = + let + nixos-rebuild = "${config.system.build.nixos-rebuild}/bin/nixos-rebuild"; + date = "${pkgs.coreutils}/bin/date"; + readlink = "${pkgs.coreutils}/bin/readlink"; + systemctl_kexec = "${config.systemd.package}/bin/systemctl kexec"; + upgradeFlag = optional (cfg.channel == null) "--upgrade"; + in + if cfg.allowKexec then '' + ${nixos-rebuild} boot ${toString (cfg.flags ++ upgradeFlag)} + booted="$(${readlink} /run/booted-system/{initrd,kernel,kernel-modules})" + built="$(${readlink} /nix/var/nix/profiles/system/{initrd,kernel,kernel-modules})" + + ${optionalString (cfg.kexecWindow != null) '' + current_time="$(${date} +%H:%M)" + + lower="${cfg.kexecWindow.lower}" + upper="${cfg.kexecWindow.upper}" + + if [[ "''${lower}" < "''${upper}" ]]; then + if [[ "''${current_time}" > "''${lower}" ]] && \ + [[ "''${current_time}" < "''${upper}" ]]; then + do_kexec="true" + else + do_kexec="false" + fi else - do_reboot="false" + # lower > upper, so we are crossing midnight (e.g. lower=23h, upper=6h) + # we want to reboot if cur > 23h or cur < 6h + if [[ "''${current_time}" < "''${upper}" ]] || \ + [[ "''${current_time}" > "''${lower}" ]]; then + do_kexec="true" + else + do_kexec="false" + fi fi + ''} + + if [ "''${booted}" = "''${built}" ]; then + ${nixos-rebuild} ${cfg.operation} ${toString cfg.flags} + ${optionalString (cfg.kexecWindow != null) '' + elif [ "''${do_kexec}" != true ]; then + echo "Outside of configured kexec window, skipping." + ''} else - # lower > upper, so we are crossing midnight (e.g. lower=23h, upper=6h) - # we want to reboot if cur > 23h or cur < 6h - if [[ "''${current_time}" < "''${upper}" ]] || \ - [[ "''${current_time}" > "''${lower}" ]]; then - do_reboot="true" - else - do_reboot="false" - fi + ${systemctl_kexec} fi - ''} - - if [ "''${booted}" = "''${built}" ]; then - ${nixos-rebuild} ${cfg.operation} ${toString cfg.flags} - ${optionalString (cfg.rebootWindow != null) '' - elif [ "''${do_reboot}" != true ]; then - echo "Outside of configured reboot window, skipping." - ''} - else - ${shutdown} -r +1 - fi - '' else '' - ${nixos-rebuild} ${cfg.operation} ${toString (cfg.flags ++ upgradeFlag)} - ''; + '' else '' + ${nixos-rebuild} ${cfg.operation} ${toString (cfg.flags ++ upgradeFlag)} + ''; startAt = cfg.dates;