Need to get more disciplined about git...

This commit is contained in:
niten 2023-01-28 13:45:24 -08:00
parent c7e98dcb27
commit 5e602e9ff4
12 changed files with 629 additions and 36 deletions

View File

@ -0,0 +1,5 @@
{ config, lib, pkgs, ... }:
{
imports = [ ./kerberos ];
}

View File

@ -0,0 +1,44 @@
{ config, lib, pkgs, ... }:
let realm = config.fudo.auth.kerberos.realm;
in {
imports = [ ./kdc.nix ];
config = {
krb5 = {
enable = true;
kerberos = pkgs.heimdal;
libdefaults = {
default_realm = realm;
allow_weak_crypto = false;
dns_lookup_kdc = true;
dns_lookup_realm = true;
forwardable = true;
proxiable = true;
};
appdefaults = {
forwardable = true;
proxiable = true;
encrypt = true;
forward = true;
};
};
security.pam.krb5.enable = true;
services.openssh = {
extraConfig = ''
GSSAPIAuthentication yes
GSSAPICleanupCredentials yes
'';
};
programs.ssh = {
extraConfig = ''
GSSAPIAuthentication yes
GSSAPIDelegateCredentials yes
'';
};
};
}

View File

@ -0,0 +1,533 @@
{ config, pkgs, lib, ... }@toplevel:
with lib;
let
hostname = cfg.instance.hostname;
ifAddrs = ifInfo:
let addrOnly = addrInfo: addrInfo.address;
in (map addrOnly (trace ifInfo.ipv4 ifInfo.ipv4).addresses)
++ (map addrOnly ifInfo.ipv6.addresses);
primaryConfig = { config, lib, pkgs, ... }:
let
cfg = config.fudo.auth.kerberos;
hasSecondary = cfg.kdc.primary.secondary-servers != [ ];
aclFile = let
aclEntryToString = _:
{ principal, perms, target, ... }:
let
in "${principal} ${concatStringsSep "," perms}${
optionalString (target != null) " ${target}"
}";
in pkgs.writeText "kdc.acl" (concatStringsSep "\n"
(mapAttrsToList aclEntryToString cfg.kdc.primary.acl));
kdcConf = pkgs.writeText "kdc.conf" ''
[kdc]
database = {
realm = ${cfg.realm}
dbname = sqlite:${cfg.kdc.database}
mkey_file = ${cfg.kdc.master-key-file}
acl_file = ${aclFile}
log_file = /dev/null
}
[realms]
${cfg.realm} = {
enable-http = false;
}
[libdefaults]
default_realm = ${cfg.realm}
allow_weak_crypto = false
[logging]
kdc = FILE:${cfg.kdc.state-directory}/kerberos.log
default = FILE:${cfg.kdc.state-directory}/kerberos.log
'';
kadminLocal = pkgs.writeShellApplication {
name = "kadmin.local";
runtimeInputs = with pkgs; [ heimdal ];
text = ''kadmin --local --config-file=${kdcConf} -- "$@"'';
};
in {
config = mkIf cfg.kdc.primary.enable {
users = {
users."${cfg.user}" = {
isSystemUser = true;
group = cfg.group;
};
groups."${cfg.group}" = { members = [ cfg.user ]; };
};
environment.systemPackages = [ kadminLocal ];
systemd = {
services = {
heimdal-kdc = {
wantedBy = [ "multi-user.target" ];
after = [ "network-online.target" ];
description =
"Heimdal Kerberos Key Distribution Center (primary ticket server).";
path = with pkgs; [ heimdal ];
serviceConfig = {
PrivateDevices = true;
PrivateTmp = true;
# PrivateMounts = true;
ProtectControlGroups = true;
ProtectKernelTunables = true;
# ProtectSystem = true;
ProtectHostname = true;
# ProtectHome = true;
ProtectClock = true;
ProtectKernelLogs = true;
MemoryDenyWriteExecute = true;
RestrictRealtime = true;
# LockPersonality = true;
# PermissionsStartOnly = true;
LimitNOFILE = 4096;
User = cfg.user;
Group = cfg.group;
Restart = "always";
RestartSec = "5s";
AmbientCapabilities = "CAP_NET_BIND_SERVICE";
SecureBits = "keep-caps";
ExecStart = let
ips = if (cfg.kdc.bind-addresses != [ ]) then
cfg.kdc.bind-addresses
else
[ "0.0.0.0" ];
bindClause = "--addresses=${concatStringsSep "," ips}";
in "${pkgs.heimdal}/libexec/heimdal/kdc --config-file=${kdcConf} --ports=88 ${bindClause}";
};
};
heimdal-kadmind = {
wantedBy = [ "heimdal-kdc.service" ];
after = [ "heimdal-kdc.service" ];
bindsTo = [ "heimdal-kdc.service" ];
description = "Heimdal Kerberos Administration Server.";
path = with pkgs; [ heimdal ];
serviceConfig = {
# StandardInput = "socket";
# StandardOutput = "socket";
PrivateDevices = true;
PrivateTmp = true;
# PrivateMounts = true;
ProtectControlGroups = true;
ProtectKernelTunables = true;
# ProtectSystem = true;
ProtectHostname = true;
# ProtectHome = true;
ProtectClock = true;
ProtectKernelLogs = true;
MemoryDenyWriteExecute = true;
RestrictRealtime = true;
# LockPersonality = true;
# PermissionsStartOnly = true;
LimitNOFILE = 4096;
User = cfg.user;
Group = cfg.group;
Restart = "always";
RestartSec = "5s";
AmbientCapabilities = "CAP_NET_BIND_SERVICE";
SecureBits = "keep-caps";
ExecStart = concatStringsSep " " [
"${pkgs.heimdal}/libexec/heimdal/kadmind"
"--config-file=${kdcConf}"
"--keytab=${cfg.kdc.primary.keytabs.kadmind}"
"--realm=${cfg.realm}"
];
};
};
heimdal-kpasswdd = {
wantedBy = [ "heimdal-kdc.service" ];
after = [ "heimdal-kdc.service" ];
bindsTo = [ "heimdal-kdc.service" ];
description = "Heimdal Kerberos Password Server.";
path = with pkgs; [ heimdal ];
serviceConfig = {
# This wasn't working:
# StandardInput = "socket";
# StandardOutput = "socket";
PrivateDevices = true;
PrivateTmp = true;
# PrivateMounts = true;
ProtectControlGroups = true;
ProtectKernelTunables = true;
ProtectSystem = true;
ProtectHostname = true;
ProtectHome = true;
ProtectClock = true;
ProtectKernelLogs = true;
MemoryDenyWriteExecute = true;
RestrictRealtime = true;
LockPersonality = true;
PermissionsStartOnly = true;
LimitNOFILE = 4096;
User = cfg.user;
Group = cfg.group;
Restart = "always";
RestartSec = "5s";
AmbientCapabilities = "CAP_NET_BIND_SERVICE";
SecureBits = "keep-caps";
ExecStart = concatStringsSep " " [
"${pkgs.heimdal}/libexec/heimdal/kpasswdd"
"--config-file=${kdcConf}"
"--keytab=${cfg.kdc.primary.keytabs.kpasswdd}"
"--realm=${cfg.realm}"
];
};
};
heimdal-hprop = mkIf hasSecondary {
wantedBy = [ "heimdal-kdc.service" ];
bindsTo = [ "heimdal-kdc.service" ];
after = [ "heimdal-kdc.service" ];
description =
"Service to propagate the KDC database to secondary servers.";
path = with pkgs; [ heimdal ];
serviceConfig = let staging-db = "$RUNTIME_DIRECTORY/realm.db";
in {
User = cfg.user;
Group = cfg.group;
Type = "oneshot";
RuntimeDirectory = "heimdal-hprop";
# ExecStartPre = let
# convertCmd = concatStringsSep " " [
# "${pkgs.kdcConvertDatabase}/bin/kdc-convert-database"
# "--config-file=${kdcConf}"
# "--key=${cfg.kdc.master-key-file}"
# "--format=db3"
# "--realm=${cfg.realm}"
# "--output=${staging-db}"
# "--verbose"
# ];
# in pkgs.writeShellScript "convert-kdc-database.sh" ''
# ${convertCmd}
# ls $RUNTIME_DIRECTORY
# '';
ExecStartPre = pkgs.writeShellScript "kdc-prepare-hprop-dump.sh"
(concatStringsSep " " [
"${pkgs.heimdal}/bin/kadmin"
"--local"
"--config-file=${kdcConf}"
"--"
"dump"
"--format=MIT"
"$(echo ${staging-db})"
]);
ExecStart = pkgs.writeShellScript "kdc-hprop.sh"
(concatStringsSep " " ([
"${pkgs.heimdal}/libexec/heimdal/hprop"
''--master-key="${cfg.kdc.master-key-file}"''
#''--database="(echo "${staging-db}")"''
"--database=sqlite:${cfg.kdc.database}"
"--source=heimdal"
''--keytab="${cfg.kdc.primary.keytabs.hprop}"''
] ++ cfg.kdc.primary.secondary-servers));
ExecStartPost = pkgs.writeShellScript "kdc-hprop-cleanup.sh"
"${pkgs.coreutils}/bin/rm ${staging-db}";
};
};
};
paths.heimdal-hprop = mkIf hasSecondary {
wantedBy = [ "heimdal-kdc.service" ];
bindsTo = [ "heimdal-kdc.service" ];
after = [ "heimdal-kdc.service" ];
pathConfig = { PathModified = cfg.kdc.database; };
};
};
# services.xinetd = {
# enable = true;
# services = [
# {
# name = "kadmin";
# user = cfg.user;
# server = "${pkgs.heimdal}/libexec/heimdal/kadmind";
# protocol = "tcp";
# serverArgs =
# "--config-file=${kdcConf} --keytab=${cfg.kdc.primary.keytabs.kadmind}";
# }
# {
# name = "kpasswd";
# user = cfg.user;
# server = "${pkgs.heimdal}/libexec/heimdal/kpasswdd";
# protocol = "udp";
# serverArgs =
# "--config-file=${kdcConf} --keytab=${cfg.kdc.primary.keytabs.kpasswdd}";
# }
# ];
# };
networking.firewall = {
allowedTCPPorts = [ 88 749 ];
allowedUDPPorts = [ 88 464 ];
};
};
};
secondaryConfig = { config, lib, pkgs, ... }:
let
cfg = config.fudo.auth.kerberos;
kdcConf = pkgs.writeText "kdc.conf" ''
[kdc]
database = {
realm = ${cfg.realm}
dbname = sqlite:${cfg.kdc.database}
mkey_file = ${cfg.kdc.master-key-file}
log_file = /dev/null
}
[realms]
${cfg.realm} = {
enable-http = false;
}
[libdefaults]
default_realm = ${cfg.realm}
allow_weak_crypto = false
[logging]
kdc = FILE:${cfg.kdc.state-directory}/kerberos.log
default = FILE:${cfg.kdc.state-directory}/kerberos.log
'';
in {
config = mkIf cfg.kdc.secondary.enable {
users = {
users."${cfg.user}" = {
isSystemUser = true;
group = cfg.group;
};
groups."${cfg.group}" = { members = [ cfg.user ]; };
};
systemd = {
services = {
heimdal-kdc-secondary = {
wantedBy = [ "multi-user.target" ];
after = [ "network-online.target" ];
description =
"Heimdal Kerberos Key Distribution Center (secondary ticket server).";
path = with pkgs; [ heimdal ];
serviceConfig = {
PrivateDevices = true;
PrivateTmp = true;
# PrivateMounts = true;
ProtectControlGroups = true;
ProtectKernelTunables = true;
# ProtectSystem = true;
ProtectHostname = true;
# ProtectHome = true;
ProtectClock = true;
ProtectKernelLogs = true;
MemoryDenyWriteExecute = true;
RestrictRealtime = true;
# LockPersonality = true;
# PermissionsStartOnly = true;
LimitNOFILE = 4096;
User = cfg.user;
Group = cfg.group;
Restart = "always";
RestartSec = "5s";
AmbientCapabilities = "CAP_NET_BIND_SERVICE";
SecureBits = "keep-caps";
ExecStart = let
ips = if (cfg.kdc.bind-addresses != [ ]) then
cfg.kdc.bind-addresses
else
[ "0.0.0.0" ];
bindClause = "--addresses=${concatStringsSep "," ips}";
in "${pkgs.heimdal}/libexec/heimdal/kdc --config-file=${kdcConf} --ports=88 ${bindClause}";
};
};
heimdal-hpropd = {
wantedBy = [ "heimdal-kdc-secondary.service" ];
after = [ "heimdal-kdc-secondary.service" ];
bindsTo = [ "heimdal-kdc-secondary.service" ];
description = "Heimdal propagation listener server.";
path = with pkgs; [ heimdal ];
serviceConfig = {
PrivateDevices = true;
PrivateTmp = true;
# PrivateMounts = true;
ProtectControlGroups = true;
ProtectKernelTunables = true;
# ProtectSystem = true;
ProtectHostname = true;
# ProtectHome = true;
ProtectClock = true;
ProtectKernelLogs = true;
MemoryDenyWriteExecute = true;
RestrictRealtime = true;
# LockPersonality = true;
# PermissionsStartOnly = true;
LimitNOFILE = 4096;
User = cfg.user;
Group = cfg.group;
Restart = "always";
RestartSec = "5s";
AmbientCapabilities = "CAP_NET_BIND_SERVICE";
SecureBits = "keep-caps";
ExecStart = concatStringsSep " " [
"${pkgs.heimdal}/libexec/heimdal/hpropd"
"--database=sqlite:${cfg.kdc.database}"
"--keytab=${cfg.kdc.secondary.keytabs.hpropd}"
];
};
};
};
};
networking.firewall = {
allowedTCPPorts = [ 88 754 ];
allowedUDPPorts = [ 88 ];
};
};
};
in {
options.fudo.auth.kerberos = with types; {
kdc = {
bind-addresses = mkOption {
type = listOf str;
description =
"A list of IP addresses on which to bind. Default to all addresses.";
default = [ ];
};
state-directory = mkOption {
type = str;
description = "Directory at which to store KDC server state.";
};
master-key-file = mkOption {
type = str;
description = "File containing the master key for this realm.";
};
database = mkOption {
type = str;
description = "Database file containing realm principals.";
default =
"${toplevel.config.fudo.auth.kerberos.kdc.state-directory}/realm.db";
};
primary = {
enable = mkEnableOption "Enable Kerberos KDC server.";
keytabs = {
kadmind = mkOption {
type = str;
description = "Kerberos keytab for kadmind.";
};
kpasswdd = mkOption {
type = str;
description = "Kerberos keytab for kpasswdd.";
};
hprop = mkOption {
type = str;
description = "Kerberos keytab for hprop database propagation.";
};
};
secondary-servers = mkOption {
type = listOf str;
description =
"List of secondary servers to which the database should be propagated.";
default = [ ];
};
acl = let
aclEntry = { name, ... }:
let principal = name;
in {
options = {
principal = mkOption {
type = str;
description = "Principal to be granted permissions.";
default = principal;
};
perms = let
permList = [
"add"
"all"
"change-password"
"delete"
"get"
"get-keys"
"list"
"modify"
];
in mkOption {
type = listOf (enum permList);
description =
"List of permissions applied to this principal.";
default = [ ];
};
target = mkOption {
type = nullOr str;
description = "Principals to which these permissions apply.";
default = null;
};
};
};
in mkOption {
type = attrsOf (submodule aclEntry);
description = "Mapping of principals to a list of permissions.";
default = { "*/root" = [ "all" ]; };
example = {
"*/root" = [ "all" ];
"admin-user" = [ "add" "list" "modify" ];
};
};
};
secondary = {
enable = mkEnableOption "Enable Kerberos KDC server.";
keytabs = {
hpropd = mkOption {
type = str;
description = "Kerberos keytab for the hpropd secondary server.";
};
};
};
};
realm = mkOption {
type = str;
description = "Realm served by this KDC.";
};
user = mkOption {
type = str;
description = "User as which to run Kerberos KDC.";
default = "kerberos";
};
group = mkOption {
type = str;
description = "Group as which to run Kerberos KDC.";
default = "kerberos";
};
};
imports = [ primaryConfig secondaryConfig ];
}

