Merge pull request #273233 from SuperSandro2000/oauth2-proxy

nixos/oauth2-proxy{,-nginx}: renamed from oauth2_proxy, also renamed the servi…

authored by Sandro and committed by GitHub bafcff9b 98f5a7c4

+155 -155
+2
nixos/doc/manual/release-notes/rl-2405.section.md
··· 398 399 - `services.zope2` has been removed as `zope2` is unmaintained and was relying on Python2. 400 401 - `services.avahi.nssmdns` got split into `services.avahi.nssmdns4` and `services.avahi.nssmdns6` which enable the mDNS NSS switch for IPv4 and IPv6 respectively. 402 Since most mDNS responders only register IPv4 addresses, most users want to keep the IPv6 support disabled to avoid long timeouts. 403
··· 398 399 - `services.zope2` has been removed as `zope2` is unmaintained and was relying on Python2. 400 401 + - `services.oauth2_proxy` was renamed to `services.oauth2-proxy`. Also the corresponding service, user and group were renamed. 402 + 403 - `services.avahi.nssmdns` got split into `services.avahi.nssmdns4` and `services.avahi.nssmdns6` which enable the mDNS NSS switch for IPv4 and IPv6 respectively. 404 Since most mDNS responders only register IPv4 addresses, most users want to keep the IPv6 support disabled to avoid long timeouts. 405
+2 -2
nixos/modules/module-list.nix
··· 1256 ./services/security/kanidm.nix 1257 ./services/security/munge.nix 1258 ./services/security/nginx-sso.nix 1259 - ./services/security/oauth2_proxy.nix 1260 - ./services/security/oauth2_proxy_nginx.nix 1261 ./services/security/opensnitch.nix 1262 ./services/security/pass-secret-service.nix 1263 ./services/security/physlock.nix
··· 1256 ./services/security/kanidm.nix 1257 ./services/security/munge.nix 1258 ./services/security/nginx-sso.nix 1259 + ./services/security/oauth2-proxy.nix 1260 + ./services/security/oauth2-proxy-nginx.nix 1261 ./services/security/opensnitch.nix 1262 ./services/security/pass-secret-service.nix 1263 ./services/security/physlock.nix
+124 -125
nixos/modules/services/security/oauth2_proxy.nix nixos/modules/services/security/oauth2-proxy.nix
··· 1 - # NixOS module for oauth2_proxy. 2 - 3 { config, lib, pkgs, ... }: 4 5 - with lib; 6 let 7 - cfg = config.services.oauth2_proxy; 8 9 - # oauth2_proxy provides many options that are only relevant if you are using 10 # a certain provider. This set maps from provider name to a function that 11 # takes the configuration and returns a string that can be inserted into the 12 - # command-line to launch oauth2_proxy. 13 providerSpecificOptions = { 14 azure = cfg: { 15 azure-tenant = cfg.azure.tenant; ··· 73 } // (getProviderOptions cfg cfg.provider) // cfg.extraConfig; 74 75 mapConfig = key: attr: 76 - optionalString (attr != null && attr != []) ( 77 - if isDerivation attr then mapConfig key (toString attr) else 78 - if (builtins.typeOf attr) == "set" then concatStringsSep " " 79 - (mapAttrsToList (name: value: mapConfig (key + "-" + name) value) attr) else 80 - if (builtins.typeOf attr) == "list" then concatMapStringsSep " " (mapConfig key) attr else 81 - if (builtins.typeOf attr) == "bool" then "--${key}=${boolToString attr}" else 82 if (builtins.typeOf attr) == "string" then "--${key}='${attr}'" else 83 "--${key}=${toString attr}"); 84 85 - configString = concatStringsSep " " (mapAttrsToList mapConfig allConfig); 86 in 87 { 88 - options.services.oauth2_proxy = { 89 - enable = mkEnableOption "oauth2_proxy"; 90 91 - package = mkPackageOption pkgs "oauth2-proxy" { }; 92 93 ############################################## 94 # PROVIDER configuration 95 # Taken from: https://github.com/oauth2-proxy/oauth2-proxy/blob/master/providers/providers.go 96 - provider = mkOption { 97 - type = types.enum [ 98 "adfs" 99 "azure" 100 "bitbucket" ··· 116 ''; 117 }; 118 119 - approvalPrompt = mkOption { 120 - type = types.enum ["force" "auto"]; 121 default = "force"; 122 description = '' 123 OAuth approval_prompt. 124 ''; 125 }; 126 127 - clientID = mkOption { 128 - type = types.nullOr types.str; 129 description = '' 130 The OAuth Client ID. 131 ''; 132 example = "123456.apps.googleusercontent.com"; 133 }; 134 135 - oidcIssuerUrl = mkOption { 136 - type = types.nullOr types.str; 137 default = null; 138 description = '' 139 The OAuth issuer URL. ··· 141 example = "https://login.microsoftonline.com/{TENANT_ID}/v2.0"; 142 }; 143 144 - clientSecret = mkOption { 145 - type = types.nullOr types.str; 146 description = '' 147 The OAuth Client Secret. 148 ''; 149 }; 150 151 - skipAuthRegexes = mkOption { 152 - type = types.listOf types.str; 153 default = []; 154 description = '' 155 Skip authentication for requests matching any of these regular ··· 159 160 # XXX: Not clear whether these two options are mutually exclusive or not. 161 email = { 162 - domains = mkOption { 163 - type = types.listOf types.str; 164 default = []; 165 description = '' 166 Authenticate emails with the specified domains. Use ··· 168 ''; 169 }; 170 171 - addresses = mkOption { 172 - type = types.nullOr types.lines; 173 default = null; 174 description = '' 175 Line-separated email addresses that are allowed to authenticate. ··· 177 }; 178 }; 179 180 - loginURL = mkOption { 181 - type = types.nullOr types.str; 182 default = null; 183 description = '' 184 Authentication endpoint. ··· 190 example = "https://provider.example.com/oauth/authorize"; 191 }; 192 193 - redeemURL = mkOption { 194 - type = types.nullOr types.str; 195 default = null; 196 description = '' 197 Token redemption endpoint. ··· 203 example = "https://provider.example.com/oauth/token"; 204 }; 205 206 - validateURL = mkOption { 207 - type = types.nullOr types.str; 208 default = null; 209 description = '' 210 Access token validation endpoint. ··· 216 example = "https://provider.example.com/user/emails"; 217 }; 218 219 - redirectURL = mkOption { 220 # XXX: jml suspects this is always necessary, but the command-line 221 # doesn't require it so making it optional. 222 - type = types.nullOr types.str; 223 default = null; 224 description = '' 225 The OAuth2 redirect URL. ··· 228 }; 229 230 azure = { 231 - tenant = mkOption { 232 - type = types.str; 233 default = "common"; 234 description = '' 235 Go to a tenant-specific or common (tenant-independent) endpoint. 236 ''; 237 }; 238 239 - resource = mkOption { 240 - type = types.str; 241 description = '' 242 The resource that is protected. 243 ''; ··· 245 }; 246 247 google = { 248 - adminEmail = mkOption { 249 - type = types.str; 250 description = '' 251 The Google Admin to impersonate for API calls. 252 ··· 258 ''; 259 }; 260 261 - groups = mkOption { 262 - type = types.listOf types.str; 263 default = []; 264 description = '' 265 Restrict logins to members of these Google groups. 266 ''; 267 }; 268 269 - serviceAccountJSON = mkOption { 270 - type = types.path; 271 description = '' 272 The path to the service account JSON credentials. 273 ''; ··· 275 }; 276 277 github = { 278 - org = mkOption { 279 - type = types.nullOr types.str; 280 default = null; 281 description = '' 282 Restrict logins to members of this organisation. 283 ''; 284 }; 285 286 - team = mkOption { 287 - type = types.nullOr types.str; 288 default = null; 289 description = '' 290 Restrict logins to members of this team. ··· 295 296 #################################################### 297 # UPSTREAM Configuration 298 - upstream = mkOption { 299 - type = with types; coercedTo str (x: [x]) (listOf str); 300 default = []; 301 description = '' 302 The http url(s) of the upstream endpoint or `file://` ··· 304 ''; 305 }; 306 307 - passAccessToken = mkOption { 308 - type = types.bool; 309 default = false; 310 description = '' 311 Pass OAuth access_token to upstream via X-Forwarded-Access-Token header. 312 ''; 313 }; 314 315 - passBasicAuth = mkOption { 316 - type = types.bool; 317 default = true; 318 description = '' 319 Pass HTTP Basic Auth, X-Forwarded-User and X-Forwarded-Email information to upstream. 320 ''; 321 }; 322 323 - basicAuthPassword = mkOption { 324 - type = types.nullOr types.str; 325 default = null; 326 description = '' 327 The password to set when passing the HTTP Basic Auth header. 328 ''; 329 }; 330 331 - passHostHeader = mkOption { 332 - type = types.bool; 333 default = true; 334 description = '' 335 Pass the request Host Header to upstream. 336 ''; 337 }; 338 339 - signatureKey = mkOption { 340 - type = types.nullOr types.str; 341 default = null; 342 description = '' 343 GAP-Signature request signature key. ··· 346 }; 347 348 cookie = { 349 - domain = mkOption { 350 - type = types.nullOr types.str; 351 default = null; 352 description = '' 353 Optional cookie domains to force cookies to (ie: `.yourcompany.com`). ··· 357 example = ".yourcompany.com"; 358 }; 359 360 - expire = mkOption { 361 - type = types.str; 362 default = "168h0m0s"; 363 description = '' 364 Expire timeframe for cookie. 365 ''; 366 }; 367 368 - httpOnly = mkOption { 369 - type = types.bool; 370 default = true; 371 description = '' 372 Set HttpOnly cookie flag. 373 ''; 374 }; 375 376 - name = mkOption { 377 - type = types.str; 378 default = "_oauth2_proxy"; 379 description = '' 380 The name of the cookie that the oauth_proxy creates. 381 ''; 382 }; 383 384 - refresh = mkOption { 385 # XXX: Unclear what the behavior is when this is not specified. 386 - type = types.nullOr types.str; 387 default = null; 388 description = '' 389 Refresh the cookie after this duration; 0 to disable. ··· 391 example = "168h0m0s"; 392 }; 393 394 - secret = mkOption { 395 - type = types.nullOr types.str; 396 description = '' 397 The seed string for secure cookies. 398 ''; 399 }; 400 401 - secure = mkOption { 402 - type = types.bool; 403 default = true; 404 description = '' 405 Set secure (HTTPS) cookie flag. ··· 410 #################################################### 411 # OAUTH2 PROXY configuration 412 413 - httpAddress = mkOption { 414 - type = types.str; 415 default = "http://127.0.0.1:4180"; 416 description = '' 417 HTTPS listening address. This module does not expose the port by ··· 421 }; 422 423 htpasswd = { 424 - file = mkOption { 425 - type = types.nullOr types.path; 426 default = null; 427 description = '' 428 Additionally authenticate against a htpasswd file. Entries must be ··· 430 ''; 431 }; 432 433 - displayForm = mkOption { 434 - type = types.bool; 435 default = true; 436 description = '' 437 Display username / password login form if an htpasswd file is provided. ··· 439 }; 440 }; 441 442 - customTemplatesDir = mkOption { 443 - type = types.nullOr types.path; 444 default = null; 445 description = '' 446 Path to custom HTML templates. 447 ''; 448 }; 449 450 - reverseProxy = mkOption { 451 - type = types.bool; 452 default = false; 453 description = '' 454 In case when running behind a reverse proxy, controls whether headers ··· 458 ''; 459 }; 460 461 - proxyPrefix = mkOption { 462 - type = types.str; 463 default = "/oauth2"; 464 description = '' 465 The url root path that this proxy should be nested under. ··· 467 }; 468 469 tls = { 470 - enable = mkOption { 471 - type = types.bool; 472 default = false; 473 description = '' 474 Whether to serve over TLS. 475 ''; 476 }; 477 478 - certificate = mkOption { 479 - type = types.path; 480 description = '' 481 Path to certificate file. 482 ''; 483 }; 484 485 - key = mkOption { 486 - type = types.path; 487 description = '' 488 Path to private key file. 489 ''; 490 }; 491 492 - httpsAddress = mkOption { 493 - type = types.str; 494 default = ":443"; 495 description = '' 496 `addr:port` to listen on for HTTPS clients. ··· 502 }; 503 }; 504 505 - requestLogging = mkOption { 506 - type = types.bool; 507 default = true; 508 description = '' 509 Log requests to stdout. ··· 514 # UNKNOWN 515 516 # XXX: Is this mandatory? Is it part of another group? Is it part of the provider specification? 517 - scope = mkOption { 518 # XXX: jml suspects this is always necessary, but the command-line 519 # doesn't require it so making it optional. 520 - type = types.nullOr types.str; 521 default = null; 522 description = '' 523 OAuth scope specification. 524 ''; 525 }; 526 527 - profileURL = mkOption { 528 - type = types.nullOr types.str; 529 default = null; 530 description = '' 531 Profile access endpoint. 532 ''; 533 }; 534 535 - setXauthrequest = mkOption { 536 - type = types.nullOr types.bool; 537 default = false; 538 description = '' 539 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). 540 ''; 541 }; 542 543 - extraConfig = mkOption { 544 default = {}; 545 - type = types.attrsOf types.anything; 546 description = '' 547 Extra config to pass to oauth2-proxy. 548 ''; 549 }; 550 551 - keyFile = mkOption { 552 - type = types.nullOr types.path; 553 default = null; 554 description = '' 555 oauth2-proxy allows passing sensitive configuration via environment variables. ··· 557 OAUTH2_PROXY_CLIENT_SECRET=asdfasdfasdf.apps.googleuserscontent.com 558 and specify the path here. 559 ''; 560 - example = "/run/keys/oauth2_proxy"; 561 }; 562 - 563 }; 564 565 - config = mkIf cfg.enable { 566 567 - services.oauth2_proxy = mkIf (cfg.keyFile != null) { 568 - clientID = mkDefault null; 569 - clientSecret = mkDefault null; 570 - cookie.secret = mkDefault null; 571 }; 572 573 - users.users.oauth2_proxy = { 574 description = "OAuth2 Proxy"; 575 isSystemUser = true; 576 - group = "oauth2_proxy"; 577 }; 578 579 - users.groups.oauth2_proxy = {}; 580 581 - systemd.services.oauth2_proxy = { 582 description = "OAuth2 Proxy"; 583 path = [ cfg.package ]; 584 wantedBy = [ "multi-user.target" ]; ··· 586 after = [ "network-online.target" ]; 587 588 serviceConfig = { 589 - User = "oauth2_proxy"; 590 Restart = "always"; 591 ExecStart = "${cfg.package}/bin/oauth2-proxy ${configString}"; 592 - EnvironmentFile = mkIf (cfg.keyFile != null) cfg.keyFile; 593 }; 594 }; 595
··· 1 { config, lib, pkgs, ... }: 2 3 let 4 + cfg = config.services.oauth2-proxy; 5 6 + # oauth2-proxy provides many options that are only relevant if you are using 7 # a certain provider. This set maps from provider name to a function that 8 # takes the configuration and returns a string that can be inserted into the 9 + # command-line to launch oauth2-proxy. 10 providerSpecificOptions = { 11 azure = cfg: { 12 azure-tenant = cfg.azure.tenant; ··· 70 } // (getProviderOptions cfg cfg.provider) // cfg.extraConfig; 71 72 mapConfig = key: attr: 73 + lib.optionalString (attr != null && attr != []) ( 74 + if lib.isDerivation attr then mapConfig key (toString attr) else 75 + if (builtins.typeOf attr) == "set" then lib.concatStringsSep " " 76 + (lib.mapAttrsToList (name: value: mapConfig (key + "-" + name) value) attr) else 77 + if (builtins.typeOf attr) == "list" then lib.concatMapStringsSep " " (mapConfig key) attr else 78 + if (builtins.typeOf attr) == "bool" then "--${key}=${lib.boolToString attr}" else 79 if (builtins.typeOf attr) == "string" then "--${key}='${attr}'" else 80 "--${key}=${toString attr}"); 81 82 + configString = lib.concatStringsSep " " (lib.mapAttrsToList mapConfig allConfig); 83 in 84 { 85 + options.services.oauth2-proxy = { 86 + enable = lib.mkEnableOption "oauth2-proxy"; 87 88 + package = lib.mkPackageOption pkgs "oauth2-proxy" { }; 89 90 ############################################## 91 # PROVIDER configuration 92 # Taken from: https://github.com/oauth2-proxy/oauth2-proxy/blob/master/providers/providers.go 93 + provider = lib.mkOption { 94 + type = lib.types.enum [ 95 "adfs" 96 "azure" 97 "bitbucket" ··· 113 ''; 114 }; 115 116 + approvalPrompt = lib.mkOption { 117 + type = lib.types.enum ["force" "auto"]; 118 default = "force"; 119 description = '' 120 OAuth approval_prompt. 121 ''; 122 }; 123 124 + clientID = lib.mkOption { 125 + type = lib.types.nullOr lib.types.str; 126 description = '' 127 The OAuth Client ID. 128 ''; 129 example = "123456.apps.googleusercontent.com"; 130 }; 131 132 + oidcIssuerUrl = lib.mkOption { 133 + type = lib.types.nullOr lib.types.str; 134 default = null; 135 description = '' 136 The OAuth issuer URL. ··· 138 example = "https://login.microsoftonline.com/{TENANT_ID}/v2.0"; 139 }; 140 141 + clientSecret = lib.mkOption { 142 + type = lib.types.nullOr lib.types.str; 143 description = '' 144 The OAuth Client Secret. 145 ''; 146 }; 147 148 + skipAuthRegexes = lib.mkOption { 149 + type = lib.types.listOf lib.types.str; 150 default = []; 151 description = '' 152 Skip authentication for requests matching any of these regular ··· 156 157 # XXX: Not clear whether these two options are mutually exclusive or not. 158 email = { 159 + domains = lib.mkOption { 160 + type = lib.types.listOf lib.types.str; 161 default = []; 162 description = '' 163 Authenticate emails with the specified domains. Use ··· 165 ''; 166 }; 167 168 + addresses = lib.mkOption { 169 + type = lib.types.nullOr lib.types.lines; 170 default = null; 171 description = '' 172 Line-separated email addresses that are allowed to authenticate. ··· 174 }; 175 }; 176 177 + loginURL = lib.mkOption { 178 + type = lib.types.nullOr lib.types.str; 179 default = null; 180 description = '' 181 Authentication endpoint. ··· 187 example = "https://provider.example.com/oauth/authorize"; 188 }; 189 190 + redeemURL = lib.mkOption { 191 + type = lib.types.nullOr lib.types.str; 192 default = null; 193 description = '' 194 Token redemption endpoint. ··· 200 example = "https://provider.example.com/oauth/token"; 201 }; 202 203 + validateURL = lib.mkOption { 204 + type = lib.types.nullOr lib.types.str; 205 default = null; 206 description = '' 207 Access token validation endpoint. ··· 213 example = "https://provider.example.com/user/emails"; 214 }; 215 216 + redirectURL = lib.mkOption { 217 # XXX: jml suspects this is always necessary, but the command-line 218 # doesn't require it so making it optional. 219 + type = lib.types.nullOr lib.types.str; 220 default = null; 221 description = '' 222 The OAuth2 redirect URL. ··· 225 }; 226 227 azure = { 228 + tenant = lib.mkOption { 229 + type = lib.types.str; 230 default = "common"; 231 description = '' 232 Go to a tenant-specific or common (tenant-independent) endpoint. 233 ''; 234 }; 235 236 + resource = lib.mkOption { 237 + type = lib.types.str; 238 description = '' 239 The resource that is protected. 240 ''; ··· 242 }; 243 244 google = { 245 + adminEmail = lib.mkOption { 246 + type = lib.types.str; 247 description = '' 248 The Google Admin to impersonate for API calls. 249 ··· 255 ''; 256 }; 257 258 + groups = lib.mkOption { 259 + type = lib.types.listOf lib.types.str; 260 default = []; 261 description = '' 262 Restrict logins to members of these Google groups. 263 ''; 264 }; 265 266 + serviceAccountJSON = lib.mkOption { 267 + type = lib.types.path; 268 description = '' 269 The path to the service account JSON credentials. 270 ''; ··· 272 }; 273 274 github = { 275 + org = lib.mkOption { 276 + type = lib.types.nullOr lib.types.str; 277 default = null; 278 description = '' 279 Restrict logins to members of this organisation. 280 ''; 281 }; 282 283 + team = lib.mkOption { 284 + type = lib.types.nullOr lib.types.str; 285 default = null; 286 description = '' 287 Restrict logins to members of this team. ··· 292 293 #################################################### 294 # UPSTREAM Configuration 295 + upstream = lib.mkOption { 296 + type = with lib.types; coercedTo str (x: [x]) (listOf str); 297 default = []; 298 description = '' 299 The http url(s) of the upstream endpoint or `file://` ··· 301 ''; 302 }; 303 304 + passAccessToken = lib.mkOption { 305 + type = lib.types.bool; 306 default = false; 307 description = '' 308 Pass OAuth access_token to upstream via X-Forwarded-Access-Token header. 309 ''; 310 }; 311 312 + passBasicAuth = lib.mkOption { 313 + type = lib.types.bool; 314 default = true; 315 description = '' 316 Pass HTTP Basic Auth, X-Forwarded-User and X-Forwarded-Email information to upstream. 317 ''; 318 }; 319 320 + basicAuthPassword = lib.mkOption { 321 + type = lib.types.nullOr lib.types.str; 322 default = null; 323 description = '' 324 The password to set when passing the HTTP Basic Auth header. 325 ''; 326 }; 327 328 + passHostHeader = lib.mkOption { 329 + type = lib.types.bool; 330 default = true; 331 description = '' 332 Pass the request Host Header to upstream. 333 ''; 334 }; 335 336 + signatureKey = lib.mkOption { 337 + type = lib.types.nullOr lib.types.str; 338 default = null; 339 description = '' 340 GAP-Signature request signature key. ··· 343 }; 344 345 cookie = { 346 + domain = lib.mkOption { 347 + type = lib.types.nullOr lib.types.str; 348 default = null; 349 description = '' 350 Optional cookie domains to force cookies to (ie: `.yourcompany.com`). ··· 354 example = ".yourcompany.com"; 355 }; 356 357 + expire = lib.mkOption { 358 + type = lib.types.str; 359 default = "168h0m0s"; 360 description = '' 361 Expire timeframe for cookie. 362 ''; 363 }; 364 365 + httpOnly = lib.mkOption { 366 + type = lib.types.bool; 367 default = true; 368 description = '' 369 Set HttpOnly cookie flag. 370 ''; 371 }; 372 373 + name = lib.mkOption { 374 + type = lib.types.str; 375 default = "_oauth2_proxy"; 376 description = '' 377 The name of the cookie that the oauth_proxy creates. 378 ''; 379 }; 380 381 + refresh = lib.mkOption { 382 # XXX: Unclear what the behavior is when this is not specified. 383 + type = lib.types.nullOr lib.types.str; 384 default = null; 385 description = '' 386 Refresh the cookie after this duration; 0 to disable. ··· 388 example = "168h0m0s"; 389 }; 390 391 + secret = lib.mkOption { 392 + type = lib.types.nullOr lib.types.str; 393 description = '' 394 The seed string for secure cookies. 395 ''; 396 }; 397 398 + secure = lib.mkOption { 399 + type = lib.types.bool; 400 default = true; 401 description = '' 402 Set secure (HTTPS) cookie flag. ··· 407 #################################################### 408 # OAUTH2 PROXY configuration 409 410 + httpAddress = lib.mkOption { 411 + type = lib.types.str; 412 default = "http://127.0.0.1:4180"; 413 description = '' 414 HTTPS listening address. This module does not expose the port by ··· 418 }; 419 420 htpasswd = { 421 + file = lib.mkOption { 422 + type = lib.types.nullOr lib.types.path; 423 default = null; 424 description = '' 425 Additionally authenticate against a htpasswd file. Entries must be ··· 427 ''; 428 }; 429 430 + displayForm = lib.mkOption { 431 + type = lib.types.bool; 432 default = true; 433 description = '' 434 Display username / password login form if an htpasswd file is provided. ··· 436 }; 437 }; 438 439 + customTemplatesDir = lib.mkOption { 440 + type = lib.types.nullOr lib.types.path; 441 default = null; 442 description = '' 443 Path to custom HTML templates. 444 ''; 445 }; 446 447 + reverseProxy = lib.mkOption { 448 + type = lib.types.bool; 449 default = false; 450 description = '' 451 In case when running behind a reverse proxy, controls whether headers ··· 455 ''; 456 }; 457 458 + proxyPrefix = lib.mkOption { 459 + type = lib.types.str; 460 default = "/oauth2"; 461 description = '' 462 The url root path that this proxy should be nested under. ··· 464 }; 465 466 tls = { 467 + enable = lib.mkOption { 468 + type = lib.types.bool; 469 default = false; 470 description = '' 471 Whether to serve over TLS. 472 ''; 473 }; 474 475 + certificate = lib.mkOption { 476 + type = lib.types.path; 477 description = '' 478 Path to certificate file. 479 ''; 480 }; 481 482 + key = lib.mkOption { 483 + type = lib.types.path; 484 description = '' 485 Path to private key file. 486 ''; 487 }; 488 489 + httpsAddress = lib.mkOption { 490 + type = lib.types.str; 491 default = ":443"; 492 description = '' 493 `addr:port` to listen on for HTTPS clients. ··· 499 }; 500 }; 501 502 + requestLogging = lib.mkOption { 503 + type = lib.types.bool; 504 default = true; 505 description = '' 506 Log requests to stdout. ··· 511 # UNKNOWN 512 513 # XXX: Is this mandatory? Is it part of another group? Is it part of the provider specification? 514 + scope = lib.mkOption { 515 # XXX: jml suspects this is always necessary, but the command-line 516 # doesn't require it so making it optional. 517 + type = lib.types.nullOr lib.types.str; 518 default = null; 519 description = '' 520 OAuth scope specification. 521 ''; 522 }; 523 524 + profileURL = lib.mkOption { 525 + type = lib.types.nullOr lib.types.str; 526 default = null; 527 description = '' 528 Profile access endpoint. 529 ''; 530 }; 531 532 + setXauthrequest = lib.mkOption { 533 + type = lib.types.nullOr lib.types.bool; 534 default = false; 535 description = '' 536 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). 537 ''; 538 }; 539 540 + extraConfig = lib.mkOption { 541 default = {}; 542 + type = lib.types.attrsOf lib.types.anything; 543 description = '' 544 Extra config to pass to oauth2-proxy. 545 ''; 546 }; 547 548 + keyFile = lib.mkOption { 549 + type = lib.types.nullOr lib.types.path; 550 default = null; 551 description = '' 552 oauth2-proxy allows passing sensitive configuration via environment variables. ··· 554 OAUTH2_PROXY_CLIENT_SECRET=asdfasdfasdf.apps.googleuserscontent.com 555 and specify the path here. 556 ''; 557 + example = "/run/keys/oauth2-proxy"; 558 }; 559 }; 560 561 + imports = [ 562 + (lib.mkRenamedOptionModule [ "services" "oauth2_proxy" ] [ "services" "oauth2-proxy" ]) 563 + ]; 564 565 + config = lib.mkIf cfg.enable { 566 + services.oauth2-proxy = lib.mkIf (cfg.keyFile != null) { 567 + clientID = lib.mkDefault null; 568 + clientSecret = lib.mkDefault null; 569 + cookie.secret = lib.mkDefault null; 570 }; 571 572 + users.users.oauth2-proxy = { 573 description = "OAuth2 Proxy"; 574 isSystemUser = true; 575 + group = "oauth2-proxy"; 576 }; 577 578 + users.groups.oauth2-proxy = {}; 579 580 + systemd.services.oauth2-proxy = { 581 description = "OAuth2 Proxy"; 582 path = [ cfg.package ]; 583 wantedBy = [ "multi-user.target" ]; ··· 585 after = [ "network-online.target" ]; 586 587 serviceConfig = { 588 + User = "oauth2-proxy"; 589 Restart = "always"; 590 ExecStart = "${cfg.package}/bin/oauth2-proxy ${configString}"; 591 + EnvironmentFile = lib.mkIf (cfg.keyFile != null) cfg.keyFile; 592 }; 593 }; 594
+27 -28
nixos/modules/services/security/oauth2_proxy_nginx.nix nixos/modules/services/security/oauth2-proxy-nginx.nix
··· 1 { config, lib, ... }: 2 - with lib; 3 let 4 - cfg = config.services.oauth2_proxy.nginx; 5 in 6 { 7 - options.services.oauth2_proxy.nginx = { 8 - proxy = mkOption { 9 - type = types.str; 10 - default = config.services.oauth2_proxy.httpAddress; 11 - defaultText = literalExpression "config.services.oauth2_proxy.httpAddress"; 12 description = '' 13 - The address of the reverse proxy endpoint for oauth2_proxy 14 ''; 15 }; 16 17 - domain = mkOption { 18 - type = types.str; 19 description = '' 20 - The domain under which the oauth2_proxy will be accesible and the path of cookies are set to. 21 This setting must be set to ensure back-redirects are working properly 22 - if oauth2-proxy is configured with {option}`services.oauth2_proxy.cookie.domain` 23 - or multiple {option}`services.oauth2_proxy.nginx.virtualHosts` that are not on the same domain. 24 ''; 25 }; 26 27 - virtualHosts = mkOption { 28 type = let 29 - vhostSubmodule = types.submodule { 30 options = { 31 - allowed_groups = mkOption { 32 - type = types.nullOr (types.listOf 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 = mkOption { 37 - type = types.nullOr (types.listOf 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 = mkOption { 42 - type = types.nullOr (types.listOf 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 = types.listOf types.str; 49 convertFunc = x: 50 - lib.warn "services.oauth2_proxy.nginx.virtualHosts should be an attrset, found ${lib.generators.toPretty {} x}" 51 lib.genAttrs x (_: {}); 52 - newType = types.attrsOf vhostSubmodule; 53 - in types.coercedTo oldType convertFunc newType; 54 default = {}; 55 example = { 56 "protected.foo.com" = { ··· 65 }; 66 }; 67 68 - config.services.oauth2_proxy = mkIf (cfg.virtualHosts != [] && (hasPrefix "127.0.0.1:" cfg.proxy)) { 69 enable = true; 70 }; 71 72 - config.services.nginx = mkIf (cfg.virtualHosts != [] && config.services.oauth2_proxy.enable) (mkMerge ([ 73 { 74 virtualHosts.${cfg.domain}.locations."/oauth2/" = { 75 proxyPass = cfg.proxy; ··· 79 ''; 80 }; 81 } 82 - ] ++ optional (cfg.virtualHosts != []) { 83 recommendedProxySettings = true; # needed because duplicate headers 84 } ++ (lib.mapAttrsToList (vhost: conf: { 85 virtualHosts.${vhost} = {
··· 1 { config, lib, ... }: 2 let 3 + cfg = config.services.oauth2-proxy.nginx; 4 in 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" = { ··· 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; ··· 78 ''; 79 }; 80 } 81 + ] ++ lib.optional (cfg.virtualHosts != []) { 82 recommendedProxySettings = true; # needed because duplicate headers 83 } ++ (lib.mapAttrsToList (vhost: conf: { 84 virtualHosts.${vhost} = {