{ config, lib, pkgs, utils, ... }: let cfg = config.services.vouch-proxy; settingsFormat = pkgs.formats.yaml { }; instanceType = { name, config, options, ... }: { options = { package = lib.mkPackageOption pkgs "vouch-proxy" { }; settings = lib.mkOption { description = '' Configuration to be passed to Vouch Proxy. ::: {.note} For settings with sensitive values like JWT token secret, you can specify a `_secret` attribute with a path value. In the final version of the generated settings, the key will have the value with the content of the specified path. ::: ''; type = settingsFormat.type; default = { }; example = lib.literalExpression '' { vouch = { listen = "127.0.0.1"; port = 30746; domains = [ "gitea.example.com" ]; allowAllUsers = true; jwt.secret._secret = "/path/to/jwt-secret"; session.key._secret = "/path/to/session-key-secret"; }; oauth = { provider = "github"; client_id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; client_secret._secret = "/path/to/secret"; auth_url = "https://gitea.example.com/login/oauth/authorize"; token_url = "https://gitea.example.com/login/oauth/access_token"; user_info_url = "https://gitea.example.com/api/v1/user?token="; callback_url = "https://example.com/auth"; }; } ''; }; settingsFile = lib.mkOption { type = with lib.types; nullOr path; default = null; defaultText = lib.literalExpression "settingsFile"; description = '' The path of the configuration file. If `null`, it uses the filepath from NixOS-generated settings. ''; example = lib.literalExpression "/etc/vouch-proxy/config.yml"; }; }; }; mkVouchInstance = name: instance: let inherit (instance) settings settingsFile; settingsFile' = "/var/lib/vouch-proxy/${name}-config.yml"; in lib.nameValuePair "vouch-proxy-${utils.escapeSystemdPath name}" { preStart = if (settings != { } && settingsFile == null) then '' ${pkgs.writeScript "vouch-proxy-replace-secrets" (utils.genJqSecretsReplacementSnippet settings settingsFile')} chmod 0600 "${settingsFile'}" '' else '' install -Dm0600 "${settingsFile}" "${settingsFile'}" ''; script = "${lib.getExe' instance.package "vouch-proxy"} -config ${settingsFile'}"; serviceConfig = { User = config.users.users.vouch-proxy.name; Group = config.users.groups.vouch-proxy.name; Restart = "on-failure"; RestartSec = 5; PrivateTmp = true; PrivateDevices = true; LockPersonality = true; MemoryDenyWriteExecute = true; NoNewPrivileges = true; RestrictSUIDSGID = true; RestrictRealtime = true; ProtectClock = true; ProtectKernelLogs = true; ProtectKernelTunables = true; ProtectKernelModules = true; ProtectHostname = true; ProtectControlGroups = true; ProtectProc = "invisible"; ProcSubset = "pid"; SystemCallFilter = [ "@system-service" "~@cpu-emulation" "~@keyring" "~@module" "~@privileged" "~@reboot" ]; SystemCallErrorNumber = "EPERM"; SystemCallArchitectures = "native"; RuntimeDirectory = "vouch-proxy"; StateDirectory = "vouch-proxy"; # Restricting what capabilities this service has. CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ]; AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ]; # Limit this service to Unix sockets and IPs. RestrictAddressFamilies = [ "AF_LOCAL" "AF_INET" "AF_INET6" ]; RestrictNamespaces = true; }; wantedBy = [ "multi-user.target" ]; }; in { options.services.vouch-proxy = { enable = lib.mkEnableOption "Vouch Proxy, a proxy for SSO and OAuth/OIDC logins"; instances = lib.mkOption { type = with lib.types; attrsOf (submodule instanceType); description = lib.mdDoc "Instances of Vouch proxy to be run."; default = { }; example = lib.literalExpression '' { "vouch.example.com".settings = { vouch = { listen = "127.0.0.1"; port = 19900; domains = [ "example.com" ]; jwt.secret._secret = "/var/lib/secrets/vouch-proxy-jwt-secret"; }; oauth = rec { provider = "oidc"; client_id = "vouch"; client_secret._secret = "/var/lib/secrets/vouch-proxy-client-secret"; code_challenge_method = "S256"; auth_url = "https://auth.example.com/ui/oauth2"; token_url = "https://auth.example.com/oauth2/token"; user_info_url = "https://auth.example.com/oauth2/openid/$${client_id}/userinfo"; scopes = [ "login" "email" ]; callback_url = "https://auth.example.com/auth"; }; }; } ''; }; }; config = lib.mkIf cfg.enable { systemd.services = lib.mapAttrs' mkVouchInstance cfg.instances; users.users.vouch-proxy = { description = "Vouch Proxy user"; group = config.users.groups.vouch-proxy.name; isSystemUser = true; }; users.groups.vouch-proxy = { }; }; }