nixos-config/lib/fudo/kdc.nix

281 lines
8.4 KiB
Nix
Raw Normal View History

2020-01-15 09:24:11 -08:00
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.fudo.auth.kdc;
2021-03-15 12:39:57 -07:00
kerberos-database = "${cfg.state-directory}/kerberos.db";
2021-03-13 16:22:23 -08:00
get-domain-hosts = domain:
mapAttrsToList (host: hostOpts: "${host}.${domain}")
(filterAttrs (host: hostOpts: hostOpts.domain == domain) config.fudo.hosts);
2021-03-15 12:39:57 -07:00
add-host-principals = realm: db-name: host: ''
${pkgs.krb5}/bin/kadmin.local -d ${db-name} addprinc -randkey host/${host} -r ${realm}
${pkgs.krb5}/bin/kadmin.local -d ${db-name} addprinc -randkey ssh/${host} -r ${realm}
2021-03-13 16:22:23 -08:00
'';
2021-03-15 12:39:57 -07:00
initialize-db = realm: kdc-conf: user: group: key-file: db-name:
pkgs.writeShellScript "initialize-kdc-db.sh" ''
if [ ! -e ${db-name} ]; then
KRB5_CONFIG=/etc/krb5.conf
KRB5_KDC_PROFILE=${kdc-conf}
PWD=$(${pkgs.pwgen}/bin/pwgen 40 1)
printf "$PWD\n$PWD\n$PWD\n" | ${pkgs.krb5}/bin/kdb5_util -r ${realm} -sf ${key-file} -d ${db-name} -m create -s
${pkgs.coreutils}/bin/chown -R ${user}:${group} $(dirname ${db-name})
fi
'';
2020-01-15 09:24:11 -08:00
2021-03-15 12:39:57 -07:00
initialize-kadmin = realm: db-name: user: group: kadmin-keytab: host:
let
domain = toLower realm;
hosts = get-domain-hosts domain;
2021-03-13 16:22:23 -08:00
in pkgs.writeShellScript "initialize-kadmin.sh" ''
if [ ! -e ${kadmin-keytab} ]; then
2021-03-15 12:39:57 -07:00
# ${pkgs.krb5}/bin/kadmin.local -d ${db-name} addprinc -randkey kadmin/${host}.${domain}
# ${pkgs.krb5}/bin/kadmin.local -d ${db-name} ktadd -k ${kadmin-keytab} kadmin/${host}.${domain}
2021-03-13 16:22:23 -08:00
# TODO: extract kadmin keytab
2021-03-15 12:39:57 -07:00
# ${
concatStringsSep "\n" (map (add-host-principals realm db-name) hosts)
}
2021-03-13 16:22:23 -08:00
fi
'';
generate-kdc-conf =
2021-03-15 12:39:57 -07:00
realm: database: kdc-listen-addrs: kadmin-listen-addrs: kpasswd-listen-addrs: acl-file: kadmin-keytab: key-stash-file:
2021-03-13 16:22:23 -08:00
pkgs.writeText "kdc.conf" ''
[kdcdefaults]
2021-03-15 12:39:57 -07:00
kdc_listen = ${concatStringsSep "," kdc-listen-addrs}
kdc_tcp_listen = ${concatStringsSep "," kdc-listen-addrs}
2021-03-13 16:22:23 -08:00
[realm]
${realm} = {
2021-03-15 12:39:57 -07:00
kadmind_listen = ${concatStringsSep "," kadmin-listen-addrs}
kpasswd_listen = ${concatStringsSep "," kpasswd-listen-addrs}
2021-03-13 16:22:23 -08:00
max_life = 24h 0m 0s
max_renewable_life = 14d 0h 0m 0s
acl_file = ${acl-file}
admin_keytab = ${kadmin-keytab}
key_stash_file = ${key-stash-file}
}
[dbmodules]
${realm} = {
database_name = ${database}
db_library = db2
}
2021-03-15 12:39:57 -07:00
[logging]
kdc = SYSLOG
admin_server = SYSLOG
default = SYSLOG
2021-03-13 16:22:23 -08:00
'';
perm-map = {
"add" = "a";
"all" = "x";
"password" = "c";
"delete" = "d";
"inquire" = "i";
"list" = "l";
"modify" = "m";
"propagate" = "p";
"set-key" = "s";
};
perms-to-permstring = perms:
concatStringsSep "" (map (perm: perm-map.${perm}) perms);
aclEntry = { principal, ... }: {
options = with types; {
perms = mkOption {
type = listOf (enum (attrNames perm-map));
description = "List of permissions.";
default = [ ];
};
target = mkOption {
type = nullOr str;
description = "Target principals.";
default = null;
example = "hosts/*@REALM.COM";
};
};
};
2021-03-15 12:39:57 -07:00
generate-acl-file = acl-entries:
2021-03-13 16:22:23 -08:00
pkgs.writeText "kdc.acl" (concatStringsSep "\n" (mapAttrsToList
(principal: opts:
"${principal} ${perms-to-permstring opts.perms}${
optionalString (opts.target != null) " ${opts.target}"
}") acl-entries));
2021-03-15 12:39:57 -07:00
acl-file = generate-acl-file cfg.acl;
kdc-listen-addrs = map (ip: "${ip}:88") cfg.bind-addresses;
kadmin-listen-addrs = map (ip: "${ip}:749") cfg.bind-addresses;
kpasswd-listen-addrs = map (ip: "${ip}:464") cfg.bind-addresses;
kdc-conf = generate-kdc-conf cfg.realm kerberos-database kdc-listen-addrs
kadmin-listen-addrs kpasswd-listen-addrs acl-file cfg.kadmin-keytab
cfg.master-key-file;
2020-01-15 09:24:11 -08:00
in {
options.fudo.auth.kdc = with types; {
2020-01-15 09:24:11 -08:00
enable = mkEnableOption "Fudo KDC";
realm = mkOption {
type = str;
description = "The realm for which we are the acting KDC.";
2020-01-15 09:24:11 -08:00
};
2021-03-13 16:22:23 -08:00
acl = mkOption {
type = attrsOf (submodule aclEntry);
description = "Mapping of pricipals to a list of permissions.";
2021-03-15 12:39:57 -07:00
default = { "*/admin" = [ "all" ]; };
2021-03-13 16:22:23 -08:00
example = {
"*/root" = [ "all" ];
"admin-user" = [ "add" "list" "modify" ];
};
2020-01-15 09:24:11 -08:00
};
bind-addresses = mkOption {
type = listOf str;
description = "A list of IP addresses on which to bind.";
default = [ ];
};
user = mkOption {
type = str;
description = "User as which to run Heimdal servers.";
default = "kerberos";
};
group = mkOption {
type = str;
description = "Group as which to run Heimdal servers.";
default = "kerberos";
};
state-directory = mkOption {
type = str;
description = "Path at which to store kerberos database.";
2021-03-13 16:22:23 -08:00
default = "/var/kerberos";
};
master-key-file = mkOption {
type = str;
description = "File containing the master key for the realm.";
default = "/var/kerberos/master.key";
};
kadmin-keytab = mkOption {
type = str;
description = "Location of keytab for kadmind.";
default = "/var/kerberos/kadmind.keytab";
2020-01-15 09:24:11 -08:00
};
};
config = mkIf cfg.enable {
users = {
users.${cfg.user} = {
isSystemUser = true;
home = "/var/heimdal";
group = cfg.group;
};
groups.${cfg.group} = { members = [ cfg.user ]; };
};
2021-03-15 12:39:57 -07:00
krb5 = {
libdefaults = { default_realm = mkDefault cfg.realm; };
realms.${cfg.realm} = { key_stash_file = cfg.master-key-file; };
extraConfig = mkAfter ''
[dbmodules]
${cfg.realm} = {
database_name = ${kerberos-database}
}
[realm]
${cfg.realm} = {
kadmind_listen = ${concatStringsSep "," kadmin-listen-addrs}
kpasswd_listen = ${concatStringsSep "," kpasswd-listen-addrs}
acl_file = ${acl-file}
admin_keytab = ${cfg.kadmin-keytab}
key_stash_file = ${cfg.master-key-file}
}
'';
};
environment = { systemPackages = [ pkgs.kerberos pkgs.krb5 ]; };
fudo.system = {
ensure-directories = {
"${cfg.state-directory}" = {
user = cfg.user;
group = cfg.group;
2021-03-13 16:22:23 -08:00
perms = "0740";
2020-01-15 09:24:11 -08:00
};
2021-03-15 12:39:57 -07:00
"/run/mit-kdc" = {
user = cfg.user;
group = cfg.group;
perms = "0744";
2021-03-13 16:22:23 -08:00
};
2021-03-15 12:39:57 -07:00
"/run/mit-kadmin" = {
user = cfg.user;
group = cfg.group;
perms = "0744";
2021-03-13 16:22:23 -08:00
};
};
2021-03-15 12:39:57 -07:00
services = {
2021-03-13 16:22:23 -08:00
mit-kdc = {
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
2021-03-13 16:22:23 -08:00
type = "forking";
description = "MIT Kerberos Key Distribution Center (ticket server).";
execStart =
2021-03-15 12:39:57 -07:00
"${pkgs.krb5}/bin/krb5kdc -r ${cfg.realm} -d ${kerberos-database} -P /run/mit-kdc/mit-kdc.pid";
readWritePaths = [ "/run/mit-kdc" ];
2021-03-13 16:22:23 -08:00
environment = {
KRB5_CONFIG = "/etc/krb5.conf";
KRB5_KDC_PROFILE = "${kdc-conf}";
};
user = cfg.user;
group = cfg.group;
workingDirectory = cfg.state-directory;
2021-03-15 12:39:57 -07:00
preStart = "${initialize-db cfg.realm kdc-conf cfg.user cfg.group
cfg.master-key-file kerberos-database}";
privateNetwork = false;
addressFamilies = [ "AF_INET" "AF_INET6" ];
requiredCapabilities = [ "CAP_NET_BIND_SERVICE+ep" ];
};
2021-03-13 16:22:23 -08:00
mit-kadmin = {
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
2021-03-13 16:22:23 -08:00
requires = [ "mit-kdc.service" ];
description = "MIT Kerberos Remote Administration Server.";
execStart =
2021-03-15 12:39:57 -07:00
"${pkgs.krb5}/bin/kadmind -r ${cfg.realm} -P /run/mit-kadmin/mit-kadmin.pid";
readWritePaths = [ "/run/mit-kadmin" ];
2021-03-13 16:22:23 -08:00
environment = {
KRB5_CONFIG = "/etc/krb5.conf";
KRB5_KDC_PROFILE = "${kdc-conf}";
};
user = cfg.user;
group = cfg.group;
workingDirectory = cfg.state-directory;
2021-03-15 12:39:57 -07:00
privateNetwork = false;
# postStart =
# "${initialize-kadmin cfg.realm kerberos-database cfg.user cfg.group
# cfg.kadmin-keytab config.networking.hostName}";
addressFamilies = [ "AF_INET" "AF_INET6" ];
requiredCapabilities = [ "CAP_NET_BIND_SERVICE" ];
2020-01-15 09:24:11 -08:00
};
};
};
};
}