View File

@ -2,6 +2,8 @@
with lib; {
imports = [
./auth
./backplane-service/dns.nix
./acme-certs.nix
@ -23,7 +25,7 @@ with lib; {
./initrd-network.nix
./ipfs.nix
./jabber.nix
./kdc.nix
# ./kdc.nix
./ldap.nix
./local-network.nix
./mail.nix

View File

@ -22,7 +22,8 @@ let
zone-definition = mkOption {
type = submodule (import ../types/zone-definition.nix);
description = "Definition of network zone to be served by local server.";
description =
"Definition of network zone to be served by local server.";
};
};
};
@ -51,7 +52,8 @@ in {
state-directory = mkOption {
type = str;
description = "Path at which to store nameserver state, including DNSSEC keys.";
description =
"Path at which to store nameserver state, including DNSSEC keys.";
default = "/var/lib/nsd";
};
};
@ -62,23 +64,25 @@ in {
allowedUDPPorts = [ 53 ];
};
fudo.nsd = {
fileSystems."/var/lib/nsd" = {
device = cfg.state-directory;
options = [ "bind" ];
};
services.nsd = {
enable = true;
identity = cfg.identity;
interfaces = cfg.listen-ips;
stateDir = cfg.state-directory;
zones = mapAttrs' (dom: dom-cfg: let
net-cfg = dom-cfg.zone-definition;
in nameValuePair "${dom}." {
dnssec = dom-cfg.dnssec;
# stateDir = cfg.state-directory;
zones = mapAttrs' (dom: dom-cfg:
let net-cfg = dom-cfg.zone-definition;
in nameValuePair "${dom}." {
dnssec = dom-cfg.dnssec;
data =
pkgs.lib.dns.zoneToZonefile
config.instance.build-timestamp
dom
data = pkgs.lib.dns.zoneToZonefile config.instance.build-timestamp dom
dom-cfg.zone-definition;
}) cfg.domains;
}) cfg.domains;
};
};
}

