commit 2d3aac87a860e17a9742ed423416f55655f9bf76
parent ef6598b88e5081ad1e8a01ac187a58bcbcdb3f9c
Author: Katja Ramona Sophie Kwast (zaphyra) <git@zaphyra.eu>
Date: Wed, 22 Jul 2026 21:31:47 +0200
parent ef6598b88e5081ad1e8a01ac187a58bcbcdb3f9c
Author: Katja Ramona Sophie Kwast (zaphyra) <git@zaphyra.eu>
Date: Wed, 22 Jul 2026 21:31:47 +0200
nixos/common/services/oauth2-proxy: init
1 file changed, 226 insertions(+), 0 deletions(-)
A
|
226
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
diff --git a/nixosModules/common/services/oauth2-proxy.nix b/nixosModules/common/services/oauth2-proxy.nix @@ -0,0 +1,226 @@ +{ + config, + lib, + pkgs, + ... +}: + +let + inherit (lib) types; + + settingsFormat = pkgs.formats.toml { }; + +in +{ + + options.common.services.oauth2-proxy = lib.mkOption { + description = "Configuration for oauth2-proxy instances."; + default = { }; + type = types.attrsOf ( + types.submodule { + options = { + enable = (lib.mkEnableOption "oauth2-proxy") // { + default = true; + }; + + package = lib.mkPackageOption pkgs "oauth2-proxy" { }; + + environmentFile = lib.mkOption { + type = with lib.types; nullOr path; + default = null; + }; + + nginx = { + enable = lib.mkEnableOption ""; + virtualHost = lib.mkOption { + type = with lib.types; nullOr str; + default = null; + }; + protectedLocations = lib.mkOption { + type = with lib.types; listOf str; + default = [ "/" ]; + }; + }; + + settings = lib.mkOption { + default = { }; + type = types.submodule { + freeformType = settingsFormat.type; + options = { + proxy_prefix = lib.mkOption { + type = lib.types.str; + default = "/oauth2"; + }; + + ping_path = lib.mkOption { + type = lib.types.str; + default = "/oauth2/ping"; + }; + + trusted_proxy_ips = lib.mkOption { + type = lib.types.str; + default = "::1"; + }; + + email_domains = lib.mkOption { + type = lib.types.str; + default = "*"; + }; + + code_challenge_method = lib.mkOption { + type = lib.types.str; + default = "S256"; + }; + + whitelist_domains = lib.mkOption { + type = with lib.types; listOf str; + default = [ "oidc.fc9f.de" ]; + }; + }; + }; + }; + }; + } + ); + }; + + config = { + assertions = lib.flatten ( + lib.flip lib.mapAttrsToList config.common.services.oauth2-proxy (name: cfg: [ ]) + ); + + services.nginx.virtualHosts = + lib.flip lib.mapAttrs' + (lib.filterAttrs (name: value: value.nginx.enable) config.common.services.oauth2-proxy) + ( + name: cfg: + lib.nameValuePair cfg.nginx.virtualHost { + locations = + (builtins.listToAttrs ( + lib.map ( + location: + lib.nameValuePair location { + extraConfig = '' + auth_request ${config.common.services.oauth2-proxy."${name}".settings.proxy_prefix}/auth; + error_page 401 403 =302 $scheme://$host${ + config.common.services.oauth2-proxy."${name}".settings.proxy_prefix + }/start?rd=$scheme://$host$request_uri; + ''; + } + ) config.common.services.oauth2-proxy."${name}".nginx.protectedLocations + )) + // { + "${config.common.services.oauth2-proxy.${name}.settings.proxy_prefix}".extraConfig = '' + auth_request off; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Auth-Request-Redirect $request_uri; + proxy_pass http://${config.common.services.oauth2-proxy.${name}.settings.http_address}; + ''; + "= ${config.common.services.oauth2-proxy."${name}".settings.proxy_prefix}/auth".extraConfig = '' + internal; + auth_request off; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-Uri $request_uri; + proxy_set_header Content-Length ""; + proxy_pass_request_body off; + proxy_pass http://${config.common.services.oauth2-proxy."${name}".settings.http_address}${ + config.common.services.oauth2-proxy."${name}".settings.proxy_prefix + }/auth; + ''; + "= ${config.common.services.oauth2-proxy."${name}".settings.proxy_prefix}/sign_out".extraConfig = '' + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Auth-Request-Redirect ${ + config.common.services.oauth2-proxy.${name}.settings.oidc_issuer_url + }/logout; + proxy_pass http://${config.common.services.oauth2-proxy.${name}.settings.http_address}; + ''; + "= ${config.common.services.oauth2-proxy."${name}".settings.proxy_prefix}/useerinfo".return = "403"; + }; + } + ); + + systemd.services = lib.flip lib.mapAttrs' config.common.services.oauth2-proxy ( + name: cfg: + let + unitName = "oauth2-proxy${lib.optionalString (name != "") "-${name}"}"; + in + (lib.nameValuePair unitName ( + let + settingsSecretsReplaced = pkgs.zphaLib.replaceSecrets "${unitName}.service" ( + lib.filterAttrsRecursive (name: value: value != null) cfg.settings + ); + settingsFile = settingsFormat.generate "${unitName}.toml" (settingsSecretsReplaced.output); + + in + { + enable = cfg.enable; + # confinement.enable = true; + + restartTriggers = [ settingsFile ]; + + wantedBy = [ "multi-user.target" ]; + + wants = [ "network-online.target" ]; + after = [ "network-online.target" ]; + + serviceConfig = { + DynamicUser = true; + + ExecStart = "${lib.getExe cfg.package} --config ${settingsFile}"; + + Restart = "always"; + + EnvironmentFile = lib.mkIf (cfg.environmentFile != null) cfg.environmentFile; + LoadCredential = settingsSecretsReplaced.credentials; + + ProtectSystem = "full"; + ProtectControlGroups = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + LockPersonality = true; + + DevicePolicy = "strict"; + DeviceAllow = [ "/dev/stdin r" ]; + + SystemCallArchitectures = "native"; + MemoryDenyWriteExecute = true; + + NoNewPrivileges = true; + PrivateTmp = true; + PrivateDevices = true; + UMask = "077"; + + RestrictAddressFamilies = "AF_INET AF_INET6"; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + + RemoveIPC = true; + PrivateIPC = true; + + SystemCallFilter = [ + "@system-service" + "~@resources" + "~@mount" + "~@setuid" + "~@cpu-emulation" + "~@debug" + "~@keyring" + "~@obsolete" + "~@pkey" + "setrlimit" + ]; + }; + } + )) + ); + }; + + meta.maintainers = with lib.maintainers; [ + zaphyra + ]; + +}