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 = let
28 vhostSubmodule = lib.types.submodule {
29 options = {
30 allowed_groups = lib.mkOption {
31 type = lib.types.nullOr (lib.types.listOf lib.types.str);
32 description = "List of groups to allow access to this vhost, or null to allow all.";
33 default = null;
34 };
35 allowed_emails = lib.mkOption {
36 type = lib.types.nullOr (lib.types.listOf lib.types.str);
37 description = "List of emails to allow access to this vhost, or null to allow all.";
38 default = null;
39 };
40 allowed_email_domains = lib.mkOption {
41 type = lib.types.nullOr (lib.types.listOf lib.types.str);
42 description = "List of email domains to allow access to this vhost, or null to allow all.";
43 default = null;
44 };
45 };
46 };
47 oldType = lib.types.listOf lib.types.str;
48 convertFunc = x:
49 lib.warn "services.oauth2-proxy.nginx.virtualHosts should be an attrset, found ${lib.generators.toPretty {} x}"
50 lib.genAttrs x (_: {});
51 newType = lib.types.attrsOf vhostSubmodule;
52 in lib.types.coercedTo oldType convertFunc newType;
53 default = {};
54 example = {
55 "protected.foo.com" = {
56 allowed_groups = ["admins"];
57 allowed_emails = ["boss@foo.com"];
58 };
59 };
60 description = ''
61 Nginx virtual hosts to put behind the oauth2 proxy.
62 You can exclude specific locations by setting `auth_request off;` in the locations extraConfig setting.
63 '';
64 };
65 };
66
67 config.services.oauth2-proxy = lib.mkIf (cfg.virtualHosts != {} && (lib.hasPrefix "127.0.0.1:" cfg.proxy)) {
68 enable = true;
69 };
70
71 config.services.nginx = lib.mkIf (cfg.virtualHosts != {} && config.services.oauth2-proxy.enable) (lib.mkMerge ([
72 {
73 virtualHosts.${cfg.domain}.locations."/oauth2/" = {
74 proxyPass = cfg.proxy;
75 extraConfig = ''
76 proxy_set_header X-Scheme $scheme;
77 proxy_set_header X-Auth-Request-Redirect $scheme://$host$request_uri;
78 '';
79 };
80 }
81 ] ++ lib.optional (cfg.virtualHosts != {}) {
82 recommendedProxySettings = true; # needed because duplicate headers
83 } ++ (lib.mapAttrsToList (vhost: conf: {
84 virtualHosts.${vhost} = {
85 locations = {
86 "/oauth2/auth" = let
87 maybeQueryArg = name: value:
88 if value == null then null
89 else "${name}=${lib.concatStringsSep "," (builtins.map lib.escapeURL value)}";
90 allArgs = lib.mapAttrsToList maybeQueryArg conf;
91 cleanArgs = builtins.filter (x: x != null) allArgs;
92 cleanArgsStr = lib.concatStringsSep "&" cleanArgs;
93 in {
94 # nginx doesn't support passing query string arguments to auth_request,
95 # so pass them here instead
96 proxyPass = "${cfg.proxy}/oauth2/auth?${cleanArgsStr}";
97 extraConfig = ''
98 auth_request off;
99 proxy_set_header X-Scheme $scheme;
100 # nginx auth_request includes headers but not body
101 proxy_set_header Content-Length "";
102 proxy_pass_request_body off;
103 '';
104 };
105 "@redirectToAuth2ProxyLogin" = {
106 return = "307 https://${cfg.domain}/oauth2/start?rd=$scheme://$host$request_uri";
107 extraConfig = ''
108 auth_request off;
109 '';
110 };
111 };
112
113 extraConfig = ''
114 auth_request /oauth2/auth;
115 error_page 401 = @redirectToAuth2ProxyLogin;
116
117 # pass information via X-User and X-Email headers to backend,
118 # requires running with --set-xauthrequest flag
119 auth_request_set $user $upstream_http_x_auth_request_user;
120 auth_request_set $email $upstream_http_x_auth_request_email;
121 proxy_set_header X-User $user;
122 proxy_set_header X-Email $email;
123
124 # if you enabled --cookie-refresh, this is needed for it to work with auth_request
125 auth_request_set $auth_cookie $upstream_http_set_cookie;
126 add_header Set-Cookie $auth_cookie;
127 '';
128 };
129 }) cfg.virtualHosts)));
130}