diff --git a/nixos/access/freeipa.nix b/nixos/access/freeipa.nix new file mode 100644 index 00000000..e4ded7e0 --- /dev/null +++ b/nixos/access/freeipa.nix @@ -0,0 +1,122 @@ +{ + config, + meta, + lib, + ... +}: +let + inherit (lib.options) mkOption; + inherit (lib.modules) mkIf mkDefault; + inherit (config.services) tailscale; + inherit (config.services.nginx) virtualHosts; + access = config.services.nginx.access.freeipa; + inherit (config.services.nginx.access) ldap; + locations = { + "/" = { + proxyPass = mkDefault access.proxyPass; + recommendedProxySettings = false; + extraConfig = '' + proxy_set_header Host ${access.domain}; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Host $host; + proxy_set_header X-Forwarded-Server $host; + proxy_redirect https://${access.domain}/ $scheme://$host/; + ''; + }; + }; +in { + imports = let + inherit (meta) nixos; + in [ + nixos.access.ldap + ]; + + options.services.nginx.access.freeipa = with lib.types; { + host = mkOption { + type = str; + }; + proxyPass = mkOption { + type = str; + default = let + scheme = if access.port == 443 then "https" else "http"; + in "${scheme}://${access.host}:${toString access.port}"; + }; + domain = mkOption { + type = str; + default = "idp.${config.networking.domain}"; + }; + localDomain = mkOption { + type = str; + default = "freeipa.local.${config.networking.domain}"; + }; + tailDomain = mkOption { + type = str; + default = "freeipa.tail.${config.networking.domain}"; + }; + port = mkOption { + type = port; + default = 443; + }; + ldapPort = mkOption { + type = port; + default = 636; + }; + useACMEHost = mkOption { + type = nullOr str; + default = virtualHosts.${access.domain}.useACMEHost; + }; + }; + config = { + services.nginx = { + access.ldap = { + enable = mkDefault true; + host = mkDefault access.host; + port = mkDefault access.ldapPort; + useACMEHost = mkDefault access.useACMEHost; + }; + virtualHosts = { + ${access.domain} = { + inherit locations; + }; + ${access.localDomain} = { + inherit (virtualHosts.${access.domain}) useACMEHost; + addSSL = mkDefault (access.useACMEHost != null || virtualHosts.${access.domain}.forceSSL); + local.enable = true; + inherit locations; + }; + ${access.tailDomain} = mkIf tailscale.enable { + inherit (virtualHosts.${access.domain}) useACMEHost; + addSSL = mkDefault (access.useACMEHost != null || virtualHosts.${access.domain}.forceSSL); + local.enable = true; + inherit locations; + }; + ${ldap.domain} = { config, ... }: { + useACMEHost = mkDefault virtualHosts.${access.domain}.useACMEHost; + addSSL = mkDefault (config.useACMEHost != null); + globalRedirect = access.domain; + }; + ${ldap.localDomain} = { + inherit (virtualHosts.${ldap.domain}) useACMEHost addSSL; + globalRedirect = access.localDomain; + local.enable = true; + }; + ${ldap.tailDomain} = mkIf tailscale.enable { + inherit (virtualHosts.${ldap.domain}) useACMEHost addSSL; + globalRedirect = access.tailDomain; + local.enable = true; + }; + }; + }; + + networking.firewall = { + interfaces.local.allowedTCPPorts = [ + 389 + ]; + allowedTCPPorts = [ + 636 + ]; + }; + }; +} diff --git a/nixos/access/kanidm.nix b/nixos/access/kanidm.nix index bb54abb1..3b3ad9c8 100644 --- a/nixos/access/kanidm.nix +++ b/nixos/access/kanidm.nix @@ -1,16 +1,14 @@ { config, + meta, lib, ... }: let inherit (lib.options) mkOption; inherit (lib.modules) mkIf mkMerge mkDefault mkOptionDefault; - inherit (lib.strings) concatMapStringsSep; - inherit (lib.lists) optionals; inherit (config.services) tailscale; inherit (config.services.nginx) virtualHosts; - inherit (config.networking.access) cidrForNetwork; cfg = config.services.kanidm; access = config.services.nginx.access.kanidm; proxyPass = mkDefault "https://${access.host}:${toString access.port}"; @@ -22,18 +20,13 @@ let alias = "${cfg.server.unencrypted.package.ca}"; }; }; - allows = let - mkAllow = cidr: "allow ${cidr};"; - allowAddresses = - cidrForNetwork.loopback.all - ++ cidrForNetwork.local.all - ++ optionals tailscale.enable cidrForNetwork.tail.all; - allows = concatMapStringsSep "\n" mkAllow allowAddresses; - in '' - ${allows} - deny all; - ''; in { + imports = let + inherit (meta) nixos; + in [ + nixos.access.ldap + ]; + options.services.nginx.access.kanidm = with lib.types; { host = mkOption { type = str; @@ -50,18 +43,6 @@ in { type = str; default = "id.tail.${config.networking.domain}"; }; - ldapDomain = mkOption { - type = str; - default = "ldap.${config.networking.domain}"; - }; - ldapLocalDomain = mkOption { - type = str; - default = "ldap.local.${config.networking.domain}"; - }; - ldapTailDomain = mkOption { - type = str; - default = "ldap.tail.${config.networking.domain}"; - }; port = mkOption { type = port; }; @@ -74,7 +55,7 @@ in { }; ldapEnable = mkOption { type = bool; - default = true; + default = false; }; useACMEHost = mkOption { type = nullOr str; @@ -90,35 +71,12 @@ in { ldapPort = mkOptionDefault cfg.server.ldap.port; ldapEnable = mkDefault cfg.server.ldap.enable; }; - streamConfig = let - inherit (config.security.acme) certs; - sslConfig = if access.useACMEHost != null then '' - ssl_certificate ${certs.${access.useACMEHost}.directory}/fullchain.pem; - ssl_certificate_key ${certs.${access.useACMEHost}.directory}/key.pem; - ssl_trusted_certificate ${certs.${access.useACMEHost}.directory}/chain.pem; - '' else '' - ssl_certificate ${cfg.serverSettings.tls_chain}; - ssl_certificate_key ${cfg.serverSettings.tls_key}; - ''; - in mkIf access.ldapEnable '' - server { - listen 0.0.0.0:389; - listen [::]:389; - ${allows} - proxy_pass ${access.ldapHost}:${toString access.ldapPort}; - proxy_ssl on; - proxy_ssl_verify off; - } - server { - listen 0.0.0.0:636 ssl; - listen [::]:636 ssl; - ${sslConfig} - proxy_pass ${access.ldapHost}:${toString access.ldapPort}; - proxy_ssl on; - proxy_ssl_verify off; - } - ''; - + access.ldap = mkIf (cfg.enableServer && cfg.ldapEnable) { + enable = mkDefault true; + host = mkOptionDefault access.kanidm.ldapHost; + port = mkOptionDefault access.kanidm.ldapPort; + useACMEHost = mkDefault access.kanidm.useACMEHost; + }; virtualHosts = { ${access.domain} = { inherit locations; @@ -129,7 +87,7 @@ in { local.enable = true; inherit locations; }; - ${access.tailDomain} = mkIf config.services.tailscale.enable { + ${access.tailDomain} = mkIf tailscale.enable { inherit (virtualHosts.${access.domain}) useACMEHost; addSSL = mkDefault (access.useACMEHost != null || virtualHosts.${access.domain}.forceSSL); local.enable = true; @@ -144,7 +102,7 @@ in { config.networking.fqdn config.networking.access.hostnameForNetwork.local ] - (mkIf config.services.tailscale.enable [ + (mkIf tailscale.enable [ "id.tail.${config.networking.domain}" config.networking.access.hostnameForNetwork.tail ]) diff --git a/nixos/access/ldap.nix b/nixos/access/ldap.nix new file mode 100644 index 00000000..764a307f --- /dev/null +++ b/nixos/access/ldap.nix @@ -0,0 +1,95 @@ +{ + config, + lib, + ... +}: +let + inherit (lib.options) mkOption mkEnableOption; + inherit (lib.modules) mkIf mkMerge; + inherit (lib.strings) concatMapStringsSep optionalString; + inherit (lib.lists) optionals; + inherit (config.services) tailscale; + inherit (config.services.nginx) virtualHosts; + inherit (config.networking.access) cidrForNetwork; + access = config.services.nginx.access.ldap; + allows = let + mkAllow = cidr: "allow ${cidr};"; + allowAddresses = + cidrForNetwork.loopback.all + ++ cidrForNetwork.local.all + ++ optionals tailscale.enable cidrForNetwork.tail.all; + allows = concatMapStringsSep "\n" mkAllow allowAddresses; + in '' + ${allows} + deny all; + ''; +in { + options.services.nginx.access.ldap = with lib.types; { + enable = mkEnableOption "LDAP proxy"; + host = mkOption { + type = str; + }; + domain = mkOption { + type = str; + default = "ldap.${config.networking.domain}"; + }; + localDomain = mkOption { + type = str; + default = "ldap.local.${config.networking.domain}"; + }; + tailDomain = mkOption { + type = str; + default = "ldap.tail.${config.networking.domain}"; + }; + port = mkOption { + type = port; + default = 636; + }; + useACMEHost = mkOption { + type = nullOr str; + default = virtualHosts.${access.domain}.useACMEHost or null; + }; + }; + config = { + services.nginx = { + streamConfig = let + cert = config.security.acme.certs.${access.useACMEHost}; + proxyPass = "${access.host}:${toString access.port}"; + proxySsl = optionalString (access.port == 636) '' + proxy_ssl on; + proxy_ssl_verify off; + ''; + in mkIf access.enable (mkMerge [ + '' + server { + listen 0.0.0.0:389; + listen [::]:389; + ${allows} + proxy_pass ${proxyPass}; + ${proxySsl} + } + '' + (mkIf (access.useACMEHost != null) '' + server { + listen 0.0.0.0:636 ssl; + listen [::]:636 ssl; + ssl_certificate ${cert.directory}/fullchain.pem; + ssl_certificate_key ${cert.directory}/key.pem; + ssl_trusted_certificate ${cert.directory}/chain.pem; + proxy_pass ${proxyPass}; + ${proxySsl} + } + '') + ]); + }; + + networking.firewall = { + interfaces.local.allowedTCPPorts = [ + 389 + ]; + allowedTCPPorts = [ + 636 + ]; + }; + }; +} diff --git a/systems/hakurei/nixos.nix b/systems/hakurei/nixos.nix index 558528bd..21e50d87 100644 --- a/systems/hakurei/nixos.nix +++ b/systems/hakurei/nixos.nix @@ -26,6 +26,7 @@ in { nixos.access.global nixos.access.gensokyo nixos.access.kanidm + nixos.access.freeipa nixos.access.proxmox nixos.access.plex ./reisen-ssh.nix @@ -56,18 +57,32 @@ in { inherit (nginx) group; extraDomainNames = mkMerge [ [access.kanidm.localDomain] - (mkIf kanidm.server.ldap.enable [ + (mkIf access.kanidm.ldapEnable [ access.kanidm.ldapDomain access.kanidm.ldapLocalDomain ]) (mkIf tailscale.enable [ access.kanidm.tailDomain ]) - (mkIf (kanidm.server.ldap.enable && tailscale.enable) [ + (mkIf (access.kanidm.ldapEnable && tailscale.enable) [ access.kanidm.ldapTailDomain ]) ]; }; + ${access.freeipa.domain} = { + inherit (nginx) group; + extraDomainNames = mkMerge [ + [ + access.freeipa.localDomain + access.ldap.domain + access.ldap.localDomain + ] + (mkIf tailscale.enable [ + access.freeipa.tailDomain + access.ldap.tailDomain + ]) + ]; + }; ${access.proxmox.domain} = { inherit (nginx) group; extraDomainNames = mkMerge [ @@ -92,14 +107,19 @@ in { access.kanidm = assert kanidm.enableServer; { inherit (kanidm.server.frontend) domain port; host = tei.networking.access.hostnameForNetwork.local; - ldapHost = "idp.local.${config.networking.domain}"; - ldapPort = 389; - ldapEnable = true; + ldapEnable = false; + }; + access.freeipa = { + host = "idp.local.${config.networking.domain}"; }; virtualHosts = { ${access.kanidm.domain} = { useACMEHost = access.kanidm.domain; }; + ${access.freeipa.domain} = { + forceSSL = true; + useACMEHost = access.freeipa.domain; + }; ${access.proxmox.domain} = { useACMEHost = access.proxmox.domain; }; diff --git a/tf/cloudflare_records.tf b/tf/cloudflare_records.tf index 850f091c..29cdf1ea 100644 --- a/tf/cloudflare_records.tf +++ b/tf/cloudflare_records.tf @@ -19,9 +19,11 @@ module "hakurei_system_records" { "prox", "id", "ldap", + "freeipa", ] global_subdomains = [ "plex", + "idp", "ldap", ] }