Set up nix tooling
This commit is contained in:
69
nix/module/default.nix
Normal file
69
nix/module/default.nix
Normal file
@@ -0,0 +1,69 @@
|
||||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
inherit (lib) mkOption types;
|
||||
cfg = config.services.kerberos_server;
|
||||
inherit (config.security.krb5) package;
|
||||
|
||||
format = import ./krb5-conf-format.nix { inherit pkgs lib; } {
|
||||
enableKdcACLEntries = true;
|
||||
};
|
||||
in
|
||||
|
||||
{
|
||||
imports = [
|
||||
(lib.mkRenamedOptionModule
|
||||
[ "services" "kerberos_server" "realms" ]
|
||||
[ "services" "kerberos_server" "settings" "realms" ]
|
||||
)
|
||||
|
||||
# ./mit.nix
|
||||
./heimdal.nix
|
||||
];
|
||||
|
||||
options = {
|
||||
services.kerberos_server = {
|
||||
enable = lib.mkEnableOption "the kerberos authentication server";
|
||||
|
||||
settings = mkOption {
|
||||
type = format.type;
|
||||
description = ''
|
||||
Settings for the kerberos server of choice.
|
||||
|
||||
See the following documentation:
|
||||
- Heimdal: {manpage}`kdc.conf(5)`
|
||||
- MIT Kerberos: <https://web.mit.edu/kerberos/krb5-1.21/doc/admin/conf_files/kdc_conf.html>
|
||||
'';
|
||||
default = { };
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
environment.systemPackages = [ package ];
|
||||
assertions = [
|
||||
{
|
||||
assertion = cfg.settings.realms != { };
|
||||
message = "The server needs at least one realm";
|
||||
}
|
||||
{
|
||||
assertion = lib.length (lib.attrNames cfg.settings.realms) <= 1;
|
||||
message = "Only one realm per server is currently supported.";
|
||||
}
|
||||
];
|
||||
|
||||
systemd.slices.system-kerberos-server = { };
|
||||
systemd.targets.kerberos-server = {
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
};
|
||||
};
|
||||
|
||||
# meta = {
|
||||
# doc = ./kerberos-server.md;
|
||||
# };
|
||||
}
|
105
nix/module/heimdal.nix
Normal file
105
nix/module/heimdal.nix
Normal file
@@ -0,0 +1,105 @@
|
||||
{
|
||||
pkgs,
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
inherit (lib) mapAttrs;
|
||||
cfg = config.services.kerberos_server;
|
||||
package = config.security.krb5.package;
|
||||
|
||||
aclConfigs = lib.pipe cfg.settings.realms [
|
||||
(mapAttrs (
|
||||
name:
|
||||
{ acl, ... }:
|
||||
lib.concatMapStringsSep "\n" (
|
||||
{
|
||||
principal,
|
||||
access,
|
||||
target,
|
||||
...
|
||||
}:
|
||||
"${principal}\t${lib.concatStringsSep "," (lib.toList access)}\t${target}"
|
||||
) acl
|
||||
))
|
||||
(lib.mapAttrsToList (
|
||||
name: text: {
|
||||
dbname = "/var/lib/heimdal/heimdal";
|
||||
acl_file = pkgs.writeText "${name}.acl" text;
|
||||
}
|
||||
))
|
||||
];
|
||||
|
||||
finalConfig = cfg.settings // {
|
||||
realms = mapAttrs (_: v: removeAttrs v [ "acl" ]) (cfg.settings.realms or { });
|
||||
kdc = (cfg.settings.kdc or { }) // {
|
||||
database = aclConfigs;
|
||||
};
|
||||
};
|
||||
|
||||
format = import ./krb5-conf-format.nix { inherit pkgs lib; } {
|
||||
enableKdcACLEntries = true;
|
||||
};
|
||||
|
||||
kdcConfFile = format.generate "kdc.conf" finalConfig;
|
||||
in
|
||||
|
||||
{
|
||||
config = lib.mkIf (cfg.enable && package.passthru.implementation == "heimdal") {
|
||||
environment.etc."heimdal-kdc/kdc.conf".source = kdcConfFile;
|
||||
|
||||
systemd.tmpfiles.settings."10-heimdal" =
|
||||
let
|
||||
databases = lib.pipe finalConfig.kdc.database [
|
||||
(map (dbAttrs: dbAttrs.dbname or null))
|
||||
(lib.filter (x: x != null))
|
||||
lib.unique
|
||||
];
|
||||
in
|
||||
lib.genAttrs databases (_: {
|
||||
d = {
|
||||
user = "root";
|
||||
group = "root";
|
||||
mode = "0700";
|
||||
};
|
||||
});
|
||||
|
||||
systemd.services.kadmind = {
|
||||
description = "Kerberos Administration Daemon";
|
||||
partOf = [ "kerberos-server.target" ];
|
||||
wantedBy = [ "kerberos-server.target" ];
|
||||
serviceConfig = {
|
||||
ExecStart = "${package}/libexec/kadmind --config-file=/etc/heimdal-kdc/kdc.conf";
|
||||
Slice = "system-kerberos-server.slice";
|
||||
StateDirectory = "heimdal";
|
||||
};
|
||||
restartTriggers = [ kdcConfFile ];
|
||||
};
|
||||
|
||||
systemd.services.kdc = {
|
||||
description = "Key Distribution Center daemon";
|
||||
partOf = [ "kerberos-server.target" ];
|
||||
wantedBy = [ "kerberos-server.target" ];
|
||||
serviceConfig = {
|
||||
ExecStart = "${package}/libexec/kdc --config-file=/etc/heimdal-kdc/kdc.conf";
|
||||
Slice = "system-kerberos-server.slice";
|
||||
StateDirectory = "heimdal";
|
||||
};
|
||||
restartTriggers = [ kdcConfFile ];
|
||||
};
|
||||
|
||||
systemd.services.kpasswdd = {
|
||||
description = "Kerberos Password Changing daemon";
|
||||
partOf = [ "kerberos-server.target" ];
|
||||
wantedBy = [ "kerberos-server.target" ];
|
||||
serviceConfig = {
|
||||
ExecStart = "${package}/libexec/kpasswdd";
|
||||
Slice = "system-kerberos-server.slice";
|
||||
StateDirectory = "heimdal";
|
||||
};
|
||||
restartTriggers = [ kdcConfFile ];
|
||||
};
|
||||
};
|
||||
}
|
204
nix/module/krb5-conf-format.nix
Normal file
204
nix/module/krb5-conf-format.nix
Normal file
@@ -0,0 +1,204 @@
|
||||
{ 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 =
|
||||
let
|
||||
relation = oneOf [
|
||||
(listOf (attrsOf value))
|
||||
(attrsOf value)
|
||||
value
|
||||
];
|
||||
value = either (listOf atom) atom;
|
||||
atom = oneOf [
|
||||
int
|
||||
str
|
||||
bool
|
||||
];
|
||||
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.
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
);
|
||||
in
|
||||
submodule {
|
||||
freeformType = attrsOf sectionType;
|
||||
options =
|
||||
{
|
||||
include = mkOption {
|
||||
default = [ ];
|
||||
description = ''
|
||||
Files to include in the Kerberos configuration.
|
||||
'';
|
||||
type = coercedTo path singleton (listOf path);
|
||||
};
|
||||
includedir = mkOption {
|
||||
default = [ ];
|
||||
description = ''
|
||||
Directories containing files to include in the Kerberos configuration.
|
||||
'';
|
||||
type = coercedTo path singleton (listOf path);
|
||||
};
|
||||
module = mkOption {
|
||||
default = [ ];
|
||||
description = ''
|
||||
Modules to obtain Kerberos configuration from.
|
||||
'';
|
||||
type = coercedTo path singleton (listOf path);
|
||||
};
|
||||
|
||||
}
|
||||
// (lib.optionalAttrs enableKdcACLEntries {
|
||||
realms = mkOption {
|
||||
type = attrsOf realm;
|
||||
description = ''
|
||||
The realm(s) to serve keys for.
|
||||
'';
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
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))}
|
||||
}''
|
||||
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:
|
||||
let
|
||||
v = if isBool atom then boolToString atom else toString atom;
|
||||
in
|
||||
"${name} = ${v}";
|
||||
in
|
||||
name: value:
|
||||
pkgs.writeText name ''
|
||||
${formatToplevel value}
|
||||
'';
|
||||
}
|
Reference in New Issue
Block a user