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})
|
2021-03-10 17:21:49 -08:00
|
|
|
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 {
|
|
|
|
|
2021-03-10 17:21:49 -08:00
|
|
|
options.fudo.auth.kdc = with types; {
|
2020-01-15 09:24:11 -08:00
|
|
|
enable = mkEnableOption "Fudo KDC";
|
|
|
|
|
2021-03-10 17:21:49 -08:00
|
|
|
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 {
|
2021-03-10 17:21:49 -08:00
|
|
|
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 {
|
2021-03-10 17:21:49 -08:00
|
|
|
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 ]; };
|
2021-03-10 17:21:49 -08:00
|
|
|
|
|
|
|
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 = {
|
2021-03-10 17:21:49 -08:00
|
|
|
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).";
|
2021-03-10 17:21:49 -08:00
|
|
|
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}";
|
|
|
|
};
|
2021-03-10 17:21:49 -08:00
|
|
|
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-10 17:21:49 -08:00
|
|
|
};
|
|
|
|
|
2021-03-13 16:22:23 -08:00
|
|
|
mit-kadmin = {
|
2021-03-10 17:21:49 -08:00
|
|
|
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.";
|
2021-03-10 17:21:49 -08:00
|
|
|
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}";
|
|
|
|
};
|
2021-03-10 17:21:49 -08:00
|
|
|
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
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
}
|