infrastructure/nixos/access/freeipa.nix
2024-05-13 15:31:34 -07:00

322 lines
9.5 KiB
Nix

{
config,
meta,
access,
gensokyo-zone,
lib,
...
}: let
inherit (gensokyo-zone.lib) mapOptionDefaults;
inherit (lib.options) mkOption mkEnableOption;
inherit (lib.modules) mkIf mkMerge mkDefault mkOptionDefault;
inherit (config.services) tailscale;
inherit (config.services) nginx;
inherit (nginx) virtualHosts;
cfg = nginx.access.freeipa;
inherit (nginx.access) ldap;
extraConfig = ''
ssl_verify_client optional_no_ca;
'';
locations = {
"/" = {
config,
xvars,
...
}: {
proxy = {
enable = true;
upstream = "freeipa";
headers = {
rewriteReferer.enable = true;
set = {
X-SSL-CERT = "$ssl_client_escaped_cert";
};
};
redirect = {
enable = true;
fromHost = config.proxy.host;
fromScheme = xvars.get.proxy_scheme;
};
};
};
};
locations'cockpit = {
"/" = {xvars, ...}: {
proxy = {
enable = true;
host = xvars.get.host;
};
};
"/cockpit/socket" = {
proxy = {
enable = true;
websocket.enable = true;
};
};
};
ldapsPort = 636;
in {
imports = let
inherit (meta) nixos;
in [
nixos.access.ldap
];
options.services.nginx.access.freeipa = with lib.types; {
preread = {
ldapPort = mkOption {
type = port;
default = 637;
};
};
kerberos = {
enable =
mkEnableOption "proxy kerberos"
// {
default = true;
};
ports = {
ticket = mkOption {
type = port;
default = 88;
};
ticket4 = mkOption {
type = port;
default = 4444;
};
kpasswd = mkOption {
type = port;
default = 464;
};
kadmin = mkOption {
type = port;
default = 749;
};
};
};
};
config = {
services.nginx = {
# TODO: ssl.preread.enable = mkDefault true;
upstreams' = {
freeipa = {config, ...}: {
ssl.host = mkDefault (access.systemFor config.servers.access.accessService.system).access.fqdn;
host = mkDefault config.ssl.host;
servers.access = {
accessService = {
name = "freeipa";
};
};
};
freeipa'cockpit = {upstream, ...}: {
servers.access = {
accessService = {
inherit (nginx.upstreams'.freeipa.servers.access.accessService) system;
name = "cockpit";
};
};
};
};
stream = let
prereadConf = {
upstreams = {
freeipa = let
inherit (nginx.upstreams') freeipa;
in {
ssl.host = mkDefault freeipa.ssl.host;
servers.access.accessService = {
inherit (freeipa.servers.access.accessService) system name id port;
};
};
ldaps_access = {
ssl.enable = true;
servers.access = {
addr = mkDefault "localhost";
port = mkOptionDefault nginx.stream.servers.ldap.listen.ldaps.port;
};
};
};
servers = {
${nginx.ssl.preread.serverName} = {
ssl.preread.upstreams = mapOptionDefaults {
${virtualHosts.freeipa.serverName} = "freeipa";
${virtualHosts.freeipa'ca.serverName} = "freeipa";
${nginx.access.ldap.domain} = "ldaps_access";
${nginx.access.ldap.localDomain} = "ldaps_access";
${nginx.access.ldap.intDomain} = "ldaps_access";
${nginx.access.ldap.tailDomain} = "ldaps_access";
};
};
preread'ldap = {
listen = {
ldaps.port = ldapsPort;
};
ssl.preread = {
enable = true;
upstreams = mapOptionDefaults {
${virtualHosts.freeipa.serverName} = "ldaps";
default = "ldaps_access";
};
};
};
};
};
kerberosConf = let
system = access.systemFor nginx.stream.upstreams.krb5.servers.access.accessService.system;
inherit (system.exports.services) kerberos;
in {
upstreams = let
mkKrb5Upstream = port: {config, ...}: {
enable = mkDefault config.servers.access.enable;
servers.access = {
accessService = {
name = "kerberos";
inherit port;
};
};
};
in {
krb5 = mkKrb5Upstream "default";
kadmin = mkKrb5Upstream "kadmin";
kpasswd = mkKrb5Upstream "kpasswd";
kticket4 = mkKrb5Upstream "ticket4";
};
servers = let
mkKrb5Server = tcpPort: udpPort: {name, ...}: {
enable = mkDefault nginx.stream.upstreams.${name}.enable;
listen = {
tcp = mkIf (tcpPort != null) {
enable = mkDefault kerberos.ports.${tcpPort}.enable;
port = mkOptionDefault kerberos.ports.${tcpPort}.port;
};
udp = mkIf (udpPort != null) {
enable = mkDefault kerberos.ports.${udpPort}.enable;
port = mkOptionDefault kerberos.ports.${udpPort}.port;
extraParameters = ["udp"];
};
};
proxy.upstream = name;
};
in {
krb5 = mkKrb5Server "default" "udp";
kadmin = mkKrb5Server "kadmin" null;
kpasswd = mkKrb5Server "kpasswd" "kpasswd-udp";
kticket4 = mkKrb5Server null "ticket4";
};
};
conf.upstreams.ldap'access.servers.ldaps.enable = false;
conf.servers = {
ldap = {
listen = {
ldaps.port = mkIf nginx.ssl.preread.enable (mkDefault cfg.preread.ldapPort);
};
ssl.cert.copyFromVhost = mkDefault "freeipa";
};
};
in
mkMerge [
conf
(mkIf nginx.ssl.preread.enable prereadConf)
(mkIf cfg.kerberos.enable kerberosConf)
];
virtualHosts = let
name.shortServer = mkDefault "ipa";
name'cockpit.shortServer = mkDefault "ipa-cock";
in {
freeipa = {
name.shortServer = mkDefault "idp";
inherit locations extraConfig;
ssl.force = mkDefault true;
};
freeipa'web = {
ssl = {
force = mkDefault virtualHosts.freeipa.ssl.force;
cert.copyFromVhost = "freeipa";
};
inherit name locations extraConfig;
};
freeipa'ca = {
name.shortServer = mkDefault "idp-ca";
locations."/" = mkMerge [
locations."/"
({
config,
virtualHost,
...
}: {
proxy.ssl.host = virtualHost.serverName;
proxy.host = config.proxy.ssl.host;
})
];
ssl = {
force = mkDefault virtualHosts.freeipa.ssl.force;
cert.copyFromVhost = "freeipa";
};
inherit extraConfig;
};
freeipa'web'local = {
ssl.cert.copyFromVhost = "freeipa'web";
local.enable = true;
inherit name locations extraConfig;
};
freeipa'cockpit = {
name = name'cockpit;
vouch.enable = mkDefault true;
ssl = {
force = mkDefault true;
cert.copyFromVhost = "freeipa'web";
};
proxy.upstream = "freeipa'cockpit";
locations = locations'cockpit;
};
freeipa'cockpit'local = {
name = name'cockpit;
ssl = {
force = mkDefault true;
cert.copyFromVhost = "freeipa'cockpit";
};
proxy.copyFromVhost = "freeipa'cockpit";
local.enable = true;
locations = locations'cockpit;
};
freeipa'ldap = {
serverName = mkDefault ldap.domain;
ssl.cert.copyFromVhost = "freeipa";
globalRedirect = virtualHosts.freeipa'web.serverName;
};
freeipa'ldap'local = {
serverName = mkDefault ldap.localDomain;
serverAliases = [ldap.intDomain];
ssl.cert.copyFromVhost = "freeipa'ldap";
globalRedirect = virtualHosts.freeipa'web'local.serverName;
local.enable = true;
};
freeipa'ldap'tail = {
enable = mkDefault tailscale.enable;
serverName = mkDefault ldap.tailDomain;
ssl.cert.copyFromVhost = "freeipa'ldap'local";
globalRedirect = virtualHosts.freeipa'web'local.name.tailscaleName;
local.enable = true;
};
};
};
networking.firewall = let
inherit (nginx.stream.servers) krb5 kadmin kpasswd kticket4;
in {
allowedTCPPorts = mkMerge [
(mkIf cfg.kerberos.enable (map (
server:
mkIf (server.enable && server.listen.tcp.enable) server.listen.tcp.port
) [krb5 kticket4 kpasswd kadmin]))
(mkIf nginx.ssl.preread.enable [
ldapsPort
])
];
allowedUDPPorts = mkIf cfg.kerberos.enable (map (
server:
mkIf (server.enable && server.listen.udp.enable) server.listen.udp.port
) [krb5 kticket4 kpasswd]);
};
};
}