2024-01-13 08:15:51 +00:00
|
|
|
{ pkgs, lib, ... }:
|
|
|
|
|
|
|
|
# Based on
|
|
|
|
# - https://web.mit.edu/kerberos/krb5-1.12/doc/admin/conf_files/krb5_conf.html
|
|
|
|
# - https://manpages.debian.org/unstable/heimdal-docs/krb5.conf.5heimdal.en.html
|
|
|
|
|
|
|
|
let
|
|
|
|
inherit (lib) boolToString concatMapStringsSep concatStringsSep filter
|
2024-04-21 15:54:59 +00:00
|
|
|
isAttrs isBool isList mapAttrsToList mkOption singleton splitString;
|
2024-06-20 14:57:18 +00:00
|
|
|
inherit (lib.types) attrsOf bool coercedTo either enum int listOf oneOf
|
|
|
|
path str submodule;
|
2024-01-13 08:15:51 +00:00
|
|
|
in
|
2024-06-20 14:57:18 +00:00
|
|
|
{
|
|
|
|
enableKdcACLEntries ? false
|
|
|
|
}: rec {
|
|
|
|
sectionType = let
|
|
|
|
relation = oneOf [
|
|
|
|
(listOf (attrsOf value))
|
|
|
|
(attrsOf value)
|
|
|
|
value
|
|
|
|
];
|
2024-01-13 08:15:51 +00:00
|
|
|
value = either (listOf atom) atom;
|
|
|
|
atom = oneOf [int str bool];
|
2024-06-20 14:57:18 +00:00
|
|
|
in attrsOf relation;
|
|
|
|
|
|
|
|
type = let
|
|
|
|
aclEntry = submodule {
|
|
|
|
options = {
|
|
|
|
principal = mkOption {
|
|
|
|
type = str;
|
|
|
|
description = "Which principal the rule applies to";
|
|
|
|
};
|
|
|
|
access = mkOption {
|
|
|
|
type = either
|
|
|
|
(listOf (enum ["add" "cpw" "delete" "get" "list" "modify"]))
|
|
|
|
(enum ["all"]);
|
|
|
|
default = "all";
|
|
|
|
description = "The changes the principal is allowed to make.";
|
|
|
|
};
|
|
|
|
target = mkOption {
|
|
|
|
type = str;
|
|
|
|
default = "*";
|
|
|
|
description = "The principals that 'access' applies to.";
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
realm = submodule ({ name, ... }: {
|
|
|
|
freeformType = sectionType;
|
|
|
|
options = {
|
|
|
|
acl = mkOption {
|
|
|
|
type = listOf aclEntry;
|
|
|
|
default = [
|
|
|
|
{ principal = "*/admin"; access = "all"; }
|
|
|
|
{ principal = "admin"; access = "all"; }
|
|
|
|
];
|
|
|
|
description = ''
|
|
|
|
The privileges granted to a user.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
};
|
|
|
|
});
|
2024-01-13 08:15:51 +00:00
|
|
|
in submodule {
|
2024-06-20 14:57:18 +00:00
|
|
|
freeformType = attrsOf sectionType;
|
2024-01-13 08:15:51 +00:00
|
|
|
options = {
|
|
|
|
include = mkOption {
|
|
|
|
default = [ ];
|
2024-04-21 15:54:59 +00:00
|
|
|
description = ''
|
2024-01-13 08:15:51 +00:00
|
|
|
Files to include in the Kerberos configuration.
|
|
|
|
'';
|
|
|
|
type = coercedTo path singleton (listOf path);
|
|
|
|
};
|
|
|
|
includedir = mkOption {
|
|
|
|
default = [ ];
|
2024-04-21 15:54:59 +00:00
|
|
|
description = ''
|
2024-01-13 08:15:51 +00:00
|
|
|
Directories containing files to include in the Kerberos configuration.
|
|
|
|
'';
|
|
|
|
type = coercedTo path singleton (listOf path);
|
|
|
|
};
|
|
|
|
module = mkOption {
|
|
|
|
default = [ ];
|
2024-04-21 15:54:59 +00:00
|
|
|
description = ''
|
2024-01-13 08:15:51 +00:00
|
|
|
Modules to obtain Kerberos configuration from.
|
|
|
|
'';
|
|
|
|
type = coercedTo path singleton (listOf path);
|
|
|
|
};
|
2024-06-20 14:57:18 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
//
|
|
|
|
(lib.optionalAttrs enableKdcACLEntries {
|
|
|
|
realms = mkOption {
|
|
|
|
type = attrsOf realm;
|
|
|
|
description = ''
|
|
|
|
The realm(s) to serve keys for.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
});
|
2024-01-13 08:15:51 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
generate = let
|
|
|
|
indent = str: concatMapStringsSep "\n" (line: " " + line) (splitString "\n" str);
|
|
|
|
|
|
|
|
formatToplevel = args @ {
|
|
|
|
include ? [ ],
|
|
|
|
includedir ? [ ],
|
|
|
|
module ? [ ],
|
|
|
|
...
|
|
|
|
}: let
|
|
|
|
sections = removeAttrs args [ "include" "includedir" "module" ];
|
|
|
|
in concatStringsSep "\n" (filter (x: x != "") [
|
|
|
|
(concatStringsSep "\n" (mapAttrsToList formatSection sections))
|
|
|
|
(concatMapStringsSep "\n" (m: "module ${m}") module)
|
|
|
|
(concatMapStringsSep "\n" (i: "include ${i}") include)
|
|
|
|
(concatMapStringsSep "\n" (i: "includedir ${i}") includedir)
|
|
|
|
]);
|
|
|
|
|
|
|
|
formatSection = name: section: ''
|
|
|
|
[${name}]
|
|
|
|
${indent (concatStringsSep "\n" (mapAttrsToList formatRelation section))}
|
|
|
|
'';
|
|
|
|
|
|
|
|
formatRelation = name: relation:
|
|
|
|
if isAttrs relation
|
|
|
|
then ''
|
|
|
|
${name} = {
|
|
|
|
${indent (concatStringsSep "\n" (mapAttrsToList formatValue relation))}
|
|
|
|
}''
|
2024-06-20 14:57:18 +00:00
|
|
|
else if isList relation
|
|
|
|
then
|
|
|
|
concatMapStringsSep "\n" (formatRelation name) relation
|
2024-01-13 08:15:51 +00:00
|
|
|
else formatValue name relation;
|
|
|
|
|
|
|
|
formatValue = name: value:
|
|
|
|
if isList value
|
|
|
|
then concatMapStringsSep "\n" (formatAtom name) value
|
|
|
|
else formatAtom name value;
|
|
|
|
|
|
|
|
formatAtom = name: atom: let
|
|
|
|
v = if isBool atom then boolToString atom else toString atom;
|
|
|
|
in "${name} = ${v}";
|
|
|
|
in
|
|
|
|
name: value: pkgs.writeText name ''
|
|
|
|
${formatToplevel value}
|
|
|
|
'';
|
|
|
|
}
|