diff options
Diffstat (limited to 'nixos/modules')
-rw-r--r-- | nixos/modules/config/mysql.nix | 57 | ||||
-rw-r--r-- | nixos/modules/module-list.nix | 2 | ||||
-rw-r--r-- | nixos/modules/programs/joycond-cemuhook.nix | 17 | ||||
-rw-r--r-- | nixos/modules/programs/oddjobd.nix | 7 | ||||
-rw-r--r-- | nixos/modules/programs/screen.nix | 38 | ||||
-rw-r--r-- | nixos/modules/services/backup/postgresql-backup.nix | 5 | ||||
-rw-r--r-- | nixos/modules/services/desktops/ayatana-indicators.nix | 58 | ||||
-rw-r--r-- | nixos/modules/services/hardware/thinkfan.nix | 2 | ||||
-rw-r--r-- | nixos/modules/services/home-automation/home-assistant.nix | 4 | ||||
-rw-r--r-- | nixos/modules/services/matrix/appservice-irc.nix | 2 | ||||
-rw-r--r-- | nixos/modules/services/misc/preload.nix | 2 | ||||
-rw-r--r-- | nixos/modules/services/web-apps/netbox.nix | 2 | ||||
-rw-r--r-- | nixos/modules/services/x11/desktop-managers/cinnamon.nix | 3 | ||||
-rw-r--r-- | nixos/modules/system/boot/clevis.md | 51 | ||||
-rw-r--r-- | nixos/modules/system/boot/clevis.nix | 107 | ||||
-rw-r--r-- | nixos/modules/system/boot/luksroot.nix | 48 | ||||
-rw-r--r-- | nixos/modules/tasks/filesystems/bcachefs.nix | 10 | ||||
-rw-r--r-- | nixos/modules/tasks/filesystems/zfs.nix | 13 |
18 files changed, 372 insertions, 56 deletions
diff --git a/nixos/modules/config/mysql.nix b/nixos/modules/config/mysql.nix index 95c9ba76663e..4f72d22c4f0e 100644 --- a/nixos/modules/config/mysql.nix +++ b/nixos/modules/config/mysql.nix @@ -6,6 +6,8 @@ let cfg = config.users.mysql; in { + meta.maintainers = [ maintainers.netali ]; + options = { users.mysql = { enable = mkEnableOption (lib.mdDoc "Authentication against a MySQL/MariaDB database"); @@ -358,7 +360,7 @@ in user = "root"; group = "root"; mode = "0600"; - # password will be added from password file in activation script + # password will be added from password file in systemd oneshot text = '' users.host=${cfg.host} users.db_user=${cfg.user} @@ -423,34 +425,45 @@ in mode = "0600"; user = config.services.nscd.user; group = config.services.nscd.group; - # password will be added from password file in activation script + # password will be added from password file in systemd oneshot text = '' username ${cfg.user} ''; }; - # preStart script to append the password from the password file - # to the configuration files. It also fixes the owner of the - # libnss-mysql-root.cfg because it is changed to root after the - # password is appended. - systemd.services.mysql.preStart = '' - if [[ -r ${cfg.passwordFile} ]]; then - org_umask=$(umask) - umask 0077 + systemd.services.mysql-auth-pw-init = { + description = "Adds the mysql password to the mysql auth config files"; + + before = [ "nscd.service" ]; + wantedBy = [ "multi-user.target" ]; + + serviceConfig = { + Type = "oneshot"; + User = "root"; + Group = "root"; + }; - conf_nss="$(mktemp)" - cp /etc/libnss-mysql-root.cfg $conf_nss - printf 'password %s\n' "$(cat ${cfg.passwordFile})" >> $conf_nss - mv -fT "$conf_nss" /etc/libnss-mysql-root.cfg - chown ${config.services.nscd.user}:${config.services.nscd.group} /etc/libnss-mysql-root.cfg + restartTriggers = [ + config.environment.etc."security/pam_mysql.conf".source + config.environment.etc."libnss-mysql.cfg".source + config.environment.etc."libnss-mysql-root.cfg".source + ]; - conf_pam="$(mktemp)" - cp /etc/security/pam_mysql.conf $conf_pam - printf 'users.db_passwd=%s\n' "$(cat ${cfg.passwordFile})" >> $conf_pam - mv -fT "$conf_pam" /etc/security/pam_mysql.conf + script = '' + if [[ -r ${cfg.passwordFile} ]]; then + umask 0077 + conf_nss="$(mktemp)" + cp /etc/libnss-mysql-root.cfg $conf_nss + printf 'password %s\n' "$(cat ${cfg.passwordFile})" >> $conf_nss + mv -fT "$conf_nss" /etc/libnss-mysql-root.cfg + chown ${config.services.nscd.user}:${config.services.nscd.group} /etc/libnss-mysql-root.cfg - umask $org_umask - fi - ''; + conf_pam="$(mktemp)" + cp /etc/security/pam_mysql.conf $conf_pam + printf 'users.db_passwd=%s\n' "$(cat ${cfg.passwordFile})" >> $conf_pam + mv -fT "$conf_pam" /etc/security/pam_mysql.conf + fi + ''; + }; }; } diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 88c0090013c7..fee7c35ed8f4 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -442,6 +442,7 @@ ./services/databases/surrealdb.nix ./services/databases/victoriametrics.nix ./services/desktops/accountsservice.nix + ./services/desktops/ayatana-indicators.nix ./services/desktops/bamf.nix ./services/desktops/blueman.nix ./services/desktops/cpupower-gui.nix @@ -1424,6 +1425,7 @@ ./system/activation/bootspec.nix ./system/activation/top-level.nix ./system/boot/binfmt.nix + ./system/boot/clevis.nix ./system/boot/emergency-mode.nix ./system/boot/grow-partition.nix ./system/boot/initrd-network.nix diff --git a/nixos/modules/programs/joycond-cemuhook.nix b/nixos/modules/programs/joycond-cemuhook.nix new file mode 100644 index 000000000000..7b129868db28 --- /dev/null +++ b/nixos/modules/programs/joycond-cemuhook.nix @@ -0,0 +1,17 @@ +{ lib, pkgs, config, ... }: +with lib; +{ + options.programs.joycond-cemuhook = { + enable = mkEnableOption (lib.mdDoc "joycond-cemuhook, a program to enable support for cemuhook's UDP protocol for joycond devices."); + }; + + config = lib.mkIf config.programs.joycond-cemuhook.enable { + assertions = [ + { + assertion = config.services.joycond.enable; + message = "joycond must be enabled through `services.joycond.enable`"; + } + ]; + environment.systemPackages = [ pkgs.joycond-cemuhook ]; + }; +} diff --git a/nixos/modules/programs/oddjobd.nix b/nixos/modules/programs/oddjobd.nix index b0920d007c9e..08bb8b268473 100644 --- a/nixos/modules/programs/oddjobd.nix +++ b/nixos/modules/programs/oddjobd.nix @@ -10,11 +10,6 @@ in }; config = lib.mkIf cfg.enable { - assertions = [ - { assertion = false; - message = "The oddjob service was found to be broken without NixOS test or maintainer. Please take ownership of this service."; - } - ]; systemd.packages = [ cfg.package ]; systemd.services.oddjobd = { @@ -30,4 +25,6 @@ in }; }; }; + + meta.maintainers = with lib.maintainers; [ SohamG ]; } diff --git a/nixos/modules/programs/screen.nix b/nixos/modules/programs/screen.nix index 68de9e52d7be..41bfb5d7809a 100644 --- a/nixos/modules/programs/screen.nix +++ b/nixos/modules/programs/screen.nix @@ -1,33 +1,41 @@ { config, lib, pkgs, ... }: let - inherit (lib) mkOption mkIf types; cfg = config.programs.screen; in { - ###### interface - options = { programs.screen = { + enable = lib.mkEnableOption (lib.mdDoc "screen, a basic terminal multiplexer"); + + package = lib.mkPackageOptionMD pkgs "screen" { }; - screenrc = mkOption { - default = ""; - description = lib.mdDoc '' - The contents of /etc/screenrc file. + screenrc = lib.mkOption { + type = with lib.types; nullOr lines; + example = '' + defscrollback 10000 + startup_message off ''; - type = types.lines; + description = lib.mdDoc "The contents of {file}`/etc/screenrc` file"; }; }; }; - ###### implementation - - config = mkIf (cfg.screenrc != "") { - environment.etc.screenrc.text = cfg.screenrc; - - environment.systemPackages = [ pkgs.screen ]; + config = { + # TODO: Added in 24.05, remove before 24.11 + assertions = [ + { + assertion = cfg.screenrc != null -> cfg.enable; + message = "`programs.screen.screenrc` has been configured, but `programs.screen.enable` is not true"; + } + ]; + } // lib.mkIf cfg.enable { + environment.etc.screenrc = { + enable = cfg.screenrc != null; + text = cfg.screenrc; + }; + environment.systemPackages = [ cfg.package ]; security.pam.services.screen = {}; }; - } diff --git a/nixos/modules/services/backup/postgresql-backup.nix b/nixos/modules/services/backup/postgresql-backup.nix index d3c6f3104fc5..82067d8ade34 100644 --- a/nixos/modules/services/backup/postgresql-backup.nix +++ b/nixos/modules/services/backup/postgresql-backup.nix @@ -17,8 +17,8 @@ let compressCmd = getAttr cfg.compression { "none" = "cat"; - "gzip" = "${pkgs.gzip}/bin/gzip -c -${toString cfg.compressionLevel}"; - "zstd" = "${pkgs.zstd}/bin/zstd -c -${toString cfg.compressionLevel}"; + "gzip" = "${pkgs.gzip}/bin/gzip -c -${toString cfg.compressionLevel} --rsyncable"; + "zstd" = "${pkgs.zstd}/bin/zstd -c -${toString cfg.compressionLevel} --rsyncable"; }; mkSqlPath = prefix: suffix: "${cfg.location}/${db}${prefix}.sql${suffix}"; @@ -178,4 +178,5 @@ in { }) ]; + meta.maintainers = with lib.maintainers; [ Scrumplex ]; } diff --git a/nixos/modules/services/desktops/ayatana-indicators.nix b/nixos/modules/services/desktops/ayatana-indicators.nix new file mode 100644 index 000000000000..abc687bbd43d --- /dev/null +++ b/nixos/modules/services/desktops/ayatana-indicators.nix @@ -0,0 +1,58 @@ +{ config +, pkgs +, lib +, ... +}: + +let + cfg = config.services.ayatana-indicators; +in +{ + options.services.ayatana-indicators = { + enable = lib.mkEnableOption (lib.mdDoc '' + Ayatana Indicators, a continuation of Canonical's Application Indicators + ''); + + packages = lib.mkOption { + type = lib.types.listOf lib.types.package; + default = [ ]; + example = lib.literalExpression "with pkgs; [ ayatana-indicator-messages ]"; + description = lib.mdDoc '' + List of packages containing Ayatana Indicator services + that should be brought up by the SystemD "ayatana-indicators" user target. + + Packages specified here must have passthru.ayatana-indicators set correctly. + + If, how, and where these indicators are displayed will depend on your DE. + ''; + }; + }; + + config = lib.mkIf cfg.enable { + environment = { + systemPackages = cfg.packages; + + pathsToLink = [ + "/share/ayatana" + ]; + }; + + # libayatana-common's ayatana-indicators.target with explicit Wants & Before to bring up requested indicator services + systemd.user.targets."ayatana-indicators" = + let + indicatorServices = lib.lists.flatten + (map + (pkg: + (map (ind: "${ind}.service") pkg.passthru.ayatana-indicators)) + cfg.packages); + in + { + description = "Target representing the lifecycle of the Ayatana Indicators. Each indicator should be bound to it in its individual service file"; + partOf = [ "graphical-session.target" ]; + wants = indicatorServices; + before = indicatorServices; + }; + }; + + meta.maintainers = with lib.maintainers; [ OPNA2608 ]; +} diff --git a/nixos/modules/services/hardware/thinkfan.nix b/nixos/modules/services/hardware/thinkfan.nix index 8fa7b456f20e..cca35f492b8e 100644 --- a/nixos/modules/services/hardware/thinkfan.nix +++ b/nixos/modules/services/hardware/thinkfan.nix @@ -217,6 +217,8 @@ in { systemd.services = { thinkfan.environment.THINKFAN_ARGS = escapeShellArgs ([ "-c" configFile ] ++ cfg.extraArgs); + thinkfan.serviceConfig.Restart = "on-failure"; + thinkfan.serviceConfig.RestartSec = "30s"; # must be added manually, see issue #81138 thinkfan.wantedBy = [ "multi-user.target" ]; diff --git a/nixos/modules/services/home-automation/home-assistant.nix b/nixos/modules/services/home-automation/home-assistant.nix index 54fd3e17292f..6aa0ae9eba47 100644 --- a/nixos/modules/services/home-automation/home-assistant.nix +++ b/nixos/modules/services/home-automation/home-assistant.nix @@ -455,10 +455,10 @@ in { ln -s /etc/home-assistant/configuration.yaml "${cfg.configDir}/configuration.yaml" ''; copyLovelaceConfig = if cfg.lovelaceConfigWritable then '' + rm -f "${cfg.configDir}/ui-lovelace.yaml" cp --no-preserve=mode ${lovelaceConfigFile} "${cfg.configDir}/ui-lovelace.yaml" '' else '' - rm -f "${cfg.configDir}/ui-lovelace.yaml" - ln -s /etc/home-assistant/ui-lovelace.yaml "${cfg.configDir}/ui-lovelace.yaml" + ln -fs /etc/home-assistant/ui-lovelace.yaml "${cfg.configDir}/ui-lovelace.yaml" ''; copyCustomLovelaceModules = if cfg.customLovelaceModules != [] then '' mkdir -p "${cfg.configDir}/www" diff --git a/nixos/modules/services/matrix/appservice-irc.nix b/nixos/modules/services/matrix/appservice-irc.nix index d153ffc2ace8..c79cd799b4d0 100644 --- a/nixos/modules/services/matrix/appservice-irc.nix +++ b/nixos/modules/services/matrix/appservice-irc.nix @@ -214,7 +214,7 @@ in { RestrictRealtime = true; PrivateMounts = true; SystemCallFilter = [ - "@system-service @pkey" + "@system-service @pkey @chown" "~@privileged @resources" ]; SystemCallArchitectures = "native"; diff --git a/nixos/modules/services/misc/preload.nix b/nixos/modules/services/misc/preload.nix index 19b2531087dd..d26e2c3d383e 100644 --- a/nixos/modules/services/misc/preload.nix +++ b/nixos/modules/services/misc/preload.nix @@ -19,7 +19,7 @@ in { serviceConfig = { EnvironmentFile = "${cfg.package}/etc/conf.d/preload"; - ExecStart = "${getExe cfg.package} --foreground $PRELOAD_OPTS"; + ExecStart = "${getExe cfg.package} -l '' --foreground $PRELOAD_OPTS"; Type = "simple"; # Only preload data during CPU idle time IOSchedulingClass = 3; diff --git a/nixos/modules/services/web-apps/netbox.nix b/nixos/modules/services/web-apps/netbox.nix index 3b9434e3d345..88d40b3abc52 100644 --- a/nixos/modules/services/web-apps/netbox.nix +++ b/nixos/modules/services/web-apps/netbox.nix @@ -317,7 +317,7 @@ in { serviceConfig = defaultServiceConfig // { ExecStart = '' - ${pkgs.python3Packages.gunicorn}/bin/gunicorn netbox.wsgi \ + ${pkg.gunicorn}/bin/gunicorn netbox.wsgi \ --bind ${cfg.listenAddress}:${toString cfg.port} \ --pythonpath ${pkg}/opt/netbox/netbox ''; diff --git a/nixos/modules/services/x11/desktop-managers/cinnamon.nix b/nixos/modules/services/x11/desktop-managers/cinnamon.nix index a882bb140d21..e9cadf219468 100644 --- a/nixos/modules/services/x11/desktop-managers/cinnamon.nix +++ b/nixos/modules/services/x11/desktop-managers/cinnamon.nix @@ -200,8 +200,7 @@ in }) ]; - # https://salsa.debian.org/cinnamon-team/cinnamon/-/commit/f87c64f8d35ba406eb11ad442989a0716f6620cf# - xdg.portal.config.x-cinnamon.default = mkDefault [ "xapp" "gtk" ]; + xdg.portal.configPackages = mkDefault [ pkgs.cinnamon.cinnamon-common ]; # Override GSettings schemas environment.sessionVariables.NIX_GSETTINGS_OVERRIDES_DIR = "${nixos-gsettings-overrides}/share/gsettings-schemas/nixos-gsettings-overrides/glib-2.0/schemas"; diff --git a/nixos/modules/system/boot/clevis.md b/nixos/modules/system/boot/clevis.md new file mode 100644 index 000000000000..91eb728a919e --- /dev/null +++ b/nixos/modules/system/boot/clevis.md @@ -0,0 +1,51 @@ +# Clevis {#module-boot-clevis} + +[Clevis](https://github.com/latchset/clevis) +is a framework for automated decryption of resources. +Clevis allows for secure unattended disk decryption during boot, using decryption policies that must be satisfied for the data to decrypt. + + +## Create a JWE file containing your secret {#module-boot-clevis-create-secret} + +The first step is to embed your secret in a [JWE](https://en.wikipedia.org/wiki/JSON_Web_Encryption) file. +JWE files have to be created through the clevis command line. 3 types of policies are supported: + +1) TPM policies + +Secrets are pinned against the presence of a TPM2 device, for example: +``` +echo hi | clevis encrypt tpm2 '{}' > hi.jwe +``` +2) Tang policies + +Secrets are pinned against the presence of a Tang server, for example: +``` +echo hi | clevis encrypt tang '{"url": "http://tang.local"}' > hi.jwe +``` + +3) Shamir Secret Sharing + +Using Shamir's Secret Sharing ([sss](https://en.wikipedia.org/wiki/Shamir%27s_secret_sharing)), secrets are pinned using a combination of the two preceding policies. For example: +``` +echo hi | clevis encrypt sss \ +'{"t": 2, "pins": {"tpm2": {"pcr_ids": "0"}, "tang": {"url": "http://tang.local"}}}' \ +> hi.jwe +``` + +For more complete documentation on how to generate a secret with clevis, see the [clevis documentation](https://github.com/latchset/clevis). + + +## Activate unattended decryption of a resource at boot {#module-boot-clevis-activate} + +In order to activate unattended decryption of a resource at boot, enable the `clevis` module: + +``` +boot.initrd.clevis.enable = true; +``` + +Then, specify the device you want to decrypt using a given clevis secret. Clevis will automatically try to decrypt the device at boot and will fallback to interactive unlocking if the decryption policy is not fulfilled. +``` +boot.initrd.clevis.devices."/dev/nvme0n1p1".secretFile = ./nvme0n1p1.jwe; +``` + +Only `bcachefs`, `zfs` and `luks` encrypted devices are supported at this time. diff --git a/nixos/modules/system/boot/clevis.nix b/nixos/modules/system/boot/clevis.nix new file mode 100644 index 000000000000..0c72590f9385 --- /dev/null +++ b/nixos/modules/system/boot/clevis.nix @@ -0,0 +1,107 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.boot.initrd.clevis; + systemd = config.boot.initrd.systemd; + supportedFs = [ "zfs" "bcachefs" ]; +in +{ + meta.maintainers = with maintainers; [ julienmalka camillemndn ]; + meta.doc = ./clevis.md; + + options = { + boot.initrd.clevis.enable = mkEnableOption (lib.mdDoc "Clevis in initrd"); + + + boot.initrd.clevis.package = mkOption { + type = types.package; + default = pkgs.clevis; + defaultText = "pkgs.clevis"; + description = lib.mdDoc "Clevis package"; + }; + + boot.initrd.clevis.devices = mkOption { + description = "Encrypted devices that need to be unlocked at boot using Clevis"; + default = { }; + type = types.attrsOf (types.submodule ({ + options.secretFile = mkOption { + description = lib.mdDoc "Clevis JWE file used to decrypt the device at boot, in concert with the chosen pin (one of TPM2, Tang server, or SSS)."; + type = types.path; + }; + })); + }; + + boot.initrd.clevis.useTang = mkOption { + description = "Whether the Clevis JWE file used to decrypt the devices uses a Tang server as a pin."; + default = false; + type = types.bool; + }; + + }; + + config = mkIf cfg.enable { + + # Implementation of clevis unlocking for the supported filesystems are located directly in the respective modules. + + + assertions = (attrValues (mapAttrs + (device: _: { + assertion = (any (fs: fs.device == device && (elem fs.fsType supportedFs)) config.system.build.fileSystems) || (hasAttr device config.boot.initrd.luks.devices); + message = '' + No filesystem or LUKS device with the name ${device} is declared in your configuration.''; + }) + cfg.devices)); + + + warnings = + if cfg.useTang && !config.boot.initrd.network.enable && !config.boot.initrd.systemd.network.enable + then [ "In order to use a Tang pinned secret you must configure networking in initrd" ] + else [ ]; + + boot.initrd = { + extraUtilsCommands = mkIf (!systemd.enable) '' + copy_bin_and_libs ${pkgs.jose}/bin/jose + copy_bin_and_libs ${pkgs.curl}/bin/curl + copy_bin_and_libs ${pkgs.bash}/bin/bash + + copy_bin_and_libs ${pkgs.tpm2-tools}/bin/.tpm2-wrapped + mv $out/bin/{.tpm2-wrapped,tpm2} + cp {${pkgs.tpm2-tss},$out}/lib/libtss2-tcti-device.so.0 + + copy_bin_and_libs ${cfg.package}/bin/.clevis-wrapped + mv $out/bin/{.clevis-wrapped,clevis} + + for BIN in ${cfg.package}/bin/clevis-decrypt*; do + copy_bin_and_libs $BIN + done + + for BIN in $out/bin/clevis{,-decrypt{,-null,-tang,-tpm2}}; do + sed -i $BIN -e 's,${pkgs.bash},,' -e 's,${pkgs.coreutils},,' + done + + sed -i $out/bin/clevis-decrypt-tpm2 -e 's,tpm2_,tpm2 ,' + ''; + + secrets = lib.mapAttrs' (name: value: nameValuePair "/etc/clevis/${name}.jwe" value.secretFile) cfg.devices; + + systemd = { + extraBin = mkIf systemd.enable { + clevis = "${cfg.package}/bin/clevis"; + curl = "${pkgs.curl}/bin/curl"; + }; + + storePaths = mkIf systemd.enable [ + cfg.package + "${pkgs.jose}/bin/jose" + "${pkgs.curl}/bin/curl" + "${pkgs.tpm2-tools}/bin/tpm2_createprimary" + "${pkgs.tpm2-tools}/bin/tpm2_flushcontext" + "${pkgs.tpm2-tools}/bin/tpm2_load" + "${pkgs.tpm2-tools}/bin/tpm2_unseal" + ]; + }; + }; + }; +} diff --git a/nixos/modules/system/boot/luksroot.nix b/nixos/modules/system/boot/luksroot.nix index ca560d63f3bd..8bd9e71cb3a9 100644 --- a/nixos/modules/system/boot/luksroot.nix +++ b/nixos/modules/system/boot/luksroot.nix @@ -1,9 +1,11 @@ -{ config, options, lib, pkgs, ... }: +{ config, options, lib, utils, pkgs, ... }: with lib; let luks = config.boot.initrd.luks; + clevis = config.boot.initrd.clevis; + systemd = config.boot.initrd.systemd; kernelPackages = config.boot.kernelPackages; defaultPrio = (mkOptionDefault {}).priority; @@ -594,7 +596,7 @@ in ''; type = with types; attrsOf (submodule ( - { name, ... }: { options = { + { config, name, ... }: { options = { name = mkOption { visible = false; @@ -894,6 +896,19 @@ in ''; }; }; + + config = mkIf (clevis.enable && (hasAttr name clevis.devices)) { + preOpenCommands = mkIf (!systemd.enable) '' + mkdir -p /clevis-${name} + mount -t ramfs none /clevis-${name} + clevis decrypt < /etc/clevis/${name}.jwe > /clevis-${name}/decrypted + ''; + keyFile = "/clevis-${name}/decrypted"; + fallbackToPassword = !systemd.enable; + postOpenCommands = mkIf (!systemd.enable) '' + umount /clevis-${name} + ''; + }; })); }; @@ -1081,6 +1096,35 @@ in boot.initrd.preLVMCommands = mkIf (!config.boot.initrd.systemd.enable) (commonFunctions + preCommands + concatStrings (mapAttrsToList openCommand preLVM) + postCommands); boot.initrd.postDeviceCommands = mkIf (!config.boot.initrd.systemd.enable) (commonFunctions + preCommands + concatStrings (mapAttrsToList openCommand postLVM) + postCommands); + boot.initrd.systemd.services = let devicesWithClevis = filterAttrs (device: _: (hasAttr device clevis.devices)) luks.devices; in + mkIf (clevis.enable && systemd.enable) ( + (mapAttrs' + (name: _: nameValuePair "cryptsetup-clevis-${name}" { + wantedBy = [ "systemd-cryptsetup@${utils.escapeSystemdPath name}.service" ]; + before = [ + "systemd-cryptsetup@${utils.escapeSystemdPath name}.service" + "initrd-switch-root.target" + "shutdown.target" + ]; + wants = [ "systemd-udev-settle.service" ] ++ optional clevis.useTang "network-online.target"; + after = [ "systemd-modules-load.service" "systemd-udev-settle.service" ] ++ optional clevis.useTang "network-online.target"; + script = '' + mkdir -p /clevis-${name} + mount -t ramfs none /clevis-${name} + umask 277 + clevis decrypt < /etc/clevis/${name}.jwe > /clevis-${name}/decrypted + ''; + conflicts = [ "initrd-switch-root.target" "shutdown.target" ]; + unitConfig.DefaultDependencies = "no"; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + ExecStop = "${config.boot.initrd.systemd.package.util-linux}/bin/umount /clevis-${name}"; + }; + }) + devicesWithClevis) + ); + environment.systemPackages = [ pkgs.cryptsetup ]; }; } diff --git a/nixos/modules/tasks/filesystems/bcachefs.nix b/nixos/modules/tasks/filesystems/bcachefs.nix index f28fd5cde9c1..639ff87841b6 100644 --- a/nixos/modules/tasks/filesystems/bcachefs.nix +++ b/nixos/modules/tasks/filesystems/bcachefs.nix @@ -57,7 +57,15 @@ let # bcachefs does not support mounting devices with colons in the path, ergo we don't (see #49671) firstDevice = fs: lib.head (lib.splitString ":" fs.device); - openCommand = name: fs: '' + openCommand = name: fs: if config.boot.initrd.clevis.enable && (lib.hasAttr (firstDevice fs) config.boot.initrd.clevis.devices) then '' + if clevis decrypt < /etc/clevis/${firstDevice fs}.jwe | bcachefs unlock ${firstDevice fs} + then + printf "unlocked ${name} using clevis\n" + else + printf "falling back to interactive unlocking...\n" + tryUnlock ${name} ${firstDevice fs} + fi + '' else '' tryUnlock ${name} ${firstDevice fs} ''; diff --git a/nixos/modules/tasks/filesystems/zfs.nix b/nixos/modules/tasks/filesystems/zfs.nix index 72bc79f31b68..fd92a0014002 100644 --- a/nixos/modules/tasks/filesystems/zfs.nix +++ b/nixos/modules/tasks/filesystems/zfs.nix @@ -17,6 +17,9 @@ let cfgZED = config.services.zfs.zed; selectModulePackage = package: config.boot.kernelPackages.${package.kernelModuleAttribute}; + clevisDatasets = map (e: e.device) (filter (e: (hasAttr e.device config.boot.initrd.clevis.devices) && e.fsType == "zfs" && (fsNeededForBoot e)) config.system.build.fileSystems); + + inInitrd = any (fs: fs == "zfs") config.boot.initrd.supportedFilesystems; inSystem = any (fs: fs == "zfs") config.boot.supportedFilesystems; @@ -120,12 +123,12 @@ let # but don't *require* it, because mounts shouldn't be killed if it's stopped. # In the future, hopefully someone will complete this: # https://github.com/zfsonlinux/zfs/pull/4943 - wants = [ "systemd-udev-settle.service" ]; + wants = [ "systemd-udev-settle.service" ] ++ optional (config.boot.initrd.clevis.useTang) "network-online.target"; after = [ "systemd-udev-settle.service" "systemd-modules-load.service" "systemd-ask-password-console.service" - ]; + ] ++ optional (config.boot.initrd.clevis.useTang) "network-online.target"; requiredBy = getPoolMounts prefix pool ++ [ "zfs-import.target" ]; before = getPoolMounts prefix pool ++ [ "zfs-import.target" ]; unitConfig = { @@ -154,6 +157,9 @@ let poolImported "${pool}" || poolImport "${pool}" # Try one last time, e.g. to import a degraded pool. fi if poolImported "${pool}"; then + ${concatMapStringsSep "\n" (elem: "clevis decrypt < /etc/clevis/${elem}.jwe | zfs load-key ${elem} || true ") (filter (p: (elemAt (splitString "/" p) 0) == pool) clevisDatasets)} + + ${optionalString keyLocations.hasKeys '' ${keyLocations.command} | while IFS=$'\t' read ds kl ks; do { @@ -623,6 +629,9 @@ in fi poolImported "${pool}" || poolImport "${pool}" # Try one last time, e.g. to import a degraded pool. fi + + ${concatMapStringsSep "\n" (elem: "clevis decrypt < /etc/clevis/${elem}.jwe | zfs load-key ${elem}") (filter (p: (elemAt (splitString "/" p) 0) == pool) clevisDatasets)} + ${if isBool cfgZfs.requestEncryptionCredentials then optionalString cfgZfs.requestEncryptionCredentials '' zfs load-key -a |