{ 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
isAttrs
isBool
isList
mapAttrsToList
mkOption
singleton
splitString
;
inherit (lib.types)
attrsOf
bool
coercedTo
either
enum
int
listOf
oneOf
path
str
submodule
in
{
enableKdcACLEntries ? false,
}:
rec {
sectionType =
relation = oneOf [
(listOf (attrsOf value))
(attrsOf value)
value
];
value = either (listOf atom) atom;
atom = oneOf [
attrsOf relation;
type =
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 {
default = "*";
description = "The principals that 'access' applies to.";
realm = submodule (
{ name, ... }:
freeformType = sectionType;
acl = mkOption {
type = listOf aclEntry;
default = [
principal = "*/admin";
access = "all";
}
principal = "admin";
description = ''
The privileges granted to a user.
'';
);
submodule {
freeformType = attrsOf sectionType;
options =
include = mkOption {
default = [ ];
Files to include in the Kerberos configuration.
type = coercedTo path singleton (listOf path);
includedir = mkOption {
Directories containing files to include in the Kerberos configuration.
module = mkOption {
Modules to obtain Kerberos configuration from.
// (lib.optionalAttrs enableKdcACLEntries {
realms = mkOption {
type = attrsOf realm;
The realm(s) to serve keys for.
});
generate =
indent = str: concatMapStringsSep "\n" (line: " " + line) (splitString "\n" str);
formatToplevel =
args@{
include ? [ ],
includedir ? [ ],
module ? [ ],
...
sections = removeAttrs args [
"include"
"includedir"
"module"
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))}
}''
else if isList relation then
concatMapStringsSep "\n" (formatRelation name) relation
else
formatValue name relation;
formatValue =
name: value:
if isList value then concatMapStringsSep "\n" (formatAtom name) value else formatAtom name value;
formatAtom =
name: atom:
v = if isBool atom then boolToString atom else toString atom;
"${name} = ${v}";
pkgs.writeText name ''
${formatToplevel value}