infrastructure/modules/nixos/sssd/sssd.nix
2024-05-13 15:31:34 -07:00

228 lines
6.6 KiB
Nix

{
config,
options,
lib,
gensokyo-zone,
...
}: let
inherit (gensokyo-zone.lib) mkAlmostOptionDefault mapOptionDefaults;
inherit (lib.options) mkOption mkEnableOption;
inherit (lib.modules) mkIf mkMerge mkOptionDefault mkForce;
inherit (lib.attrsets) mapAttrs filterAttrs attrNames attrValues listToAttrs mapAttrsToList nameValuePair;
inherit (lib.lists) filter isList concatMap;
inherit (lib.strings) toUpper concatMapStringsSep replaceStrings;
inherit (lib.trivial) flip;
inherit (lib) generators;
cfg = config.services.sssd;
mkValuePrimitive = value:
if value == true
then "True"
else if value == false
then "False"
else toString value;
toINI = generators.toINI {
mkKeyValue = generators.mkKeyValueDefault {
mkValueString = value:
if isList value
then concatMapStringsSep ", " mkValuePrimitive value
else mkValuePrimitive value;
} " = ";
};
primitiveType = with lib.types; oneOf [str int bool];
valueType = with lib.types; oneOf [primitiveType (listOf primitiveType)];
settingsType = lib.types.attrsOf valueType;
serviceModule = {name, ...}: {
options = with lib.types; {
enable = mkEnableOption "${name} service";
name = mkOption {
type = str;
default = name;
readOnly = true;
};
settings = mkOption {
type = settingsType;
default = {};
};
};
};
nssModule = {nixosConfig, ...}: {
options = {
# TODO: passwd.enable = mkEnableOption "passwd" // { default = true; };
shadow.enable = mkEnableOption "shadow" // {default = nixosConfig.services.sssd.services.pam.enable;};
netgroup.enable = mkEnableOption "netgroup" // {default = true;};
};
};
domainModule = {name, ...}: {
options = with lib.types; {
enable =
mkEnableOption "domain"
// {
default = true;
};
domain = mkOption {
type = str;
default = name;
};
settings = mkOption {
type = settingsType;
};
};
};
domainLdapModule = {config, ...}: let
cfg = config.ldap;
in {
options.ldap = with lib.types; {
extraAttrs.user = mkOption {
type = attrsOf str;
default = {};
};
authtok = {
type = mkOption {
type = enum ["password" "obfuscated_password"];
default = "password";
};
password = mkOption {
type = nullOr str;
default = null;
};
passwordFile = mkOption {
type = nullOr path;
default = null;
};
passwordVar = mkOption {
type = str;
internal = true;
default = "SSSD_AUTHTOK_" + replaceStrings ["-" "."] ["_" "_"] (toUpper config.domain);
};
};
};
config = let
authtokConfig = mkIf (cfg.authtok.password != null || cfg.authtok.passwordFile != null) {
ldap_default_authtok_type = mkOptionDefault cfg.authtok.type;
ldap_default_authtok = mkOptionDefault (
if cfg.authtok.passwordFile != null
then "\$${cfg.authtok.passwordVar}"
else cfg.authtok.password
);
};
extraAttrsConfig = mkIf (cfg.extraAttrs.user != {}) {
ldap_user_extra_attrs = let
mkAttr = name: attr: "${name}:${attr}";
in
mapAttrsToList mkAttr cfg.extraAttrs.user;
};
in {
settings = mkMerge [
authtokConfig
extraAttrsConfig
];
};
};
in {
options.services.sssd = with lib.types; {
debugLevel = mkOption {
type = ints.between 16 65520;
default = 16;
};
domains = mkOption {
type = attrsOf (submoduleWith {
modules = [domainModule domainLdapModule];
specialArgs = {
nixosConfig = config;
};
});
default = {
shadowutils.settings = mapOptionDefaults {
id_provider = "proxy";
proxy_lib_name = "files";
auth_provider = "proxy";
proxy_pam_target = "sssd-shadowutils";
proxy_fast_alias = true;
};
};
};
services = let
mkServiceOption = name: {modules ? []}:
mkOption {
type = submoduleWith {
modules = [serviceModule] ++ modules;
specialArgs = {
inherit name;
nixosConfig = config;
};
};
};
services = {
nss = {modules = [nssModule];};
pam = {};
ifp = {};
sudo = {};
autofs = {};
ssh = {};
pac = {};
};
in
mapAttrs mkServiceOption services;
settings = mkOption {
type = attrsOf settingsType;
};
configText = mkOption {
type = nullOr lines;
};
};
config.services.sssd = let
enabledDomains = filter (domain: domain.enable) (attrValues cfg.domains);
enabledServices = filterAttrs (_: service: service.enable) cfg.services;
in {
settings = let
serviceSettings = mapAttrs (name: service: mapOptionDefaults service.settings) enabledServices;
defaultSettings = {
sssd = mapOptionDefaults {
config_file_version = 2;
debug_level = cfg.debugLevel;
services = mapAttrsToList (_: service: service.name) enabledServices;
domains = map (domain: domain.domain) enabledDomains;
};
};
domainSettings =
map (domain: {
"domain/${domain.domain}" = mapAttrs (_: mkOptionDefault) domain.settings;
})
enabledDomains;
settings = [defaultSettings serviceSettings] ++ domainSettings;
in
mkMerge settings;
services = {
nss.enable = mkAlmostOptionDefault true;
pam.enable = mkAlmostOptionDefault true;
ifp.settings = let
extraUserAttrs = listToAttrs (concatMap (domain: map (flip nameValuePair {}) (attrNames domain.ldap.extraAttrs.user)) enabledDomains);
mkExtraAttr = name: _: "+${name}";
in {
user_attributes = mkIf (extraUserAttrs != {}) (mkOptionDefault (
mapAttrsToList mkExtraAttr extraUserAttrs
));
};
sudo = {};
autofs = {};
ssh = {};
pac = {};
};
configText = mkOptionDefault (toINI cfg.settings);
config = mkIf (cfg.configText != null) (mkAlmostOptionDefault cfg.configText);
};
config.system.nssDatabases = let
inherit (cfg.services) nss;
in
mkIf cfg.enable {
${
if options ? system.nssDatabases.netgroup
then "netgroup"
else null
} =
mkIf (nss.enable && nss.netgroup.enable) ["sss"];
shadow = mkIf (!nss.enable || !nss.shadow.enable) (
mkForce ["files"]
);
};
}