# SPDX-FileCopyrightText: 2024 Tom Hubrecht # # SPDX-License-Identifier: EUPL-1.2 { config, lib, pkgs, meta, ... }: let inherit (lib) attrValues catAttrs escapeRegex concatStringsSep mapAttrs' nameValuePair ; domain = "sso.dgnum.eu"; port = 8443; cert = config.security.acme.certs.${domain}; allowedDomains = builtins.map escapeRegex ( (builtins.map (s: "${s}.dgnum.eu") [ # DGNum subdomains "cloud" "git" "videos" "social" "demarches" "netbird" ]) ++ [ # Extra domains "netbird-beta.hubrecht.ovh" ] ); usernameFor = member: meta.organization.members.${member}.username; in { nixpkgs.config.permittedInsecurePackages = [ "kanidm-1.3.3" ]; services.kanidm = { enableServer = true; package = pkgs.kanidm_1_4; serverSettings = { inherit domain; origin = "https://${domain}"; bindaddress = "127.0.0.1:${builtins.toString port}"; ldapbindaddress = "0.0.0.0:636"; trust_x_forward_for = true; tls_chain = "${cert.directory}/fullchain.pem"; tls_key = "${cert.directory}/key.pem"; }; provision = { enable = true; persons = mapAttrs' ( _: { email, name, username, ... }: nameValuePair username { displayName = name; mailAddresses = [ email ]; } ) meta.organization.members; groups = { grp_active.members = catAttrs "username" (attrValues meta.organization.members); } // (mapAttrs' ( name: members: nameValuePair "grp_${name}" { members = builtins.map usernameFor members; } ) meta.organization.groups); # INFO: The authentication resources declared here can only be for internal services, # as regular members cannot be statically known. systems.oauth2 = { dgn_grafana = { displayName = "Grafana [Analysis]"; originLanding = "https://grafana.dgnum.eu"; originUrl = "https://grafana.dgnum.eu/login/generic_oauth"; preferShortUsername = true; scopeMaps.grp_active = [ "openid" "profile" "email" ]; }; dgn_librenms = { allowInsecureClientDisablePkce = true; displayName = "LibreNMS [Network]"; enableLegacyCrypto = true; originLanding = "https://nms.dgnum.eu"; originUrl = "https://nms.dgnum.eu/auth/kanidm/callback"; preferShortUsername = true; scopeMaps.grp_active = [ "openid" "profile" "email" ]; }; dgn_netbird = { displayName = "Netbird [VPN]"; enableLocalhostRedirects = true; originLanding = "https://netbird.dgnum.eu"; originUrl = "https://netbird.dgnum.eu/index"; preferShortUsername = true; public = true; scopeMaps.grp_active = [ "openid" "profile" "email" ]; }; dgn_netbox = { allowInsecureClientDisablePkce = true; displayName = "Netbox [Inventory]"; enableLegacyCrypto = true; originLanding = "https://netbox.dgnum.eu"; originUrl = "https://netbox.dgnum.eu/oauth/complete/oidc/"; preferShortUsername = true; scopeMaps.grp_active = [ "openid" "profile" "email" ]; }; dgn_outline = { displayName = "Outline [Docs]"; originUrl = "https://docs.dgnum.eu/auth/oidc.callback"; originLanding = "https://docs.dgnum.eu"; preferShortUsername = true; allowInsecureClientDisablePkce = true; scopeMaps.grp_active = [ "openid" "profile" "email" ]; }; }; }; }; users.users.kanidm.extraGroups = [ cert.group ]; dgn-web.internalPorts.kanidm = port; services.nginx = { enable = true; virtualHosts.${domain} = { enableACME = true; forceSSL = true; locations."/" = { proxyPass = "https://127.0.0.1:${builtins.toString port}"; extraConfig = '' if ( $request_method !~ ^(GET|POST|HEAD|OPTIONS|PUT|PATCH|DELETE)$ ) { return 444; } set $origin $http_origin; if ($origin !~ '^https?://(${concatStringsSep "|" allowedDomains})$') { set $origin 'https://${domain}'; } proxy_hide_header Access-Control-Allow-Origin; if ($request_method = 'OPTIONS') { add_header 'Access-Control-Allow-Origin' "$origin" always; add_header 'Access-Control-Allow-Methods' 'GET, POST, PATCH, PUT, DELETE, OPTIONS' always; add_header 'Access-Control-Allow-Headers' 'Content-Type, Accept, Authorization' always; add_header 'Access-Control-Allow-Credentials' 'true' always; add_header Access-Control-Max-Age 1728000; add_header Content-Type 'text/plain charset=UTF-8'; add_header Content-Length 0; return 204; } if ($request_method ~ '(GET|POST|PATCH|PUT|DELETE)') { add_header Access-Control-Allow-Origin "$origin" always; add_header Access-Control-Allow-Methods 'GET, POST, PATCH, PUT, DELETE, OPTIONS' always; add_header Access-Control-Allow-Headers 'Content-Type, Accept, Authorization' always; add_header Access-Control-Allow-Credentials true always; } ''; }; }; }; networking.firewall.allowedTCPPorts = [ 636 ]; networking.firewall.allowedUDPPorts = [ 636 ]; dgn-backups.jobs.kanidm.settings.paths = [ "/var/lib/kanidm" ]; }