1{ config, lib, ... }:
2let
3 cfg = config.services.oauth2-proxy.nginx;
4in
5{
6 options.services.oauth2-proxy.nginx = {
7 proxy = lib.mkOption {
8 type = lib.types.str;
9 default = config.services.oauth2-proxy.httpAddress;
10 defaultText = lib.literalExpression "config.services.oauth2-proxy.httpAddress";
11 description = ''
12 The address of the reverse proxy endpoint for oauth2-proxy
13 '';
14 };
15
16 domain = lib.mkOption {
17 type = lib.types.str;
18 description = ''
19 The domain under which the oauth2-proxy will be accesible and the path of cookies are set to.
20 This setting must be set to ensure back-redirects are working properly
21 if oauth2-proxy is configured with {option}`services.oauth2-proxy.cookie.domain`
22 or multiple {option}`services.oauth2-proxy.nginx.virtualHosts` that are not on the same domain.
23 '';
24 };
25
26 virtualHosts = lib.mkOption {
27 type =
28 let
29 vhostSubmodule = lib.types.submodule {
30 options = {
31 allowed_groups = lib.mkOption {
32 type = lib.types.nullOr (lib.types.listOf lib.types.str);
33 description = "List of groups to allow access to this vhost, or null to allow all.";
34 default = null;
35 };
36 allowed_emails = lib.mkOption {
37 type = lib.types.nullOr (lib.types.listOf lib.types.str);
38 description = "List of emails to allow access to this vhost, or null to allow all.";
39 default = null;
40 };
41 allowed_email_domains = lib.mkOption {
42 type = lib.types.nullOr (lib.types.listOf lib.types.str);
43 description = "List of email domains to allow access to this vhost, or null to allow all.";
44 default = null;
45 };
46 };
47 };
48 oldType = lib.types.listOf lib.types.str;
49 convertFunc =
50 x:
51 lib.warn
52 "services.oauth2-proxy.nginx.virtualHosts should be an attrset, found ${lib.generators.toPretty { } x}"
53 lib.genAttrs
54 x
55 (_: { });
56 newType = lib.types.attrsOf vhostSubmodule;
57 in
58 lib.types.coercedTo oldType convertFunc newType;
59 default = { };
60 example = {
61 "protected.foo.com" = {
62 allowed_groups = [ "admins" ];
63 allowed_emails = [ "boss@foo.com" ];
64 };
65 };
66 description = ''
67 Nginx virtual hosts to put behind the oauth2 proxy.
68 You can exclude specific locations by setting `auth_request off;` in the locations extraConfig setting.
69 '';
70 };
71 };
72
73 config.services.oauth2-proxy =
74 lib.mkIf (cfg.virtualHosts != { } && (lib.hasPrefix "127.0.0.1:" cfg.proxy))
75 {
76 enable = true;
77 };
78
79 config.services.nginx = lib.mkIf (cfg.virtualHosts != { } && config.services.oauth2-proxy.enable) (
80 lib.mkMerge (
81 [
82 {
83 virtualHosts.${cfg.domain}.locations."/oauth2/" = {
84 proxyPass = cfg.proxy;
85 extraConfig = ''
86 auth_request off;
87 proxy_set_header X-Scheme $scheme;
88 proxy_set_header X-Auth-Request-Redirect $scheme://$host$request_uri;
89 '';
90 };
91 }
92 ]
93 ++ lib.optional (cfg.virtualHosts != { }) {
94 recommendedProxySettings = true; # needed because duplicate headers
95 }
96 ++ (lib.mapAttrsToList (vhost: conf: {
97 virtualHosts.${vhost} = {
98 locations = {
99 "/".extraConfig = ''
100 # pass information via X-User and X-Email headers to backend, requires running with --set-xauthrequest flag
101 proxy_set_header X-User $user;
102 proxy_set_header X-Email $email;
103
104 # if you enabled --cookie-refresh, this is needed for it to work with auth_request
105 add_header Set-Cookie $auth_cookie;
106 '';
107
108 "= /oauth2/auth" =
109 let
110 maybeQueryArg =
111 name: value:
112 if value == null then
113 null
114 else
115 "${name}=${lib.concatStringsSep "," (builtins.map lib.escapeURL value)}";
116 allArgs = lib.mapAttrsToList maybeQueryArg conf;
117 cleanArgs = builtins.filter (x: x != null) allArgs;
118 cleanArgsStr = lib.concatStringsSep "&" cleanArgs;
119 in
120 {
121 # nginx doesn't support passing query string arguments to auth_request,
122 # so pass them here instead
123 proxyPass = "${cfg.proxy}/oauth2/auth?${cleanArgsStr}";
124 extraConfig = ''
125 auth_request off;
126 proxy_set_header X-Scheme $scheme;
127 # nginx auth_request includes headers but not body
128 proxy_set_header Content-Length "";
129 proxy_pass_request_body off;
130 '';
131 };
132
133 "@redirectToAuth2ProxyLogin" = {
134 return = "307 https://${cfg.domain}/oauth2/start?rd=$scheme://$host$request_uri";
135 extraConfig = ''
136 auth_request off;
137 '';
138 };
139 };
140
141 extraConfig = ''
142 auth_request /oauth2/auth;
143 error_page 401 = @redirectToAuth2ProxyLogin;
144
145 # set variables being used in locations."/".extraConfig
146 auth_request_set $user $upstream_http_x_auth_request_user;
147 auth_request_set $email $upstream_http_x_auth_request_email;
148 auth_request_set $auth_cookie $upstream_http_set_cookie;
149 '';
150 };
151 }) cfg.virtualHosts)
152 )
153 );
154}