View File

@ -131,7 +131,7 @@ in {
rootUrl = "https://${cfg.hostname}/";
user = mkIf (cfg.user != null) cfg.user;
ssh = {
enable = true;
#enable = true;
clonePort = cfg.ssh.listen-port;
};
settings = mkIf (cfg.ssh != null) {

View File

@ -217,11 +217,11 @@ in {
from_address = "${cfg.smtp.username}@${cfg.smtp.domain}";
host = "${cfg.smtp.hostname}:25";
user = cfg.smtp.username;
password = "$__${cfg.smtp.password-file}}";
password = "$__file{${cfg.smtp.password-file}}";
};
security = {
admin_password = "$__{${cfg.admin-password-file}}";
admin_password = "$__file{${cfg.admin-password-file}}";
secret_key = "$__file{${cfg.secret-key-file}}";
};
@ -229,7 +229,7 @@ in {
host = cfg.database.hostname;
name = cfg.database.name;
user = cfg.database.user;
password = "$__{${cfg.database.password-file}}";
password = "$__file{${cfg.database.password-file}}";
type = "postgres";
};

View File

@ -260,11 +260,6 @@ in {
environment = mkIf (cfg.kerberos-keytab != null) {
KRB5_KTNAME = cfg.kerberos-keytab;
};
preStart = mkOrder 5000 ''
${build-ca-script cfg.ssl-chain cfg.ssl-ca-certificate}
# The script is failing to do this
chown "${user}:${group}" -R /etc/openldap
'';
serviceConfig = {
PrivateDevices = true;
PrivateTmp = true;
@ -301,6 +296,13 @@ in {
InaccessiblePaths = [ "/home" "/root" ];
LimitNOFILE = 49152;
PermissionsStartOnly = true;
ExecStartPre = [
"${build-ca-script cfg.ssl-chain cfg.ssl-ca-certificate}"
''${pkgs.coreutils}/bin/chown "${user}:${group}" -vR /etc/openldap''
''
${pkgs.coreutils}/bin/chown "${user}:${group}" -vR "/var/lib/openldap/database"''
];
};
};
};

View File

@ -1,6 +1,8 @@
# ## NOTE:
## This is a copy of the upstream version, which allows for overriding the state directory
## OBSOLETE
{ config, pkgs, lib, ... }:
with lib;

View File

@ -347,7 +347,6 @@ in {
description =
"A service to set postgresql user passwords after the server has started.";
after = [ "postgresql.service" ] ++ cfg.required-services;
requires = [ "postgresql.service" ] ++ cfg.required-services;
wantedBy = [ "postgresql.service" ];
serviceConfig = {
Type = "oneshot";
@ -386,10 +385,10 @@ in {
};
postgresql-finalizer = {
requires = [ "postgresql.target" ];
after = [ "postgresql.target" "postgresql-password-setter.target" ];
partOf = [ cfg.systemd-target ];
wantedBy = [ "postgresql.target" ];
requires = [ "postgresql.service" ];
after = [ "postgresql.service" "postgresql-password-setter.service" ];
partOf = [ "postgresql.target" ];
wantedBy = [ "postgresql.service" ];
serviceConfig = {
User = config.services.postgresql.superUser;
ExecStart = let

View File

@ -318,7 +318,11 @@ in {
powerdns = {
description = "PowerDNS nameserver.";
requires = [ "powerdns-config-generator.service" ];
after = [ "network.target" "powerdns-config-generator.service" ];
after = [
"network.target"
"powerdns-config-generator.service"
"postgresql.service"
];
wantedBy = [ "multi-user.target" ];
path = with pkgs; [ powerdns postgresql util-linux ];
serviceConfig = {

View File

@ -1,6 +1,4 @@
(final: prev: with builtins; {
lib = let
pkgs = prev;
in
pkgs.lib // (import ./lib.nix { inherit pkgs; });
})
(final: prev:
with builtins; {
lib = prev.lib // (import ./lib.nix { pkgs = prev; });
})