chore(idp): ldap ssl proxy

This commit is contained in:
arcnmx 2024-03-13 15:36:12 -07:00
parent e7ed4ee5ac
commit 926290306a
4 changed files with 137 additions and 70 deletions

View file

@ -5,6 +5,7 @@
inputs, inputs,
... ...
}: let }: let
inherit (inputs.self.lib.lib) domain;
inherit (lib.modules) mkIf mkOptionDefault; inherit (lib.modules) mkIf mkOptionDefault;
in { in {
options = let options = let
@ -28,7 +29,7 @@ in {
autoRollback = mkOptionDefault true; autoRollback = mkOptionDefault true;
magicRollback = mkOptionDefault true; magicRollback = mkOptionDefault true;
fastConnection = mkOptionDefault false; fastConnection = mkOptionDefault false;
hostname = mkOptionDefault "${name}.local.gensokyo.zone"; hostname = mkOptionDefault "${name}.local.${domain}";
profiles.system = { profiles.system = {
user = "root"; user = "root";
path = let path = let

View file

@ -3,7 +3,8 @@
meta, meta,
lib, lib,
... ...
}: let }:
let
inherit (lib.options) mkOption mkEnableOption; inherit (lib.options) mkOption mkEnableOption;
inherit (lib.modules) mkIf mkMerge mkBefore mkDefault; inherit (lib.modules) mkIf mkMerge mkBefore mkDefault;
inherit (lib.strings) optionalString concatStringsSep; inherit (lib.strings) optionalString concatStringsSep;
@ -29,6 +30,9 @@
proxy_set_header X-SSL-CERT $ssl_client_escaped_cert; proxy_set_header X-SSL-CERT $ssl_client_escaped_cert;
proxy_redirect https://${domain}/ $scheme://$host/; proxy_redirect https://${domain}/ $scheme://$host/;
proxy_ssl_server_name on;
proxy_ssl_name ${domain};
set $x_referer $http_referer; set $x_referer $http_referer;
if ($x_referer ~ "^https://([^/]*)/(.*)$") { if ($x_referer ~ "^https://([^/]*)/(.*)$") {
set $x_referer_host $1; set $x_referer_host $1;
@ -55,22 +59,22 @@ in {
type = str; type = str;
}; };
preread = { preread = {
enable = enable = mkEnableOption "ssl preread" // {
mkEnableOption "ssl preread" default = true;
// { };
default = true;
};
port = mkOption { port = mkOption {
type = port; type = port;
default = 444; default = 444;
}; };
ldapPort = mkOption {
type = port;
default = 637;
};
}; };
kerberos = { kerberos = {
enable = enable = mkEnableOption "proxy kerberos" // {
mkEnableOption "proxy kerberos" default = true;
// { };
default = true;
};
ports = { ports = {
ticket = mkOption { ticket = mkOption {
type = port; type = port;
@ -89,10 +93,7 @@ in {
proxyPass = mkOption { proxyPass = mkOption {
type = str; type = str;
default = let default = let
scheme = scheme = if access.port == 443 then "https" else "http";
if access.port == 443
then "https"
else "http";
in "${scheme}://${access.host}:${toString access.port}"; in "${scheme}://${access.host}:${toString access.port}";
}; };
domain = mkOption { domain = mkOption {
@ -133,30 +134,77 @@ in {
access.ldap = { access.ldap = {
enable = mkDefault true; enable = mkDefault true;
host = mkDefault access.host; host = mkDefault access.host;
port = mkDefault access.ldapPort; port = mkDefault 389;
sslPort = mkDefault access.ldapPort;
useACMEHost = mkDefault access.useACMEHost; useACMEHost = mkDefault access.useACMEHost;
bind.sslPort = mkIf access.preread.enable (mkDefault access.preread.ldapPort);
}; };
resolver.addresses = mkIf access.preread.enable ["[::1]" "127.0.0.1:5353"]; resolver.addresses = mkIf access.preread.enable (mkMerge [
(mkDefault [ "[::1]:5353" "127.0.0.1:5353" ])
(mkIf config.systemd.network.enable [ "127.0.0.53" ])
]);
defaultSSLListenPort = mkIf access.preread.enable access.preread.port; defaultSSLListenPort = mkIf access.preread.enable access.preread.port;
streamConfig = let streamConfig = let
upstreams' = {
freeipa = "${access.host}:${toString access.port}";
ldap_freeipa = "${nginx.access.ldap.host}:${toString nginx.access.ldap.sslPort}";
ldap = "localhost:${toString nginx.access.ldap.bind.sslPort}";
nginx = "localhost:${toString nginx.defaultSSLListenPort}";
samba = if config.services.samba.enable
then "localhost:445"
else "smb.local.${config.networking.domain}:445";
};
upstreams = builtins.mapAttrs (name: _: name) upstreams';
preread = '' preread = ''
upstream freeipa { upstream freeipa {
server ${access.host}:${toString access.port}; server ${upstreams'.freeipa};
}
upstream ldap_freeipa {
server ${upstreams'.ldap_freeipa};
}
upstream ldap {
server ${upstreams'.ldap};
}
upstream samba {
server ${upstreams'.samba};
} }
upstream nginx { upstream nginx {
server localhost:${toString nginx.defaultSSLListenPort}; server ${upstreams'.nginx};
} }
map $ssl_preread_server_name $ssl_name { map $ssl_preread_server_name $ssl_server_name {
hostnames; hostnames;
${access.domain} freeipa; ${access.domain} ${upstreams.freeipa};
${access.caDomain} freeipa; ${access.caDomain} ${upstreams.freeipa};
default nginx; ${nginx.access.ldap.domain} ${upstreams.ldap};
${nginx.access.ldap.localDomain} ${upstreams.ldap};
${nginx.access.ldap.tailDomain} ${upstreams.ldap};
default ${upstreams.nginx};
} }
map $ssl_preread_alpn_protocols $https_upstream {
~\bsmb\b ${upstreams.samba};
# XXX: if only there were an ldap protocol id...
default $ssl_server_name;
}
server { server {
listen 0.0.0.0:443; listen 0.0.0.0:443;
listen [::]:443; listen [::]:443;
ssl_preread on; ssl_preread on;
proxy_pass $ssl_name; proxy_pass $https_upstream;
}
map $ssl_preread_server_name $ldap_upstream {
hostnames;
# TODO: ${access.domain} ${upstreams.ldap_freeipa};
${access.globalDomain} ${upstreams.ldap_freeipa};
default ${upstreams.ldap};
}
server {
listen 0.0.0.0:636;
listen [::]:636;
ssl_preread on;
proxy_pass $ldap_upstream;
} }
''; '';
kerberos = '' kerberos = ''
@ -180,11 +228,10 @@ in {
proxy_pass ${access.host}:${toString access.kerberos.ports.kpasswd}; proxy_pass ${access.host}:${toString access.kerberos.ports.kpasswd};
} }
''; '';
in in mkMerge [
mkMerge [ (mkIf access.preread.enable preread)
(mkIf access.preread.enable preread) (mkIf access.kerberos.enable kerberos)
(mkIf access.kerberos.enable kerberos) ];
];
virtualHosts = { virtualHosts = {
${access.domain} = { ${access.domain} = {
inherit locations extraConfig; inherit locations extraConfig;
@ -214,7 +261,7 @@ in {
local.enable = true; local.enable = true;
inherit locations; inherit locations;
}; };
${ldap.domain} = {config, ...}: { ${ldap.domain} = { config, ... }: {
useACMEHost = mkDefault virtualHosts.${access.domain}.useACMEHost; useACMEHost = mkDefault virtualHosts.${access.domain}.useACMEHost;
addSSL = mkDefault (config.useACMEHost != null); addSSL = mkDefault (config.useACMEHost != null);
globalRedirect = access.domain; globalRedirect = access.domain;
@ -233,9 +280,14 @@ in {
}; };
networking.firewall = { networking.firewall = {
allowedTCPPorts = mkIf access.kerberos.enable [ allowedTCPPorts = mkMerge [
access.kerberos.ports.ticket (mkIf access.kerberos.enable [
access.kerberos.ports.kpasswd access.kerberos.ports.ticket
access.kerberos.ports.kpasswd
])
(mkIf access.preread.enable [
636
])
]; ];
allowedUDPPorts = mkIf access.kerberos.enable [ allowedUDPPorts = mkIf access.kerberos.enable [
access.kerberos.ports.ticket access.kerberos.ports.ticket

View file

@ -2,7 +2,8 @@
config, config,
lib, lib,
... ...
}: let }:
let
inherit (lib.options) mkOption mkEnableOption; inherit (lib.options) mkOption mkEnableOption;
inherit (lib.modules) mkIf mkMerge; inherit (lib.modules) mkIf mkMerge;
inherit (lib.strings) concatMapStringsSep optionalString; inherit (lib.strings) concatMapStringsSep optionalString;
@ -11,17 +12,17 @@
inherit (config.services.nginx) virtualHosts; inherit (config.services.nginx) virtualHosts;
inherit (config.networking.access) cidrForNetwork localaddrs; inherit (config.networking.access) cidrForNetwork localaddrs;
access = config.services.nginx.access.ldap; access = config.services.nginx.access.ldap;
portPlaintext = 389;
portSsl = 636;
allows = let allows = let
mkAllow = cidr: "allow ${cidr};"; mkAllow = cidr: "allow ${cidr};";
allowAddresses = allowAddresses =
cidrForNetwork.loopback.all cidrForNetwork.loopback.all
++ cidrForNetwork.local.all ++ cidrForNetwork.local.all
++ optionals tailscale.enable cidrForNetwork.tail.all; ++ optionals tailscale.enable cidrForNetwork.tail.all;
allows = allows = concatMapStringsSep "\n" mkAllow allowAddresses + optionalString localaddrs.enable ''
concatMapStringsSep "\n" mkAllow allowAddresses include ${localaddrs.stateDir}/*.nginx.conf;
+ optionalString localaddrs.enable '' '';
include ${localaddrs.stateDir}/*.nginx.conf;
'';
in '' in ''
${allows} ${allows}
deny all; deny all;
@ -46,7 +47,21 @@ in {
}; };
port = mkOption { port = mkOption {
type = port; type = port;
default = 636; default = portSsl;
};
sslPort = mkOption {
type = port;
default = portSsl;
};
bind = {
sslPort = mkOption {
type = port;
default = portSsl;
};
port = mkOption {
type = port;
default = portPlaintext;
};
}; };
useACMEHost = mkOption { useACMEHost = mkOption {
type = nullOr str; type = nullOr str;
@ -57,42 +72,40 @@ in {
services.nginx = { services.nginx = {
streamConfig = let streamConfig = let
cert = config.security.acme.certs.${access.useACMEHost}; cert = config.security.acme.certs.${access.useACMEHost};
proxyPass = "${access.host}:${toString access.port}"; proxySsl = port: optionalString (port == portSsl) ''
proxySsl = optionalString (access.port == 636) ''
proxy_ssl on; proxy_ssl on;
proxy_ssl_verify off; proxy_ssl_verify off;
''; '';
in in mkIf access.enable (mkMerge [
mkIf access.enable (mkMerge [ ''
'' server {
server { listen 0.0.0.0:${toString access.bind.port};
listen 0.0.0.0:389; listen [::]:${toString access.bind.port};
listen [::]:389; ${allows}
${allows} proxy_pass ${access.host}:${toString access.port};
proxy_pass ${proxyPass}; ${proxySsl access.port}
${proxySsl} }
} ''
'' (mkIf (access.useACMEHost != null) ''
(mkIf (access.useACMEHost != null) '' server {
server { listen 0.0.0.0:${toString access.bind.sslPort} ssl;
listen 0.0.0.0:636 ssl; listen [::]:${toString access.bind.sslPort} ssl;
listen [::]:636 ssl; ssl_certificate ${cert.directory}/fullchain.pem;
ssl_certificate ${cert.directory}/fullchain.pem; ssl_certificate_key ${cert.directory}/key.pem;
ssl_certificate_key ${cert.directory}/key.pem; ssl_trusted_certificate ${cert.directory}/chain.pem;
ssl_trusted_certificate ${cert.directory}/chain.pem; proxy_pass ${access.host}:${toString access.sslPort};
proxy_pass ${proxyPass}; ${proxySsl access.sslPort}
${proxySsl} }
} '')
'') ]);
]);
}; };
networking.firewall = { networking.firewall = {
interfaces.local.allowedTCPPorts = [ interfaces.local.allowedTCPPorts = [
389 access.bind.port
]; ];
allowedTCPPorts = [ allowedTCPPorts = [
636 access.bind.sslPort
]; ];
}; };
}; };

View file

@ -4,10 +4,11 @@
lib, lib,
... ...
}: let }: let
inherit (inputs.self.lib.lib) domain;
inherit (lib.modules) mkForce; inherit (lib.modules) mkForce;
inherit (lib.strings) escapeShellArgs; inherit (lib.strings) escapeShellArgs;
kubeMasterIP = "10.1.1.173"; kubeMasterIP = "10.1.1.173";
kubeMasterHostname = "k8s.gensokyo.zone"; kubeMasterHostname = "k8s.${domain}";
kubeMasterAPIServerPort = 6443; kubeMasterAPIServerPort = 6443;
in { in {
# packages for administration tasks # packages for administration tasks
@ -42,7 +43,7 @@ in {
extraOpts = escapeShellArgs [ extraOpts = escapeShellArgs [
"--service-node-port-range=1-65535" "--service-node-port-range=1-65535"
/* /*
"--oidc-issuer-url=https://dex.gensokyo.zone:32000" "--oidc-issuer-url=https://dex.${domain}:32000"
"--oidc-client-id=kuwubernetes" "--oidc-client-id=kuwubernetes"
"--oidc-ca-file=/etc/dex-ssl/ca.pem" "--oidc-ca-file=/etc/dex-ssl/ca.pem"
"--oidc-username-claim=email" "--oidc-username-claim=email"