Merge pull request #273233 from SuperSandro2000/oauth2-proxy

nixos/oauth2-proxy{,-nginx}: renamed from oauth2_proxy, also renamed the servi…
This commit is contained in:
Sandro 2024-05-02 09:48:01 +02:00 committed by GitHub
commit bafcff9b15
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 155 additions and 155 deletions

View File

@ -398,6 +398,8 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m
- `services.zope2` has been removed as `zope2` is unmaintained and was relying on Python2.
- `services.oauth2_proxy` was renamed to `services.oauth2-proxy`. Also the corresponding service, user and group were renamed.
- `services.avahi.nssmdns` got split into `services.avahi.nssmdns4` and `services.avahi.nssmdns6` which enable the mDNS NSS switch for IPv4 and IPv6 respectively.
Since most mDNS responders only register IPv4 addresses, most users want to keep the IPv6 support disabled to avoid long timeouts.

View File

@ -1256,8 +1256,8 @@
./services/security/kanidm.nix
./services/security/munge.nix
./services/security/nginx-sso.nix
./services/security/oauth2_proxy.nix
./services/security/oauth2_proxy_nginx.nix
./services/security/oauth2-proxy.nix
./services/security/oauth2-proxy-nginx.nix
./services/security/opensnitch.nix
./services/security/pass-secret-service.nix
./services/security/physlock.nix

View File

