mirror of
https://github.com/oddlama/nix-config.git
synced 2025-10-11 07:10:39 +02:00
chore(kanidm): add preliminary provisioning scripts
This commit is contained in:
parent
aa0f037de2
commit
5d934bddf0
1 changed files with 195 additions and 31 deletions
|
@ -5,17 +5,64 @@
|
|||
}: let
|
||||
inherit
|
||||
(lib)
|
||||
assertMsg
|
||||
filter
|
||||
genAttrs
|
||||
hasInfix
|
||||
head
|
||||
mdDoc
|
||||
mkIf
|
||||
all
|
||||
attrNames
|
||||
attrValues
|
||||
concatLines
|
||||
concatLists
|
||||
concatMap
|
||||
concatMapStrings
|
||||
elem
|
||||
escapeShellArg
|
||||
flip
|
||||
mapAttrsToList
|
||||
mkOption
|
||||
removeSuffix
|
||||
optionals
|
||||
subtractLists
|
||||
types
|
||||
;
|
||||
|
||||
cfg = config.services.kanidm;
|
||||
|
||||
mkPresentOption = what:
|
||||
mkOption {
|
||||
description = "Whether to ensure that this ${what} is present or absent.";
|
||||
type = types.bool;
|
||||
default = true;
|
||||
};
|
||||
|
||||
mkScript = script:
|
||||
mkOption {
|
||||
readOnly = true;
|
||||
internal = true;
|
||||
type = types.str;
|
||||
default = script;
|
||||
};
|
||||
|
||||
script = ''
|
||||
set -euo pipefail
|
||||
|
||||
# TODO login
|
||||
|
||||
known_groups=$(kanidm group list --output=json)
|
||||
function group_exists() {
|
||||
[[ -n "$(${getExe jq} <<< "$known_groups" '. | select(.name[0] == "$1")')" ]]
|
||||
}
|
||||
|
||||
#known_persons=$(kanidm person list --output=json)
|
||||
#function person_exists() {
|
||||
# [[ -n "$(${getExe jq} <<< "$known_persons" '. | select(.name[0] == "$1")')" ]]
|
||||
#}
|
||||
|
||||
#known_oauth2_systems=$(kanidm person list --output=json)
|
||||
#function oauth2_system_exists() {
|
||||
# [[ -n "$(${getExe jq} <<< "$known_oauth2_systems" '. | select(.oauth2_rs_name[0] == "$1")')" ]]
|
||||
#}
|
||||
|
||||
${concatMapStrings (x: x._script) (attrValues cfg.provision.groups)}
|
||||
${concatMapStrings (x: x._script) (attrValues cfg.provision.persons)}
|
||||
${concatMapStrings (x: x._script) (attrValues cfg.provision.systems.oauth2)}
|
||||
'';
|
||||
in {
|
||||
options.services.kanidm.provision = {
|
||||
enable = mkEnableOption "provisioning of systems (oauth2), groups and users";
|
||||
|
@ -23,12 +70,62 @@ in {
|
|||
persons = mkOption {
|
||||
description = "Provisioning of kanidm persons";
|
||||
default = {};
|
||||
type = types.attrsOf (types.submodule (personSubmod: {
|
||||
type = types.attrsOf (types.submodule (personSubmod: let
|
||||
inherit (personSubmod.module._args) name;
|
||||
updateArgs =
|
||||
(optionals (personSubmod.config.legalName != null) ["--legalname" personSubmod.config.legalName])
|
||||
# mail addresses
|
||||
++ concatMap (addr: ["--mail" addr]) personSubmod.config.mailAddresses;
|
||||
in {
|
||||
options = {
|
||||
present = mkOption {
|
||||
description = "Whether to ensure that this person is present or absent.";
|
||||
type = types.bool;
|
||||
default = true;
|
||||
_script = mkScript (
|
||||
if personSubmod.config.present
|
||||
then
|
||||
''
|
||||
if ! person_exists ${escapeShellArg name}; then
|
||||
kanidm person create ${escapeShellArg name} \
|
||||
${escapeShellArg personSubmod.config.displayName}
|
||||
fi
|
||||
''
|
||||
+ optionalString (updateArgs != []) ''
|
||||
kanidm person update ${escapeShellArg name} ${escapeShellArgs updateArgs}
|
||||
''
|
||||
+ flip concatMapStrings personSubmod.config.groups (group: ''
|
||||
kanidm group add-members ${escapeShellArg group} ${escapeShellArg name}
|
||||
'')
|
||||
else ''
|
||||
if oauth2_system_exists ${escapeShellArg name}; then
|
||||
kanidm group delete ${escapeShellArg name}
|
||||
fi
|
||||
''
|
||||
);
|
||||
|
||||
present = mkPresentOption "person";
|
||||
|
||||
displayName = mkOption {
|
||||
description = "Display name";
|
||||
type = types.str;
|
||||
example = "My User";
|
||||
};
|
||||
|
||||
legalName = mkOption {
|
||||
description = "Full legal name";
|
||||
type = types.nullOr types.str;
|
||||
example = "Jane Doe";
|
||||
default = null;
|
||||
};
|
||||
|
||||
mailAddresses = mkOption {
|
||||
description = "Mail addresses. First given address is considered the primary address.";
|
||||
type = types.listOf types.str;
|
||||
example = ["jane.doe@example.com"];
|
||||
default = [];
|
||||
};
|
||||
|
||||
groups = mkOption {
|
||||
description = "List of kanidm groups to which this user belongs.";
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
};
|
||||
};
|
||||
}));
|
||||
|
@ -37,13 +134,25 @@ in {
|
|||
groups = mkOption {
|
||||
description = "Provisioning of kanidm groups";
|
||||
default = {};
|
||||
type = types.attrsOf (types.submodule (groupSubmod: {
|
||||
type = types.attrsOf (types.submodule (groupSubmod: let
|
||||
inherit (groupSubmod.module._args) name;
|
||||
in {
|
||||
options = {
|
||||
present = mkOption {
|
||||
description = "Whether to ensure that this group is present or absent.";
|
||||
type = types.bool;
|
||||
default = true;
|
||||
};
|
||||
_script = mkScript (
|
||||
if groupSubmod.config.present
|
||||
then ''
|
||||
if ! group_exists ${escapeShellArg name}; then
|
||||
kanidm group create ${escapeShellArg name}
|
||||
fi
|
||||
''
|
||||
else ''
|
||||
if group_exists ${escapeShellArg name}; then
|
||||
kanidm group delete ${escapeShellArg name}
|
||||
fi
|
||||
''
|
||||
);
|
||||
|
||||
present = mkPresentOption "group";
|
||||
};
|
||||
}));
|
||||
};
|
||||
|
@ -51,17 +160,49 @@ in {
|
|||
systems.oauth2 = mkOption {
|
||||
description = "Provisioning of oauth2 systems";
|
||||
default = {};
|
||||
type = types.attrsOf (types.submodule (oauth2Submod: {
|
||||
type = types.attrsOf (types.submodule (oauth2Submod: let
|
||||
inherit (oauth2Submod.module._args) name;
|
||||
in {
|
||||
options = {
|
||||
present = mkOption {
|
||||
description = "Whether to ensure that this oauth2 system is present or absent.";
|
||||
type = types.bool;
|
||||
default = true;
|
||||
_script = mkScript (
|
||||
if oauth2Submod.config.present
|
||||
then
|
||||
''
|
||||
if ! oauth2_system_exists ${escapeShellArg name}; then
|
||||
kanidm system oauth2 create \
|
||||
${escapeShellArg name} \
|
||||
${escapeShellArg oauth2Submod.config.displayName} \
|
||||
${escapeShellArg oauth2Submod.config.originUrl}
|
||||
fi
|
||||
''
|
||||
+ concatLines (flip mapAttrsToList oauth2Submod.config.scopeMaps (group: scopes: ''
|
||||
kanidm system oauth2 update-scope-map ${escapeShellArg name} \
|
||||
${escapeShellArg group} ${escapeShellArgs scopes}
|
||||
''))
|
||||
+ concatLines (flip mapAttrsToList oauth2Submod.config.supplementaryScopeMaps (group: scopes: ''
|
||||
kanidm system oauth2 update-sup-scope-map ${escapeShellArg name} \
|
||||
${escapeShellArg group} ${escapeShellArgs scopes}
|
||||
''))
|
||||
else ''
|
||||
if oauth2_system_exists ${escapeShellArg name}; then
|
||||
kanidm group delete ${escapeShellArg name}
|
||||
fi
|
||||
''
|
||||
);
|
||||
|
||||
present = mkPresentOption "oauth2 system";
|
||||
|
||||
displayName = mkOption {
|
||||
description = "Display name";
|
||||
type = types.str;
|
||||
example = "Some Service";
|
||||
};
|
||||
|
||||
url =
|
||||
mkOption {
|
||||
};
|
||||
originUrl = mkOption {
|
||||
description = "The basic secret to use for this service. If null, the random secret generated by kanidm will not be touched. Do NOT use a path from the nix store here!";
|
||||
type = types.str;
|
||||
example = "https://someservice.example.com/";
|
||||
};
|
||||
|
||||
basicSecretFile = mkOption {
|
||||
description = "The basic secret to use for this service. If null, the random secret generated by kanidm will not be touched. Do NOT use a path from the nix store here!";
|
||||
|
@ -70,12 +211,14 @@ in {
|
|||
default = null;
|
||||
};
|
||||
|
||||
scopeMap = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
scopeMaps = mkOption {
|
||||
description = "Maps kanidm groups to provided scopes. See [Scope Relations](https://kanidm.github.io/kanidm/stable/integrations/oauth2.html#scope-relationships) for more information.";
|
||||
type = types.attrsOf types.str;
|
||||
default = {};
|
||||
};
|
||||
|
||||
supScopeMaps = mkOption {
|
||||
supplementaryScopeMaps = mkOption {
|
||||
description = "Maps kanidm groups to provided supplementary scopes. See [Scope Relations](https://kanidm.github.io/kanidm/stable/integrations/oauth2.html#scope-relationships) for more information.";
|
||||
type = types.attrsOf types.str;
|
||||
default = {};
|
||||
};
|
||||
|
@ -85,5 +228,26 @@ in {
|
|||
};
|
||||
|
||||
config = {
|
||||
assertions =
|
||||
flip mapAttrsToList cfg.provision.persons (person: personCfg: let
|
||||
unknownGroups = subtractLists (attrNames cfg.provision.groups) personCfg.groups;
|
||||
in {
|
||||
assertion = unknownGroups == [];
|
||||
message = "kanidm: provision.persons.${person}.groups: Refers to unknown groups: ${unknownGroups}";
|
||||
})
|
||||
+ concatLists (flip mapAttrsToList cfg.provision.systems.oauth2 (oauth2: oauth2Cfg: [
|
||||
(let
|
||||
unknownGroups = subtractLists (attrNames cfg.provision.groups) (attrNames oauth2Cfg.scopeMaps);
|
||||
in {
|
||||
assertion = unknownGroups == [];
|
||||
message = "kanidm: provision.systems.oauth2.${oauth2}.scopeMaps: Refers to unknown groups: ${unknownGroups}";
|
||||
})
|
||||
(let
|
||||
unknownGroups = subtractLists (attrNames cfg.provision.groups) (attrNames oauth2Cfg.supplementaryScopeMaps);
|
||||
in {
|
||||
assertion = unknownGroups == [];
|
||||
message = "kanidm: provision.systems.oauth2.${oauth2}.supplementaryScopeMaps: Refers to unknown groups: ${unknownGroups}";
|
||||
})
|
||||
]));
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue