From b901c40a8e2aeabafedbaeec6e07f3ce4567d42a Mon Sep 17 00:00:00 2001 From: Yorick van Pelt Date: Thu, 12 Apr 2018 18:45:14 +0200 Subject: [PATCH 1/3] oauth2_proxy: update module for extraConfig support --- .../services/security/oauth2_proxy.nix | 125 ++++++++++-------- 1 file changed, 71 insertions(+), 54 deletions(-) diff --git a/nixos/modules/services/security/oauth2_proxy.nix b/nixos/modules/services/security/oauth2_proxy.nix index ef48d52e7a94..d4557a7dfe21 100644 --- a/nixos/modules/services/security/oauth2_proxy.nix +++ b/nixos/modules/services/security/oauth2_proxy.nix @@ -6,70 +6,80 @@ with lib; let cfg = config.services.oauth2_proxy; - # Use like: - # repeatedArgs (arg: "--arg=${arg}") args - repeatedArgs = concatMapStringsSep " "; - # oauth2_proxy provides many options that are only relevant if you are using # a certain provider. This set maps from provider name to a function that # takes the configuration and returns a string that can be inserted into the # command-line to launch oauth2_proxy. providerSpecificOptions = { - azure = cfg: '' - --azure-tenant=${cfg.azure.tenant} \ - --resource=${cfg.azure.resource} \ - ''; + azure = cfg: { + azure.tenant = cfg.azure.tenant; + resource = cfg.azure.resource; + }; - github = cfg: '' - ${optionalString (!isNull cfg.github.org) "--github-org=${cfg.github.org}"} \ - ${optionalString (!isNull cfg.github.team) "--github-org=${cfg.github.team}"} \ - ''; + github = cfg: { github = { + inherit (cfg.github) org team; + }; }; - google = cfg: '' - --google-admin-email=${cfg.google.adminEmail} \ - --google-service-account=${cfg.google.serviceAccountJSON} \ - ${repeatedArgs (group: "--google-group=${group}") cfg.google.groups} \ - ''; + google = cfg: { google = with cfg.google; { + admin-email = adminEmail; + service-account = serviceAccountJSON; + group = groups; + }; }; }; authenticatedEmailsFile = pkgs.writeText "authenticated-emails" cfg.email.addresses; - getProviderOptions = cfg: provider: providerSpecificOptions.${provider} or (_: "") cfg; + getProviderOptions = cfg: provider: providerSpecificOptions.${provider} or (_: {}) cfg; - mkCommandLine = cfg: '' - --provider='${cfg.provider}' \ - ${optionalString (!isNull cfg.email.addresses) "--authenticated-emails-file='${authenticatedEmailsFile}'"} \ - --approval-prompt='${cfg.approvalPrompt}' \ - ${optionalString (cfg.passBasicAuth && !isNull cfg.basicAuthPassword) "--basic-auth-password='${cfg.basicAuthPassword}'"} \ - --client-id='${cfg.clientID}' \ - --client-secret='${cfg.clientSecret}' \ - ${optionalString (!isNull cfg.cookie.domain) "--cookie-domain='${cfg.cookie.domain}'"} \ - --cookie-expire='${cfg.cookie.expire}' \ - --cookie-httponly=${boolToString cfg.cookie.httpOnly} \ - --cookie-name='${cfg.cookie.name}' \ - --cookie-secret='${cfg.cookie.secret}' \ - --cookie-secure=${boolToString cfg.cookie.secure} \ - ${optionalString (!isNull cfg.cookie.refresh) "--cookie-refresh='${cfg.cookie.refresh}'"} \ - ${optionalString (!isNull cfg.customTemplatesDir) "--custom-templates-dir='${cfg.customTemplatesDir}'"} \ - ${repeatedArgs (x: "--email-domain='${x}'") cfg.email.domains} \ - --http-address='${cfg.httpAddress}' \ - ${optionalString (!isNull cfg.htpasswd.file) "--htpasswd-file='${cfg.htpasswd.file}' --display-htpasswd-form=${boolToString cfg.htpasswd.displayForm}"} \ - ${optionalString (!isNull cfg.loginURL) "--login-url='${cfg.loginURL}'"} \ - --pass-access-token=${boolToString cfg.passAccessToken} \ - --pass-basic-auth=${boolToString cfg.passBasicAuth} \ - --pass-host-header=${boolToString cfg.passHostHeader} \ - --proxy-prefix='${cfg.proxyPrefix}' \ - ${optionalString (!isNull cfg.profileURL) "--profile-url='${cfg.profileURL}'"} \ - ${optionalString (!isNull cfg.redeemURL) "--redeem-url='${cfg.redeemURL}'"} \ - ${optionalString (!isNull cfg.redirectURL) "--redirect-url='${cfg.redirectURL}'"} \ - --request-logging=${boolToString cfg.requestLogging} \ - ${optionalString (!isNull cfg.scope) "--scope='${cfg.scope}'"} \ - ${repeatedArgs (x: "--skip-auth-regex='${x}'") cfg.skipAuthRegexes} \ - ${optionalString (!isNull cfg.signatureKey) "--signature-key='${cfg.signatureKey}'"} \ - --upstream='${cfg.upstream}' \ - ${optionalString (!isNull cfg.validateURL) "--validate-url='${cfg.validateURL}'"} \ - ${optionalString cfg.tls.enable "--tls-cert='${cfg.tls.certificate}' --tls-key='${cfg.tls.key}' --https-address='${cfg.tls.httpsAddress}'"} \ - '' + getProviderOptions cfg cfg.provider; + allConfig = with cfg; { + inherit (cfg) provider scope upstream; + approval-prompt = approvalPrompt; + basic-auth-password = basicAuthPassword; + client-id = clientID; + client-secret = clientSecret; + custom-templates-dir = customTemplatesDir; + email-domain = email.domains; + http-address = httpAddress; + login-url = loginURL; + pass-access-token = passAccessToken; + pass-basic-auth = passBasicAuth; + pass-host-header = passHostHeader; + proxy-prefix = proxyPrefix; + profile-url = profileURL; + redeem-url = redeemURL; + redirect-url = redirectURL; + request-logging = requestLogging; + skip-auth-regex = skipAuthRegexes; + signature-key = signatureKey; + validate-url = validateURL; + htpasswd-file = htpasswd.file; + cookie = { + inherit (cookie) domain secure expire name secret refresh; + httponly = cookie.httpOnly; + }; + } // lib.optionalAttrs (!isNull cfg.email.addresses) { + authenticated-emails-file = authenticatedEmailsFile; + } // lib.optionalAttrs (cfg.passBasicAuth) { + basic-auth-password = cfg.basicAuthPassword; + } // lib.optionalAttrs (!isNull cfg.htpasswd.file) { + display-htpasswd-file = cfg.htpasswd.displayForm; + } // lib.optionalAttrs tls.enable { + tls-cert = tls.certificate; + tls-key = tls.key; + https-address = tls.httpsAddress; + } // (getProviderOptions cfg cfg.provider) // cfg.extraConfig; + + mapConfig = key: attr: + if (!isNull attr && attr != []) then ( + if (builtins.typeOf attr) == "set" then concatStringsSep " " + (mapAttrsToList (name: value: mapConfig (key + "-" + name) value) attr) else + if (builtins.typeOf attr) == "list" then concatMapStringsSep " " (mapConfig key) attr else + if (builtins.typeOf attr) == "bool" then "--${key}=${boolToString attr}" else + if (builtins.typeOf attr) == "string" then "--${key}='${attr}'" else + "--${key}=${toString attr}") + else ""; + + configString = concatStringsSep " " (mapAttrsToList mapConfig allConfig); in { options.services.oauth2_proxy = { @@ -365,7 +375,7 @@ in }; secret = mkOption { - type = types.str; + type = types.nullOr types.str; description = '' The seed string for secure cookies. ''; @@ -494,6 +504,13 @@ in ''; }; + extraConfig = mkOption { + default = {}; + description = '' + Extra config to pass to oauth2_proxy. + ''; + }; + }; config = mkIf cfg.enable { @@ -511,7 +528,7 @@ in serviceConfig = { User = "oauth2_proxy"; Restart = "always"; - ExecStart = "${cfg.package.bin}/bin/oauth2_proxy ${mkCommandLine cfg}"; + ExecStart = "${cfg.package.bin}/bin/oauth2_proxy ${configString}"; }; }; From a037cbd46bab2553921c5d5de51641bfdcf902a9 Mon Sep 17 00:00:00 2001 From: Yorick van Pelt Date: Mon, 16 Apr 2018 14:06:22 +0200 Subject: [PATCH 2/3] oauth2_proxy: add keyFile, make some options optional --- .../services/security/oauth2_proxy.nix | 37 +++++++++++++++++-- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/nixos/modules/services/security/oauth2_proxy.nix b/nixos/modules/services/security/oauth2_proxy.nix index d4557a7dfe21..cf41625d16c8 100644 --- a/nixos/modules/services/security/oauth2_proxy.nix +++ b/nixos/modules/services/security/oauth2_proxy.nix @@ -20,7 +20,7 @@ let inherit (cfg.github) org team; }; }; - google = cfg: { google = with cfg.google; { + google = cfg: { google = with cfg.google; optionalAttrs (groups != []) { admin-email = adminEmail; service-account = serviceAccountJSON; group = groups; @@ -57,6 +57,7 @@ let inherit (cookie) domain secure expire name secret refresh; httponly = cookie.httpOnly; }; + set-xauthrequest = setXauthrequest; } // lib.optionalAttrs (!isNull cfg.email.addresses) { authenticated-emails-file = authenticatedEmailsFile; } // lib.optionalAttrs (cfg.passBasicAuth) { @@ -120,7 +121,7 @@ in }; clientID = mkOption { - type = types.str; + type = types.nullOr types.str; description = '' The OAuth Client ID. ''; @@ -128,7 +129,7 @@ in }; clientSecret = mkOption { - type = types.str; + type = types.nullOr types.str; description = '' The OAuth Client Secret. ''; @@ -282,7 +283,8 @@ in #################################################### # UPSTREAM Configuration upstream = mkOption { - type = types.commas; + type = with types; coercedTo string (x: [x]) (listOf string); + default = []; description = '' The http url(s) of the upstream endpoint or file:// paths for static files. Routing is based on the path. @@ -504,6 +506,14 @@ in ''; }; + setXauthrequest = mkOption { + type = types.nullOr types.bool; + default = null; + description = '' + Set X-Auth-Request-User and X-Auth-Request-Email response headers (useful in Nginx auth_request mode). + ''; + }; + extraConfig = mkOption { default = {}; description = '' @@ -511,10 +521,28 @@ in ''; }; + keyFile = mkOption { + type = types.nullOr types.string; + default = null; + description = '' + oauth2_proxy allows passing sensitive configuration via environment variables. + Make a file that contains lines like + OAUTH2_PROXY_CLIENT_SECRET=asdfasdfasdf.apps.googleuserscontent.com + and specify the path here. + ''; + example = "/run/keys/oauth2_proxy"; + }; + }; config = mkIf cfg.enable { + services.oauth2_proxy = mkIf (!isNull cfg.keyFile) { + clientID = mkDefault null; + clientSecret = mkDefault null; + cookie.secret = mkDefault null; + }; + users.extraUsers.oauth2_proxy = { description = "OAuth2 Proxy"; }; @@ -529,6 +557,7 @@ in User = "oauth2_proxy"; Restart = "always"; ExecStart = "${cfg.package.bin}/bin/oauth2_proxy ${configString}"; + EnvironmentFile = mkIf (cfg.keyFile != null) cfg.keyFile; }; }; From 048c991eb0344c368ba9b29e0168faf8b2aff9f7 Mon Sep 17 00:00:00 2001 From: Yorick van Pelt Date: Fri, 27 Apr 2018 16:45:38 +0200 Subject: [PATCH 3/3] oauth2_proxy: use explicit upstream default for setXauthrequest --- nixos/modules/services/security/oauth2_proxy.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nixos/modules/services/security/oauth2_proxy.nix b/nixos/modules/services/security/oauth2_proxy.nix index cf41625d16c8..433d97c2a7d7 100644 --- a/nixos/modules/services/security/oauth2_proxy.nix +++ b/nixos/modules/services/security/oauth2_proxy.nix @@ -508,9 +508,9 @@ in setXauthrequest = mkOption { type = types.nullOr types.bool; - default = null; + default = false; description = '' - Set X-Auth-Request-User and X-Auth-Request-Email response headers (useful in Nginx auth_request mode). + Set X-Auth-Request-User and X-Auth-Request-Email response headers (useful in Nginx auth_request mode). Setting this to 'null' means using the upstream default (false). ''; };