@ -1,56 +1,55 @@
{ config, lib, ... }:
with lib;
let
cfg = config.services.oauth2_proxy.nginx;
cfg = config.services.oauth2-proxy.nginx;
in
{
options.services.oauth2_proxy.nginx = {
proxy = mkOption {
type = types.str;
default = config.services.oauth2_proxy.httpAddress;
defaultText = literalExpression "config.services.oauth2_proxy.httpAddress";
options.services.oauth2-proxy.nginx = {
proxy = lib.mkOption {
type = lib.types.str;
default = config.services.oauth2-proxy.httpAddress;
defaultText = lib.literalExpression "config.services.oauth2-proxy.httpAddress";
description = ''
The address of the reverse proxy endpoint for oauth2_proxy
The address of the reverse proxy endpoint for oauth2-proxy
'';
};
domain = mkOption {
type = types.str;
domain = lib.mkOption {
type = lib.types.str;
description = ''
The domain under which the oauth2_proxy will be accesible and the path of cookies are set to.
The domain under which the oauth2-proxy will be accesible and the path of cookies are set to.
This setting must be set to ensure back-redirects are working properly
if oauth2-proxy is configured with {option}`services.oauth2_proxy.cookie.domain`
or multiple {option}`services.oauth2_proxy.nginx.virtualHosts` that are not on the same domain.
if oauth2-proxy is configured with {option}`services.oauth2-proxy.cookie.domain`
or multiple {option}`services.oauth2-proxy.nginx.virtualHosts` that are not on the same domain.
'';
};
virtualHosts = mkOption {
virtualHosts = lib.mkOption {
type = let
vhostSubmodule = types.submodule {
vhostSubmodule = lib.types.submodule {
options = {
allowed_groups = mkOption {
type = types.nullOr (types.listOf types.str);
allowed_groups = lib.mkOption {
type = lib.types.nullOr (lib.types.listOf lib.types.str);
description = "List of groups to allow access to this vhost, or null to allow all.";
default = null;
};
allowed_emails = mkOption {
type = types.nullOr (types.listOf types.str);
allowed_emails = lib.mkOption {
type = lib.types.nullOr (lib.types.listOf lib.types.str);
description = "List of emails to allow access to this vhost, or null to allow all.";
default = null;
};
allowed_email_domains = mkOption {
type = types.nullOr (types.listOf types.str);
allowed_email_domains = lib.mkOption {
type = lib.types.nullOr (lib.types.listOf lib.types.str);
description = "List of email domains to allow access to this vhost, or null to allow all.";
default = null;
};
};
};
oldType = types.listOf types.str;
oldType = lib.types.listOf lib.types.str;
convertFunc = x:
lib.warn "services.oauth2_proxy.nginx.virtualHosts should be an attrset, found ${lib.generators.toPretty {} x}"
lib.warn "services.oauth2-proxy.nginx.virtualHosts should be an attrset, found ${lib.generators.toPretty {} x}"
lib.genAttrs x (_: {});
newType = types.attrsOf vhostSubmodule;
in types.coercedTo oldType convertFunc newType;
newType = lib.types.attrsOf vhostSubmodule;
in lib.types.coercedTo oldType convertFunc newType;
default = {};
example = {
"protected.foo.com" = {
@ -65,11 +64,11 @@ in
};
};
config.services.oauth2_proxy = mkIf (cfg.virtualHosts != [] && (hasPrefix "127.0.0.1:" cfg.proxy)) {
config.services.oauth2-proxy = lib.mkIf (cfg.virtualHosts != [] && (lib.hasPrefix "127.0.0.1:" cfg.proxy)) {
enable = true;
};
config.services.nginx = mkIf (cfg.virtualHosts != [] && config.services.oauth2_proxy.enable) (mkMerge ([
config.services.nginx = lib.mkIf (cfg.virtualHosts != [] && config.services.oauth2-proxy.enable) (lib.mkMerge ([
{
virtualHosts.${cfg.domain}.locations."/oauth2/" = {
proxyPass = cfg.proxy;
@ -79,7 +78,7 @@ in
'';
};
}
] ++ optional (cfg.virtualHosts != []) {
] ++ lib.optional (cfg.virtualHosts != []) {
recommendedProxySettings = true; # needed because duplicate headers
} ++ (lib.mapAttrsToList (vhost: conf: {
virtualHosts.${vhost} = {

View File

@ -1,15 +1,12 @@
# NixOS module for oauth2_proxy.
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.oauth2_proxy;
cfg = config.services.oauth2-proxy;
# oauth2_proxy provides many options that are only relevant if you are using
# 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.
# command-line to launch oauth2-proxy.
providerSpecificOptions = {
azure = cfg: {
azure-tenant = cfg.azure.tenant;
@ -73,28 +70,28 @@ let
} // (getProviderOptions cfg cfg.provider) // cfg.extraConfig;
mapConfig = key: attr:
optionalString (attr != null && attr != []) (
if isDerivation attr then mapConfig key (toString attr) else
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
lib.optionalString (attr != null && attr != []) (
if lib.isDerivation attr then mapConfig key (toString attr) else
if (builtins.typeOf attr) == "set" then lib.concatStringsSep " "
(lib.mapAttrsToList (name: value: mapConfig (key + "-" + name) value) attr) else
if (builtins.typeOf attr) == "list" then lib.concatMapStringsSep " " (mapConfig key) attr else
if (builtins.typeOf attr) == "bool" then "--${key}=${lib.boolToString attr}" else
if (builtins.typeOf attr) == "string" then "--${key}='${attr}'" else
"--${key}=${toString attr}");
configString = concatStringsSep " " (mapAttrsToList mapConfig allConfig);
configString = lib.concatStringsSep " " (lib.mapAttrsToList mapConfig allConfig);
in
{
options.services.oauth2_proxy = {
enable = mkEnableOption "oauth2_proxy";
options.services.oauth2-proxy = {
enable = lib.mkEnableOption "oauth2-proxy";
package = mkPackageOption pkgs "oauth2-proxy" { };
package = lib.mkPackageOption pkgs "oauth2-proxy" { };
##############################################
# PROVIDER configuration
# Taken from: https://github.com/oauth2-proxy/oauth2-proxy/blob/master/providers/providers.go
provider = mkOption {
type = types.enum [
provider = lib.mkOption {
type = lib.types.enum [
"adfs"
"azure"
"bitbucket"
@ -116,24 +113,24 @@ in
'';
};
approvalPrompt = mkOption {
type = types.enum ["force" "auto"];
approvalPrompt = lib.mkOption {
type = lib.types.enum ["force" "auto"];
default = "force";
description = ''
OAuth approval_prompt.
'';
};
clientID = mkOption {
type = types.nullOr types.str;
clientID = lib.mkOption {
type = lib.types.nullOr lib.types.str;
description = ''
The OAuth Client ID.
'';
example = "123456.apps.googleusercontent.com";
};
oidcIssuerUrl = mkOption {
type = types.nullOr types.str;
oidcIssuerUrl = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = ''
The OAuth issuer URL.
@ -141,15 +138,15 @@ in
example = "https://login.microsoftonline.com/{TENANT_ID}/v2.0";
};
clientSecret = mkOption {
type = types.nullOr types.str;
clientSecret = lib.mkOption {
type = lib.types.nullOr lib.types.str;
description = ''
The OAuth Client Secret.
'';
};
skipAuthRegexes = mkOption {
type = types.listOf types.str;
skipAuthRegexes = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [];
description = ''
Skip authentication for requests matching any of these regular
@ -159,8 +156,8 @@ in
# XXX: Not clear whether these two options are mutually exclusive or not.
email = {
domains = mkOption {
type = types.listOf types.str;
domains = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [];
description = ''
Authenticate emails with the specified domains. Use
@ -168,8 +165,8 @@ in
'';
};
addresses = mkOption {
type = types.nullOr types.lines;
addresses = lib.mkOption {
type = lib.types.nullOr lib.types.lines;
default = null;
description = ''
Line-separated email addresses that are allowed to authenticate.
@ -177,8 +174,8 @@ in
};
};
loginURL = mkOption {
type = types.nullOr types.str;
loginURL = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = ''
Authentication endpoint.
@ -190,8 +187,8 @@ in
example = "https://provider.example.com/oauth/authorize";
};
redeemURL = mkOption {
type = types.nullOr types.str;
redeemURL = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = ''
Token redemption endpoint.
@ -203,8 +200,8 @@ in
example = "https://provider.example.com/oauth/token";
};
validateURL = mkOption {
type = types.nullOr types.str;
validateURL = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = ''
Access token validation endpoint.
@ -216,10 +213,10 @@ in
example = "https://provider.example.com/user/emails";
};
redirectURL = mkOption {
redirectURL = lib.mkOption {
# XXX: jml suspects this is always necessary, but the command-line
# doesn't require it so making it optional.
type = types.nullOr types.str;
type = lib.types.nullOr lib.types.str;
default = null;
description = ''
The OAuth2 redirect URL.
@ -228,16 +225,16 @@ in
};
azure = {
tenant = mkOption {
type = types.str;
tenant = lib.mkOption {
type = lib.types.str;
default = "common";
description = ''
Go to a tenant-specific or common (tenant-independent) endpoint.
'';
};
resource = mkOption {
type = types.str;
resource = lib.mkOption {
type = lib.types.str;
description = ''
The resource that is protected.
'';
@ -245,8 +242,8 @@ in
};
google = {
adminEmail = mkOption {
type = types.str;
adminEmail = lib.mkOption {
type = lib.types.str;
description = ''
The Google Admin to impersonate for API calls.
@ -258,16 +255,16 @@ in
'';
};
groups = mkOption {
type = types.listOf types.str;
groups = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [];
description = ''
Restrict logins to members of these Google groups.
'';
};
serviceAccountJSON = mkOption {
type = types.path;
serviceAccountJSON = lib.mkOption {
type = lib.types.path;
description = ''
The path to the service account JSON credentials.
'';
@ -275,16 +272,16 @@ in
};
github = {
org = mkOption {
type = types.nullOr types.str;
org = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = ''
Restrict logins to members of this organisation.
'';
};
team = mkOption {
type = types.nullOr types.str;
team = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = ''
Restrict logins to members of this team.
@ -295,8 +292,8 @@ in
####################################################
# UPSTREAM Configuration
upstream = mkOption {
type = with types; coercedTo str (x: [x]) (listOf str);
upstream = lib.mkOption {
type = with lib.types; coercedTo str (x: [x]) (listOf str);
default = [];
description = ''
The http url(s) of the upstream endpoint or `file://`
@ -304,40 +301,40 @@ in
'';
};
passAccessToken = mkOption {
type = types.bool;
passAccessToken = lib.mkOption {
type = lib.types.bool;
default = false;
description = ''
Pass OAuth access_token to upstream via X-Forwarded-Access-Token header.
'';
};
passBasicAuth = mkOption {
type = types.bool;
passBasicAuth = lib.mkOption {
type = lib.types.bool;
default = true;
description = ''
Pass HTTP Basic Auth, X-Forwarded-User and X-Forwarded-Email information to upstream.
'';
};
basicAuthPassword = mkOption {
type = types.nullOr types.str;
basicAuthPassword = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = ''
The password to set when passing the HTTP Basic Auth header.
'';
};
passHostHeader = mkOption {
type = types.bool;
passHostHeader = lib.mkOption {
type = lib.types.bool;
default = true;
description = ''
Pass the request Host Header to upstream.
'';
};
signatureKey = mkOption {
type = types.nullOr types.str;
signatureKey = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = ''
GAP-Signature request signature key.
@ -346,8 +343,8 @@ in
};
cookie = {
domain = mkOption {
type = types.nullOr types.str;
domain = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = ''
Optional cookie domains to force cookies to (ie: `.yourcompany.com`).
@ -357,33 +354,33 @@ in
example = ".yourcompany.com";
};
expire = mkOption {
type = types.str;
expire = lib.mkOption {
type = lib.types.str;
default = "168h0m0s";
description = ''
Expire timeframe for cookie.
'';
};
httpOnly = mkOption {
type = types.bool;
httpOnly = lib.mkOption {
type = lib.types.bool;
default = true;
description = ''
Set HttpOnly cookie flag.
'';
};
name = mkOption {
type = types.str;
name = lib.mkOption {
type = lib.types.str;
default = "_oauth2_proxy";
description = ''
The name of the cookie that the oauth_proxy creates.
'';
};
refresh = mkOption {
refresh = lib.mkOption {
# XXX: Unclear what the behavior is when this is not specified.
type = types.nullOr types.str;
type = lib.types.nullOr lib.types.str;
default = null;
description = ''
Refresh the cookie after this duration; 0 to disable.
@ -391,15 +388,15 @@ in
example = "168h0m0s";
};
secret = mkOption {
type = types.nullOr types.str;
secret = lib.mkOption {
type = lib.types.nullOr lib.types.str;
description = ''
The seed string for secure cookies.
'';
};
secure = mkOption {
type = types.bool;
secure = lib.mkOption {
type = lib.types.bool;
default = true;
description = ''
Set secure (HTTPS) cookie flag.
@ -410,8 +407,8 @@ in
####################################################
# OAUTH2 PROXY configuration
httpAddress = mkOption {
type = types.str;
httpAddress = lib.mkOption {
type = lib.types.str;
default = "http://127.0.0.1:4180";
description = ''
HTTPS listening address. This module does not expose the port by
@ -421,8 +418,8 @@ in
};
htpasswd = {
file = mkOption {
type = types.nullOr types.path;
file = lib.mkOption {
type = lib.types.nullOr lib.types.path;
default = null;
description = ''
Additionally authenticate against a htpasswd file. Entries must be
@ -430,8 +427,8 @@ in
'';
};
displayForm = mkOption {
type = types.bool;
displayForm = lib.mkOption {
type = lib.types.bool;
default = true;
description = ''
Display username / password login form if an htpasswd file is provided.
@ -439,16 +436,16 @@ in
};
};
customTemplatesDir = mkOption {
type = types.nullOr types.path;
customTemplatesDir = lib.mkOption {
type = lib.types.nullOr lib.types.path;
default = null;
description = ''
Path to custom HTML templates.
'';
};
reverseProxy = mkOption {
type = types.bool;
reverseProxy = lib.mkOption {
type = lib.types.bool;
default = false;
description = ''
In case when running behind a reverse proxy, controls whether headers
@ -458,8 +455,8 @@ in
'';
};
proxyPrefix = mkOption {
type = types.str;
proxyPrefix = lib.mkOption {
type = lib.types.str;
default = "/oauth2";
description = ''
The url root path that this proxy should be nested under.
@ -467,30 +464,30 @@ in
};
tls = {
enable = mkOption {
type = types.bool;
enable = lib.mkOption {
type = lib.types.bool;
default = false;
description = ''
Whether to serve over TLS.
'';
};
certificate = mkOption {
type = types.path;
certificate = lib.mkOption {
type = lib.types.path;
description = ''
Path to certificate file.
'';
};
key = mkOption {
type = types.path;
key = lib.mkOption {
type = lib.types.path;
description = ''
Path to private key file.
'';
};
httpsAddress = mkOption {
type = types.str;
httpsAddress = lib.mkOption {
type = lib.types.str;
default = ":443";
description = ''
`addr:port` to listen on for HTTPS clients.
@ -502,8 +499,8 @@ in
};
};
requestLogging = mkOption {
type = types.bool;
requestLogging = lib.mkOption {
type = lib.types.bool;
default = true;
description = ''
Log requests to stdout.
@ -514,42 +511,42 @@ in
# UNKNOWN
# XXX: Is this mandatory? Is it part of another group? Is it part of the provider specification?
scope = mkOption {
scope = lib.mkOption {
# XXX: jml suspects this is always necessary, but the command-line
# doesn't require it so making it optional.
type = types.nullOr types.str;
type = lib.types.nullOr lib.types.str;
default = null;
description = ''
OAuth scope specification.
'';
};
profileURL = mkOption {
type = types.nullOr types.str;
profileURL = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = ''
Profile access endpoint.
'';
};
setXauthrequest = mkOption {
type = types.nullOr types.bool;
setXauthrequest = lib.mkOption {
type = lib.types.nullOr lib.types.bool;
default = false;
description = ''
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).
'';
};
extraConfig = mkOption {
extraConfig = lib.mkOption {
default = {};
type = types.attrsOf types.anything;
type = lib.types.attrsOf lib.types.anything;
description = ''
Extra config to pass to oauth2-proxy.
'';
};
keyFile = mkOption {
type = types.nullOr types.path;
keyFile = lib.mkOption {
type = lib.types.nullOr lib.types.path;
default = null;
description = ''
oauth2-proxy allows passing sensitive configuration via environment variables.
@ -557,28 +554,30 @@ in
OAUTH2_PROXY_CLIENT_SECRET=asdfasdfasdf.apps.googleuserscontent.com
and specify the path here.
'';
example = "/run/keys/oauth2_proxy";
example = "/run/keys/oauth2-proxy";
};
};
config = mkIf cfg.enable {
imports = [
(lib.mkRenamedOptionModule [ "services" "oauth2_proxy" ] [ "services" "oauth2-proxy" ])
];
services.oauth2_proxy = mkIf (cfg.keyFile != null) {
clientID = mkDefault null;
clientSecret = mkDefault null;
cookie.secret = mkDefault null;
config = lib.mkIf cfg.enable {
services.oauth2-proxy = lib.mkIf (cfg.keyFile != null) {
clientID = lib.mkDefault null;
clientSecret = lib.mkDefault null;
cookie.secret = lib.mkDefault null;
};
users.users.oauth2_proxy = {
users.users.oauth2-proxy = {
description = "OAuth2 Proxy";
isSystemUser = true;
group = "oauth2_proxy";
group = "oauth2-proxy";
};
users.groups.oauth2_proxy = {};
users.groups.oauth2-proxy = {};
systemd.services.oauth2_proxy = {
systemd.services.oauth2-proxy = {
description = "OAuth2 Proxy";
path = [ cfg.package ];
wantedBy = [ "multi-user.target" ];
@ -586,10 +585,10 @@ in
after = [ "network-online.target" ];
serviceConfig = {
User = "oauth2_proxy";
User = "oauth2-proxy";
Restart = "always";
ExecStart = "${cfg.package}/bin/oauth2-proxy ${configString}";
EnvironmentFile = mkIf (cfg.keyFile != null) cfg.keyFile;
EnvironmentFile = lib.mkIf (cfg.keyFile != null) cfg.keyFile;
};
};