infrastructure/modules/nixos/sssd/sssd.nix
2024-04-07 15:05:00 -07:00

210 lines
6.5 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" ]
);
};
}