diff --git a/nixos/modules/hardware/cpu/amd-sev.nix b/nixos/modules/hardware/cpu/amd-sev.nix index 28ee07f005b..08e1de49638 100644 --- a/nixos/modules/hardware/cpu/amd-sev.nix +++ b/nixos/modules/hardware/cpu/amd-sev.nix @@ -1,37 +1,43 @@ -{ config, lib, ... }: +{ config, options, lib, ... }: with lib; let - cfg = config.hardware.cpu.amd.sev; - defaultGroup = "sev"; -in - with lib; { - options.hardware.cpu.amd.sev = { - enable = mkEnableOption (lib.mdDoc "access to the AMD SEV device"); - user = mkOption { - description = lib.mdDoc "Owner to assign to the SEV device."; - type = types.str; - default = "root"; - }; - group = mkOption { - description = lib.mdDoc "Group to assign to the SEV device."; - type = types.str; - default = defaultGroup; - }; - mode = mkOption { - description = lib.mdDoc "Mode to set for the SEV device."; - type = types.str; - default = "0660"; - }; - }; + cfgSev = config.hardware.cpu.amd.sev; + cfgSevGuest = config.hardware.cpu.amd.sevGuest; - config = mkIf cfg.enable { + optionsFor = device: group: { + enable = mkEnableOption (lib.mdDoc "access to the AMD ${device} device"); + user = mkOption { + description = lib.mdDoc "Owner to assign to the ${device} device."; + type = types.str; + default = "root"; + }; + group = mkOption { + description = lib.mdDoc "Group to assign to the ${device} device."; + type = types.str; + default = group; + }; + mode = mkOption { + description = lib.mdDoc "Mode to set for the ${device} device."; + type = types.str; + default = "0660"; + }; + }; +in +with lib; { + options.hardware.cpu.amd.sev = optionsFor "SEV" "sev"; + + options.hardware.cpu.amd.sevGuest = optionsFor "SEV guest" "sev-guest"; + + config = mkMerge [ + # /dev/sev + (mkIf cfgSev.enable { assertions = [ { - assertion = hasAttr cfg.user config.users.users; + assertion = hasAttr cfgSev.user config.users.users; message = "Given user does not exist"; } { - assertion = (cfg.group == defaultGroup) || (hasAttr cfg.group config.users.groups); + assertion = (cfgSev.group == options.hardware.cpu.amd.sev.group.default) || (hasAttr cfgSev.group config.users.groups); message = "Given group does not exist"; } ]; @@ -40,12 +46,35 @@ in options kvm_amd sev=1 ''; - users.groups = optionalAttrs (cfg.group == defaultGroup) { - "${cfg.group}" = {}; + users.groups = optionalAttrs (cfgSev.group == options.hardware.cpu.amd.sev.group.default) { + "${cfgSev.group}" = { }; }; - services.udev.extraRules = with cfg; '' + services.udev.extraRules = with cfgSev; '' KERNEL=="sev", OWNER="${user}", GROUP="${group}", MODE="${mode}" ''; - }; - } + }) + + # /dev/sev-guest + (mkIf cfgSevGuest.enable { + assertions = [ + { + assertion = hasAttr cfgSevGuest.user config.users.users; + message = "Given user does not exist"; + } + { + assertion = (cfgSevGuest.group == options.hardware.cpu.amd.sevGuest.group.default) || (hasAttr cfgSevGuest.group config.users.groups); + message = "Given group does not exist"; + } + ]; + + users.groups = optionalAttrs (cfgSevGuest.group == options.hardware.cpu.amd.sevGuest.group.default) { + "${cfgSevGuest.group}" = { }; + }; + + services.udev.extraRules = with cfgSevGuest; '' + KERNEL=="sev-guest", OWNER="${user}", GROUP="${group}", MODE="${mode}" + ''; + }) + ]; +} diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 11cc12f071c..a3e85c337aa 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -109,6 +109,7 @@ in { allTerminfo = handleTest ./all-terminfo.nix {}; alps = handleTest ./alps.nix {}; amazon-init-shell = handleTest ./amazon-init-shell.nix {}; + amd-sev = runTest ./amd-sev.nix; anbox = runTest ./anbox.nix; anuko-time-tracker = handleTest ./anuko-time-tracker.nix {}; apcupsd = handleTest ./apcupsd.nix {}; diff --git a/nixos/tests/amd-sev.nix b/nixos/tests/amd-sev.nix new file mode 100644 index 00000000000..bf9a50c10d0 --- /dev/null +++ b/nixos/tests/amd-sev.nix @@ -0,0 +1,56 @@ +{ lib, ... }: { + name = "amd-sev"; + meta = { + maintainers = with lib.maintainers; [ trundle veehaitch ]; + }; + + nodes.machine = { lib, ... }: { + hardware.cpu.amd.sev.enable = true; + hardware.cpu.amd.sevGuest.enable = true; + + specialisation.sevCustomUserGroup.configuration = { + users.groups.sevtest = { }; + + hardware.cpu.amd.sev = { + enable = true; + group = "root"; + mode = "0600"; + }; + hardware.cpu.amd.sevGuest = { + enable = true; + group = "sevtest"; + }; + }; + }; + + testScript = { nodes, ... }: + let + specialisations = "${nodes.machine.system.build.toplevel}/specialisation"; + in + '' + machine.wait_for_unit("multi-user.target") + + with subtest("Check default settings"): + out = machine.succeed("cat /etc/udev/rules.d/99-local.rules") + assert 'KERNEL=="sev", OWNER="root", GROUP="sev", MODE="0660"' in out + assert 'KERNEL=="sev-guest", OWNER="root", GROUP="sev-guest", MODE="0660"' in out + + out = machine.succeed("cat /etc/group") + assert "sev:" in out + assert "sev-guest:" in out + assert "sevtest:" not in out + + with subtest("Activate configuration with custom user/group"): + machine.succeed('${specialisations}/sevCustomUserGroup/bin/switch-to-configuration test') + + with subtest("Check custom user and group"): + out = machine.succeed("cat /etc/udev/rules.d/99-local.rules") + assert 'KERNEL=="sev", OWNER="root", GROUP="root", MODE="0600"' in out + assert 'KERNEL=="sev-guest", OWNER="root", GROUP="sevtest", MODE="0660"' in out + + out = machine.succeed("cat /etc/group") + assert "sev:" not in out + assert "sev-guest:" not in out + assert "sevtest:" in out + ''; +}