diff --git a/nixos/modules/services/security/kanidm.nix b/nixos/modules/services/security/kanidm.nix index bb56d5a44797..6e4a853e3d6f 100644 --- a/nixos/modules/services/security/kanidm.nix +++ b/nixos/modules/services/security/kanidm.nix @@ -54,15 +54,10 @@ let ++ optional (cfg.provision.extraJsonFile != null) cfg.provision.extraJsonFile ++ mapAttrsToList (_: x: x.basicSecretFile) cfg.provision.systems.oauth2 ); - secretDirectories = unique ( - map builtins.dirOf ( - [ - cfg.serverSettings.tls_chain - cfg.serverSettings.tls_key - ] - ++ optionals cfg.provision.enable provisionSecretFiles - ) - ); + secretPaths = [ + cfg.serverSettings.tls_chain + cfg.serverSettings.tls_key + ] ++ optionals cfg.provision.enable provisionSecretFiles; # Merge bind mount paths and remove paths where a prefix is already mounted. # This makes sure that if e.g. the tls_chain is in the nix store and /nix/store is already in the mount @@ -185,7 +180,9 @@ let finalJson = if cfg.provision.extraJsonFile != null then - "<(${lib.getExe pkgs.jq} -s '.[0] * .[1]' ${provisionStateJson} ${cfg.provision.extraJsonFile})" + '' + <(${lib.getExe pkgs.yq-go} '. *+ load("${cfg.provision.extraJsonFile}") | (.. | select(type == "!!seq")) |= unique' ${provisionStateJson}) + '' else provisionStateJson; @@ -442,10 +439,8 @@ in description = '' A JSON file for provisioning persons, groups & systems. Options set in this file take precedence over values set using the other options. - In the case of duplicates, `jq` will remove all but the last one - when merging this file with the options. + The files get deeply merged, and deduplicated. The accepted JSON schema can be found at . - Note: theoretically `jq` cannot merge nested types, but this does not pose an issue as kanidm-provision's JSON scheme does not use nested types. ''; type = types.nullOr types.path; default = null; @@ -892,7 +887,7 @@ in ( defaultServiceConfig // { - BindReadOnlyPaths = mergePaths (defaultServiceConfig.BindReadOnlyPaths ++ secretDirectories); + BindReadOnlyPaths = mergePaths (defaultServiceConfig.BindReadOnlyPaths ++ secretPaths); } ) { @@ -906,8 +901,6 @@ in BindPaths = [ - # To create the socket - "/run/kanidmd:/run/kanidmd" # To store backups cfg.serverSettings.online_backup.path ] diff --git a/nixos/tests/kanidm-provisioning.nix b/nixos/tests/kanidm-provisioning.nix index 7b40675aacd2..10365d2cb40c 100644 --- a/nixos/tests/kanidm-provisioning.nix +++ b/nixos/tests/kanidm-provisioning.nix @@ -244,6 +244,29 @@ import ./make-test-python.nix ( }; }; + specialisation.extraJsonFile.configuration = + { ... }: + { + services.kanidm.provision = lib.mkForce { + enable = true; + idmAdminPasswordFile = pkgs.writeText "idm-admin-pw" provisionIdmAdminPassword; + + extraJsonFile = pkgs.writeText "extra-json.json" ( + builtins.toJSON { + persons.testuser2.displayName = "Test User 2"; + groups.testgroup1.members = [ "testuser2" ]; + } + ); + + groups.testgroup1 = { }; + + persons.testuser1 = { + displayName = "Test User 1"; + groups = [ "testgroup1" ]; + }; + }; + }; + security.pki.certificateFiles = [ certs.ca.cert ]; networking.hosts."::1" = [ serverDomain ]; @@ -535,6 +558,21 @@ import ./make-test-python.nix ( out = provision.succeed("kanidm system oauth2 get service2") assert_lacks(out, "name: service2") + provision.succeed("kanidm logout -D idm_admin") + + with subtest("Test Provisioning - extraJsonFile"): + provision.succeed('${specialisations}/extraJsonFile/bin/switch-to-configuration test') + provision_login("${provisionIdmAdminPassword}") + out = provision.succeed("kanidm group get testgroup1") + assert_contains(out, "name: testgroup1") + out = provision.succeed("kanidm person get testuser1") + assert_contains(out, "name: testuser1") + out = provision.succeed("kanidm person get testuser2") + assert_contains(out, "name: testuser2") + out = provision.succeed("kanidm group get testgroup1") + assert_contains(out, "member: testuser1") + assert_contains(out, "member: testuser2") + provision.succeed("kanidm logout -D idm_admin") ''; }