A bunch of changes...
This commit is contained in:
parent
45f924111f
commit
9f7ab64d09
|
@ -88,9 +88,12 @@ in {
|
||||||
|
|
||||||
auth.kdc = {
|
auth.kdc = {
|
||||||
enable = true;
|
enable = true;
|
||||||
realm = "SELBY.CA";
|
realm = "RUS.SELBY.CA";
|
||||||
acl-file = "/var/heimdal/access.acl";
|
|
||||||
bind-addresses = [ "10.0.0.1" "127.0.0.1" "::1" ];
|
bind-addresses = [ "10.0.0.1" "127.0.0.1" "::1" ];
|
||||||
|
acl = {
|
||||||
|
"niten" = { perms = [ "all" ]; };
|
||||||
|
"*/root" = { perms = [ "password" "list" ]; };
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
secure-dns-proxy = {
|
secure-dns-proxy = {
|
||||||
|
|
|
@ -22,6 +22,18 @@ in {
|
||||||
|
|
||||||
system.autoUpgrade.enable = true;
|
system.autoUpgrade.enable = true;
|
||||||
|
|
||||||
|
krb5 = {
|
||||||
|
libdefaults = {
|
||||||
|
allow_weak_crypto = false;
|
||||||
|
dns_lookup_kdc = true;
|
||||||
|
forwardable = true;
|
||||||
|
ignore_acceptor_hostname = true;
|
||||||
|
noaddresses = true;
|
||||||
|
rdns = false;
|
||||||
|
proxiable = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
services = {
|
services = {
|
||||||
openssh = {
|
openssh = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
|
258
lib/fudo/kdc.nix
258
lib/fudo/kdc.nix
|
@ -4,13 +4,101 @@ with lib;
|
||||||
let
|
let
|
||||||
cfg = config.fudo.auth.kdc;
|
cfg = config.fudo.auth.kdc;
|
||||||
|
|
||||||
initialize-db = realm: key-file:
|
get-domain-hosts = domain:
|
||||||
pkgs.writeShellScript "initialize-heimdal-db.sh" ''
|
mapAttrsToList (host: hostOpts: "${host}.${domain}")
|
||||||
if [ ! -e ${key-file} ]; then
|
(filterAttrs (host: hostOpts: hostOpts.domain == domain) config.fudo.hosts);
|
||||||
${pkgs.heimdalFull}/bin/kadmin -l init --realm=${realm} --realm-max-ticket-life=1d --realm-max-renewable-life=2w ${realm}
|
|
||||||
|
add-host-principals = realm: host: ''
|
||||||
|
${pkgs.kerberos}/bin/kadmin.local addprinc -randkey host/${host} -r ${realm}
|
||||||
|
${pkgs.kerberos}/bin/kadmin.local addprinc -randkey ssh/${host} -r ${realm}
|
||||||
|
'';
|
||||||
|
|
||||||
|
initialize-db = realm: user: group: key-file: db-file:
|
||||||
|
let
|
||||||
|
domain = toLower realm;
|
||||||
|
hosts = get-domain-hosts domain;
|
||||||
|
in pkgs.writeShellScript "initialize-kdc-db.sh" ''
|
||||||
|
if [ ! -e ${db-file} ]; then
|
||||||
|
PWD=$(${pkgs.pwgen}/bin/pwgen -n1 -y 40)
|
||||||
|
${pkgs.krb5}/bin/kdb5_util -r ${realm} -sf ${key-file} -d ${db-file} -P $PWD -m create -s
|
||||||
|
${pkgs.coreutils}/bin/chown -R ${user}:${group} $(dirname ${db-file})
|
||||||
|
${concatStringsSep "\n" (map (add-host-principals realm) hosts)}
|
||||||
fi
|
fi
|
||||||
'';
|
'';
|
||||||
|
|
||||||
|
initialize-kadmin = realm: user: group: kadmin-keytab: host:
|
||||||
|
let domain = toLower realm;
|
||||||
|
in pkgs.writeShellScript "initialize-kadmin.sh" ''
|
||||||
|
if [ ! -e ${kadmin-keytab} ]; then
|
||||||
|
${pkgs.krb5}/bin/kadmin.local addprinc -randkey kadmin/${host}.${domain}
|
||||||
|
${pkgs.krb5}/bin/kadmin.local ktadd -k ${kadmin-keytab} kadmin/${host}.${domain}
|
||||||
|
# TODO: extract kadmin keytab
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
|
||||||
|
generate-kdc-conf =
|
||||||
|
realm: database: kdc-listen-ips: kadmind-port: acl-file: kadmin-keytab: key-stash-file:
|
||||||
|
pkgs.writeText "kdc.conf" ''
|
||||||
|
[kdcdefaults]
|
||||||
|
kdc_listen = ${concatStringsSep "," kdc-listen-ips}
|
||||||
|
kdc_tcp_listen = ${concatStringsSep "," kdc-listen-ips}
|
||||||
|
|
||||||
|
[realm]
|
||||||
|
${realm} = {
|
||||||
|
kadmind_port = ${toString kadmind-port}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
|
||||||
|
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";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
kdc-acl-file = acl-entries:
|
||||||
|
pkgs.writeText "kdc.acl" (concatStringsSep "\n" (mapAttrsToList
|
||||||
|
(principal: opts:
|
||||||
|
"${principal} ${perms-to-permstring opts.perms}${
|
||||||
|
optionalString (opts.target != null) " ${opts.target}"
|
||||||
|
}") acl-entries));
|
||||||
|
|
||||||
in {
|
in {
|
||||||
|
|
||||||
options.fudo.auth.kdc = with types; {
|
options.fudo.auth.kdc = with types; {
|
||||||
|
@ -21,21 +109,14 @@ in {
|
||||||
description = "The realm for which we are the acting KDC.";
|
description = "The realm for which we are the acting KDC.";
|
||||||
};
|
};
|
||||||
|
|
||||||
config-file = mkOption {
|
acl = mkOption {
|
||||||
type = str;
|
type = attrsOf (submodule aclEntry);
|
||||||
description = "Path to configuartion file.";
|
description = "Mapping of pricipals to a list of permissions.";
|
||||||
default = "/etc/krb5.conf";
|
default = { };
|
||||||
};
|
example = {
|
||||||
|
"*/root" = [ "all" ];
|
||||||
master-key-file = mkOption {
|
"admin-user" = [ "add" "list" "modify" ];
|
||||||
type = str;
|
};
|
||||||
description = "The path to the master key file.";
|
|
||||||
default = "/var/heimdal/master.key";
|
|
||||||
};
|
|
||||||
|
|
||||||
acl-file = mkOption {
|
|
||||||
type = str;
|
|
||||||
description = "The path to the Access Control file.";
|
|
||||||
};
|
};
|
||||||
|
|
||||||
bind-addresses = mkOption {
|
bind-addresses = mkOption {
|
||||||
|
@ -59,7 +140,43 @@ in {
|
||||||
state-directory = mkOption {
|
state-directory = mkOption {
|
||||||
type = str;
|
type = str;
|
||||||
description = "Path at which to store kerberos database.";
|
description = "Path at which to store kerberos database.";
|
||||||
default = "/srv/kerberos";
|
default = "/var/kerberos";
|
||||||
|
};
|
||||||
|
|
||||||
|
kdc-pid-file = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "PID file for the KDC server.";
|
||||||
|
default = "/var/run/kerberos-kdc.pid";
|
||||||
|
};
|
||||||
|
|
||||||
|
kadmind-pid-file = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "PID file for the Kerberos admin server.";
|
||||||
|
default = "/var/run/kerberos-kadmin.pid";
|
||||||
|
};
|
||||||
|
|
||||||
|
kadmind-internal-port = mkOption {
|
||||||
|
type = port;
|
||||||
|
description = "Local port on which to run kadmind.";
|
||||||
|
default = 7749;
|
||||||
|
};
|
||||||
|
|
||||||
|
kdc-internal-port = mkOption {
|
||||||
|
type = port;
|
||||||
|
description = "Local port on which to run kdc.";
|
||||||
|
default = 7088;
|
||||||
|
};
|
||||||
|
|
||||||
|
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";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -74,63 +191,100 @@ in {
|
||||||
groups.${cfg.group} = { members = [ cfg.user ]; };
|
groups.${cfg.group} = { members = [ cfg.user ]; };
|
||||||
};
|
};
|
||||||
|
|
||||||
environment = {
|
krb5.libdefaults = { default_realm = mkForce cfg.realm; };
|
||||||
systemPackages = [ pkgs.heimdalFull ];
|
|
||||||
|
|
||||||
etc."krb5.conf" = {
|
environment = { systemPackages = [ pkgs.kerberos ]; };
|
||||||
text = mkAfter ''
|
|
||||||
[kdc]
|
|
||||||
database = {
|
|
||||||
realm = ${cfg.realm}
|
|
||||||
mkey_file = ${cfg.master-key-file}
|
|
||||||
acl_file = ${cfg.acl-file}
|
|
||||||
}
|
|
||||||
addresses = ${concatStringsSep " " cfg.bind-addresses}
|
|
||||||
|
|
||||||
# Binds to port 80!
|
# services.xinitd = {
|
||||||
enable-http = false
|
# enable = true;
|
||||||
'';
|
# services = [
|
||||||
};
|
# {
|
||||||
};
|
# name = "kdc";
|
||||||
|
# unlisted = true;
|
||||||
systemd = {
|
# port = 88;
|
||||||
tmpfiles.rules = [ "L /var/heimdal - - - - ${cfg.state-directory}" ];
|
# server = "/usr/bin/env";
|
||||||
};
|
# extraConfig = "redirect = localhost ${cfg.kdc-internal-port}";
|
||||||
|
# }
|
||||||
|
# {
|
||||||
|
# name = "kadmin";
|
||||||
|
# unlisted = true;
|
||||||
|
# port = 749;
|
||||||
|
# server = "/usr/bin/env";
|
||||||
|
# extraConfig = "redirect = localhost ${cfg.kadmin-internal-port}";
|
||||||
|
# }
|
||||||
|
# ];
|
||||||
|
# };
|
||||||
|
|
||||||
fudo.system = {
|
fudo.system = {
|
||||||
ensure-directories = {
|
ensure-directories = {
|
||||||
"${cfg.state-directory}" = {
|
"${cfg.state-directory}" = {
|
||||||
user = cfg.user;
|
user = cfg.user;
|
||||||
group = cfg.group;
|
group = cfg.group;
|
||||||
|
perms = "0740";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
services = {
|
internal-port-map = {
|
||||||
heimdal-kdc = {
|
kdc = {
|
||||||
|
internal-port = cfg.kdc-internal-port;
|
||||||
|
external-port = 88;
|
||||||
|
};
|
||||||
|
kadmin = {
|
||||||
|
internal-port = cfg.kadmind-internal-port;
|
||||||
|
external-port = 749;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services = let
|
||||||
|
kerberos-database = "${cfg.state-directory}/kerberos.db";
|
||||||
|
acl-file = kdc-acl-file cfg.acl;
|
||||||
|
kdc-listen-addrs = map (ip: "${ip}:${toString cfg.kdc-internal-port}") [
|
||||||
|
"127.0.0.1"
|
||||||
|
"::1"
|
||||||
|
];
|
||||||
|
|
||||||
|
kdc-conf =
|
||||||
|
generate-kdc-conf cfg.realm kerberos-database kdc-listen-addrs
|
||||||
|
cfg.kadmind-internal-port acl-file cfg.kadmin-keytab
|
||||||
|
cfg.master-key-file;
|
||||||
|
|
||||||
|
in {
|
||||||
|
mit-kdc = {
|
||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
after = [ "network.target" ];
|
after = [ "network.target" ];
|
||||||
description =
|
type = "forking";
|
||||||
"Heimdal Kerberos Key Distribution Center (ticket server).";
|
description = "MIT Kerberos Key Distribution Center (ticket server).";
|
||||||
execStart =
|
execStart =
|
||||||
"${pkgs.heimdalFull}/libexec/heimdal/kdc --config-file=${cfg.config-file}";
|
"${pkgs.krb5}/bin/krb5kdc -r ${cfg.realm} -d ${kerberos-database} -P ${cfg.kdc-pid-file} -M ${cfg.master-key-file}";
|
||||||
privateNetwork = false;
|
environment = {
|
||||||
|
KRB5_CONFIG = "/etc/krb5.conf";
|
||||||
|
KRB5_KDC_PROFILE = "${kdc-conf}";
|
||||||
|
};
|
||||||
user = cfg.user;
|
user = cfg.user;
|
||||||
group = cfg.group;
|
group = cfg.group;
|
||||||
workingDirectory = cfg.state-directory;
|
workingDirectory = cfg.state-directory;
|
||||||
preStart = "${initialize-db cfg.realm cfg.master-key-file}";
|
preStart =
|
||||||
|
"${initialize-db cfg.realm cfg.user cfg.group cfg.master-key-file
|
||||||
|
kerberos-database}";
|
||||||
};
|
};
|
||||||
|
|
||||||
heimdal-admin-server = {
|
mit-kadmin = {
|
||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
after = [ "network.target" ];
|
after = [ "network.target" ];
|
||||||
description = "Heimdal Kerberos Remote Administration Server.";
|
requires = [ "mit-kdc.service" ];
|
||||||
|
description = "MIT Kerberos Remote Administration Server.";
|
||||||
execStart =
|
execStart =
|
||||||
"${pkgs.heimdalFull}/libexec/heimdal/kadmind --config-file=${cfg.config-file} --key-file=${cfg.master-key-file}";
|
"${pkgs.kerberos}/bin/kadmind -r ${cfg.realm} -P ${cfg.kadmind-pid-file}";
|
||||||
privateNetwork = false;
|
environment = {
|
||||||
|
KRB5_CONFIG = "/etc/krb5.conf";
|
||||||
|
KRB5_KDC_PROFILE = "${kdc-conf}";
|
||||||
|
};
|
||||||
user = cfg.user;
|
user = cfg.user;
|
||||||
group = cfg.group;
|
group = cfg.group;
|
||||||
workingDirectory = cfg.state-directory;
|
workingDirectory = cfg.state-directory;
|
||||||
preStart = "${initialize-db cfg.realm cfg.master-key-file}";
|
preStart =
|
||||||
|
"${initialize-kadmin cfg.realm cfg.user cfg.group cfg.kadmin-keytab
|
||||||
|
config.networking.hostName}";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -332,6 +332,25 @@ let
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
portMappingOpts = { name, ... }: {
|
||||||
|
options = with types; {
|
||||||
|
internal-port = mkOption {
|
||||||
|
type = port;
|
||||||
|
description = "Port on localhost to recieve traffic";
|
||||||
|
};
|
||||||
|
external-port = mkOption {
|
||||||
|
type = port;
|
||||||
|
description = "External port on which to listen for traffic.";
|
||||||
|
};
|
||||||
|
protocol = mkOption {
|
||||||
|
type = nullOr str;
|
||||||
|
description =
|
||||||
|
"Protocol for which to forward ports. Default is tcp & udp.";
|
||||||
|
default = null;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
in {
|
in {
|
||||||
options.fudo.system = with types; {
|
options.fudo.system = with types; {
|
||||||
services = mkOption {
|
services = mkOption {
|
||||||
|
@ -351,6 +370,20 @@ in {
|
||||||
description = "A map of required directories to directory properties.";
|
description = "A map of required directories to directory properties.";
|
||||||
default = { };
|
default = { };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
internal-port-map = mkOption {
|
||||||
|
type = attrsOf (submodule portMappingOpts);
|
||||||
|
description =
|
||||||
|
"Sets of external ports to internal (i.e. localhost) ports to forward.";
|
||||||
|
default = { };
|
||||||
|
example = {
|
||||||
|
sshmap = {
|
||||||
|
internal-port = 2222;
|
||||||
|
external-port = 22;
|
||||||
|
protocol = "udp";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
|
@ -361,6 +394,37 @@ in {
|
||||||
# };
|
# };
|
||||||
# }) (filterAttrs (name: opts: opts.networkWhitelist != null) cfg.services);
|
# }) (filterAttrs (name: opts: opts.networkWhitelist != null) cfg.services);
|
||||||
|
|
||||||
|
boot.kernel.sysctl = mkIf (cfg.internal-port-map != { }) {
|
||||||
|
"net.ipv4.conf.all.route_localhost" = "1";
|
||||||
|
};
|
||||||
|
|
||||||
|
networking.firewall = let
|
||||||
|
ip-forward-line = protocols: internal: external:
|
||||||
|
concatStringsSep "\n" (map (protocol:
|
||||||
|
"${pkgs.iptables}/bin/iptables -t nat -I PREROUTING -p ${protocol} --dport ${
|
||||||
|
toString external
|
||||||
|
} -j DNAT --to 127.0.0.1:${toString internal}") protocols);
|
||||||
|
|
||||||
|
ip-unforward-line = protocols: internal: external:
|
||||||
|
concatStringsSep "\n" (map (protocol:
|
||||||
|
"${pkgs.iptables}/bin/iptables -t nat -D PREROUTING -p ${protocol} --dport ${
|
||||||
|
toString external
|
||||||
|
} -j DNAT --to 127.0.0.1:${toString internal} || true") protocols);
|
||||||
|
|
||||||
|
protocol-list = protocol:
|
||||||
|
if (protocol == null) then [ "tcp" "udp" ] else [ protocol ];
|
||||||
|
in {
|
||||||
|
extraCommands = mkAfter (concatStringsSep "\n" (mapAttrsToList
|
||||||
|
(name: opts:
|
||||||
|
ip-forward-line (protocol-list opts.protocol) opts.internal-port
|
||||||
|
opts.external-port) cfg.internal-port-map));
|
||||||
|
|
||||||
|
extraStopCommands = mkAfter (concatStringsSep "\n" (mapAttrsToList
|
||||||
|
(name: opts:
|
||||||
|
ip-unforward-line (protocol-list opts.protocol) opts.internal-port
|
||||||
|
opts.external-port) cfg.internal-port-map));
|
||||||
|
};
|
||||||
|
|
||||||
systemd.timers = mapAttrs (name: opts: {
|
systemd.timers = mapAttrs (name: opts: {
|
||||||
enable = true;
|
enable = true;
|
||||||
description = opts.description;
|
description = opts.description;
|
||||||
|
|
Loading…
Reference in New Issue