mirror of
https://github.com/gensokyo-zone/infrastructure.git
synced 2026-02-09 12:29:19 -08:00
refactor(nginx): proxy options
This commit is contained in:
parent
c3f3fe1fed
commit
02508ecbd3
18 changed files with 638 additions and 424 deletions
|
|
@ -56,7 +56,7 @@
|
|||
set ${varPrefix}client 1;
|
||||
}
|
||||
'';
|
||||
localModule = {config, ...}: let
|
||||
localModule = {config, xvars, ...}: let
|
||||
cfg = config.local;
|
||||
in {
|
||||
options.local = with lib.types; {
|
||||
|
|
@ -100,7 +100,7 @@
|
|||
in mkMerge [
|
||||
(mkIf cfg.emitDenyGlobal (mkBefore allowDirectives))
|
||||
(mkIf cfg.emitVars (mkBefore (mkAddrVar "$remote_addr" "$local_")))
|
||||
(mkIf cfg.emitVars (mkBefore (mkAddrVar "$x_remote_addr" "$x_local_")))
|
||||
(mkIf (cfg.emitVars && config.xvars.enable) (mkBefore (mkAddrVar (xvars.remote_addr.get) "$x_local_")))
|
||||
];
|
||||
};
|
||||
};
|
||||
|
|
@ -130,13 +130,7 @@
|
|||
|
||||
options = with lib.types; {
|
||||
locations = mkOption {
|
||||
type = attrsOf (submoduleWith {
|
||||
modules = [locationModule];
|
||||
shorthandOnlyDefinesConfig = true;
|
||||
specialArgs = {
|
||||
virtualHost = config;
|
||||
};
|
||||
});
|
||||
type = attrsOf (submodule [locationModule]);
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -149,13 +143,7 @@
|
|||
in {
|
||||
options = with lib.types; {
|
||||
services.nginx.virtualHosts = mkOption {
|
||||
type = attrsOf (submoduleWith {
|
||||
modules = [hostModule];
|
||||
shorthandOnlyDefinesConfig = true;
|
||||
specialArgs = {
|
||||
nixosConfig = config;
|
||||
};
|
||||
});
|
||||
type = attrsOf (submodule [hostModule]);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,57 +1,27 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
inputs,
|
||||
...
|
||||
}: let
|
||||
inherit (inputs.self.lib.lib) mkAlmostAfter mkAlmostOptionDefault;
|
||||
inherit (lib.options) mkOption mkEnableOption;
|
||||
inherit (lib.modules) mkIf mkMerge mkBefore mkDefault mkOptionDefault;
|
||||
inherit (lib.strings) optionalString splitString match;
|
||||
inherit (lib.attrsets) attrValues;
|
||||
inherit (lib.lists) length head /*optional*/ any;
|
||||
inherit (lib.trivial) mapNullable;
|
||||
#inherit (config) networking;
|
||||
inherit (config.services) nginx;
|
||||
schemeForUrl = url: let
|
||||
parts = splitString ":" url;
|
||||
in if length parts == 1 then null else head parts;
|
||||
pathForUrl = url: let
|
||||
parts = match ''[^:]+://[^/]+(.*)'' url;
|
||||
in if parts == null then null else head parts;
|
||||
hostForUrl = url: let
|
||||
parts = match ''[^:]+://([^/]+).*'' url;
|
||||
in if parts == null then null else head parts;
|
||||
xHeadersDefaults = ''
|
||||
set $x_scheme $scheme;
|
||||
set $x_forwarded_for $remote_addr;
|
||||
set $x_remote_addr $remote_addr;
|
||||
set $x_forwarded_host $host;
|
||||
set $x_forwarded_server $host;
|
||||
set $x_host $host;
|
||||
set $x_referer $http_referer;
|
||||
set $x_proxy_host $x_host;
|
||||
'';
|
||||
xHeadersProxied = ''
|
||||
set $x_forwarded_for $proxy_add_x_forwarded_for;
|
||||
inherit (inputs.self.lib.lib) mkJustBefore mkAlmostOptionDefault orderJustBefore;
|
||||
inherit (lib.options) mkOption;
|
||||
inherit (lib.modules) mkIf mkMerge mkOrder mkDefault mkOptionDefault;
|
||||
xHeadersProxied = { xvars }: ''
|
||||
${xvars.init "forwarded_for" "$proxy_add_x_forwarded_for"}
|
||||
if ($http_x_forwarded_proto) {
|
||||
set $x_scheme $http_x_forwarded_proto;
|
||||
${xvars.init "scheme" "$http_x_forwarded_proto"}
|
||||
}
|
||||
if ($http_x_real_ip) {
|
||||
set $x_remote_addr $http_x_real_ip;
|
||||
${xvars.init "remote_addr" "$http_x_real_ip"}
|
||||
}
|
||||
if ($http_x_forwarded_host) {
|
||||
set $x_forwarded_host $http_x_forwarded_host;
|
||||
${xvars.init "host" "$http_x_forwarded_host"}
|
||||
}
|
||||
if ($http_x_forwarded_server) {
|
||||
set $x_forwarded_server $http_x_forwarded_server;
|
||||
}
|
||||
if ($x_referer ~ "^https?://([^/]*)/(.*)$") {
|
||||
set $x_referer_host $1;
|
||||
set $x_referer_path $2;
|
||||
${xvars.init "forwarded_server" "$http_x_forwarded_server"}
|
||||
}
|
||||
'';
|
||||
locationModule = { config, virtualHost, ... }: let
|
||||
locationModule = { config, virtualHost, xvars, ... }: let
|
||||
cfg = config.proxied;
|
||||
in {
|
||||
options = with lib.types; {
|
||||
|
|
@ -64,94 +34,30 @@
|
|||
type = bool;
|
||||
readOnly = true;
|
||||
};
|
||||
xvars.enable = mkEnableOption "$x_variables";
|
||||
redirectScheme = mkEnableOption "redirect to X-Forwarded-Proto" // {
|
||||
default = cfg.enabled;
|
||||
};
|
||||
rewriteReferer = mkEnableOption "rewrite Referer header" // {
|
||||
default = cfg.enabled;
|
||||
};
|
||||
};
|
||||
proxy = {
|
||||
enabled = mkOption {
|
||||
type = bool;
|
||||
readOnly = true;
|
||||
};
|
||||
scheme = mkOption {
|
||||
type = nullOr str;
|
||||
};
|
||||
path = mkOption {
|
||||
type = nullOr str;
|
||||
};
|
||||
host = mkOption {
|
||||
type = nullOr str;
|
||||
};
|
||||
headers.enableRecommended = mkOption {
|
||||
type = enum [ true false "nixpkgs" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
config = let
|
||||
emitVars = cfg.enabled && !virtualHost.proxied.enabled;
|
||||
emitRedirectScheme = config.proxy.enabled && cfg.redirectScheme;
|
||||
emitRefererRewrite = config.proxy.enabled && cfg.rewriteReferer;
|
||||
emitHeaders = config.proxy.enabled && config.proxy.headers.enableRecommended == true;
|
||||
in {
|
||||
proxied = {
|
||||
enabled = mkOptionDefault (virtualHost.proxied.enabled || cfg.enable != false);
|
||||
xvars.enable = mkIf (cfg.enabled || emitRedirectScheme || emitHeaders) true;
|
||||
};
|
||||
proxy = {
|
||||
enabled = mkOptionDefault (config.proxyPass != null);
|
||||
headers.enableRecommended = mkOptionDefault (
|
||||
if !virtualHost.recommendedProxySettings then false
|
||||
else if cfg.enabled then true
|
||||
else "nixpkgs"
|
||||
);
|
||||
scheme = mkOptionDefault (
|
||||
mapNullable schemeForUrl config.proxyPass
|
||||
);
|
||||
path = mkOptionDefault (
|
||||
mapNullable pathForUrl config.proxyPass
|
||||
);
|
||||
host = mkOptionDefault (
|
||||
mapNullable hostForUrl config.proxyPass
|
||||
);
|
||||
headers = {
|
||||
enableRecommended = mkIf cfg.enabled (mkAlmostOptionDefault true);
|
||||
rewriteReferer.enable = mkIf cfg.enabled (mkAlmostOptionDefault true);
|
||||
};
|
||||
redirect.enable = mkIf cfg.enabled (mkAlmostOptionDefault true);
|
||||
};
|
||||
recommendedProxySettings = mkMerge [
|
||||
(mkAlmostOptionDefault (config.proxy.headers.enableRecommended == "nixpkgs"))
|
||||
];
|
||||
xvars.enable = mkIf cfg.enabled true;
|
||||
extraConfig = mkMerge [
|
||||
(mkIf emitVars (
|
||||
mkBefore xHeadersProxied
|
||||
mkJustBefore (xHeadersProxied { inherit xvars; })
|
||||
))
|
||||
(mkIf emitRedirectScheme ''
|
||||
proxy_redirect ${config.proxy.scheme}://$host/ $x_scheme://$host/;
|
||||
'')
|
||||
(mkIf emitRefererRewrite ''
|
||||
if ($x_referer_host = $host) {
|
||||
set $x_referer "${config.proxy.scheme}://${config.proxy.host}/$x_referer_path";
|
||||
}
|
||||
'')
|
||||
(mkIf emitHeaders (mkAlmostAfter ''
|
||||
if ($x_proxy_host = "") {
|
||||
set $x_proxy_host $proxy_host;
|
||||
}
|
||||
if ($x_proxy_host = "") {
|
||||
set $x_proxy_host ${config.proxy.host};
|
||||
}
|
||||
proxy_set_header Host $x_proxy_host;
|
||||
proxy_set_header Referer $x_referer;
|
||||
proxy_set_header X-Real-IP $x_remote_addr;
|
||||
proxy_set_header X-Forwarded-For $x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $x_scheme;
|
||||
proxy_set_header X-Forwarded-Host $x_forwarded_host;
|
||||
proxy_set_header X-Forwarded-Server $x_forwarded_server;
|
||||
''))
|
||||
];
|
||||
};
|
||||
};
|
||||
hostModule = { config, ... }: let
|
||||
hostModule = { config, xvars, ... }: let
|
||||
cfg = config.proxied;
|
||||
in {
|
||||
options = with lib.types; {
|
||||
|
|
@ -164,13 +70,6 @@
|
|||
type = bool;
|
||||
default = cfg.enable != false;
|
||||
};
|
||||
xvars.enable = mkEnableOption "$x_variables" // {
|
||||
default = cfg.enabled;
|
||||
};
|
||||
};
|
||||
recommendedProxySettings = mkOption {
|
||||
type = bool;
|
||||
default = nginx.recommendedProxySettings;
|
||||
};
|
||||
locations = mkOption {
|
||||
type = attrsOf (submoduleWith {
|
||||
|
|
@ -181,23 +80,17 @@
|
|||
};
|
||||
|
||||
config = {
|
||||
proxied = {
|
||||
xvars.enable = mkIf (any (loc: loc.proxied.xvars.enable) (attrValues config.locations)) true;
|
||||
};
|
||||
xvars.enable = mkIf cfg.enabled true;
|
||||
local.denyGlobal = mkIf (cfg.enable == "cloudflared") (mkDefault true);
|
||||
extraConfig = mkIf cfg.xvars.enable (mkBefore ''
|
||||
${xHeadersDefaults}
|
||||
${optionalString cfg.enabled xHeadersProxied}
|
||||
'');
|
||||
extraConfig = mkIf (cfg.enabled && config.xvars.enable) (
|
||||
mkOrder (orderJustBefore + 25) (xHeadersProxied { inherit xvars; })
|
||||
);
|
||||
};
|
||||
};
|
||||
in {
|
||||
options = with lib.types; {
|
||||
services.nginx.virtualHosts = mkOption {
|
||||
type = attrsOf (submoduleWith {
|
||||
modules = [ hostModule ];
|
||||
shorthandOnlyDefinesConfig = true;
|
||||
});
|
||||
type = attrsOf (submodule [hostModule]);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
|||
214
modules/nixos/nginx/proxy.nix
Normal file
214
modules/nixos/nginx/proxy.nix
Normal file
|
|
@ -0,0 +1,214 @@
|
|||
let
|
||||
locationModule = { config, name, virtualHost, xvars, gensokyo-zone, lib, ... }: let
|
||||
inherit (gensokyo-zone.lib) mkJustBefore mkJustAfter mkAlmostOptionDefault mapOptionDefaults coalesce parseUrl;
|
||||
inherit (lib.options) mkOption mkEnableOption;
|
||||
inherit (lib.modules) mkIf mkMerge mkBefore mkOptionDefault;
|
||||
inherit (lib.attrsets) filterAttrs mapAttrsToList;
|
||||
inherit (lib.strings) hasPrefix removeSuffix concatStringsSep;
|
||||
inherit (lib.trivial) mapNullable;
|
||||
cfg = config.proxy;
|
||||
in {
|
||||
options = with lib.types; {
|
||||
proxy = {
|
||||
enable = mkEnableOption "proxy";
|
||||
enabled = mkOption {
|
||||
type = bool;
|
||||
readOnly = true;
|
||||
};
|
||||
url = mkOption {
|
||||
type = str;
|
||||
};
|
||||
path = mkOption {
|
||||
type = str;
|
||||
};
|
||||
host = mkOption {
|
||||
type = nullOr str;
|
||||
};
|
||||
websocket.enable = mkEnableOption "websocket proxy" // {
|
||||
default = virtualHost.proxy.websocket.enable;
|
||||
};
|
||||
parsed = {
|
||||
scheme = mkOption {
|
||||
type = nullOr str;
|
||||
};
|
||||
path = mkOption {
|
||||
type = nullOr str;
|
||||
};
|
||||
host = mkOption {
|
||||
type = nullOr str;
|
||||
};
|
||||
hostport = mkOption {
|
||||
type = nullOr str;
|
||||
};
|
||||
port = mkOption {
|
||||
type = nullOr int;
|
||||
};
|
||||
};
|
||||
headers = {
|
||||
enableRecommended = mkOption {
|
||||
type = enum [ true false "nixpkgs" ];
|
||||
};
|
||||
rewriteReferer.enable = mkEnableOption "rewrite referer host";
|
||||
set = mkOption {
|
||||
type = attrsOf (nullOr str);
|
||||
};
|
||||
};
|
||||
redirect = {
|
||||
enable = mkEnableOption "proxy_redirect";
|
||||
fromHost = mkOption {
|
||||
type = str;
|
||||
default = xvars.get.host;
|
||||
example = "xvars.get.proxy_host";
|
||||
};
|
||||
fromScheme = mkOption {
|
||||
type = str;
|
||||
default = xvars.get.scheme;
|
||||
example = "xvars.get.proxy_scheme";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
config = let
|
||||
emitHeaders = setHeaders' != { };
|
||||
url = parseUrl config.proxyPass;
|
||||
recommendedHeaders = {
|
||||
Host = if cfg.host == null then xvars.get.proxy_host else cfg.host;
|
||||
Referer = xvars.get.referer;
|
||||
X-Real-IP = xvars.get.remote_addr;
|
||||
X-Forwarded-For = xvars.get.forwarded_for;
|
||||
X-Forwarded-Proto = xvars.get.scheme;
|
||||
X-Forwarded-Host = xvars.get.host;
|
||||
X-Forwarded-Server = xvars.get.forwarded_server;
|
||||
};
|
||||
initProxyVars = ''
|
||||
${xvars.init "proxy_scheme" cfg.parsed.scheme}
|
||||
${xvars.init "proxy_host" "$proxy_host"}
|
||||
if (${xvars.get.proxy_host} = "") {
|
||||
${xvars.init "proxy_host" cfg.parsed.hostport}
|
||||
}
|
||||
'';
|
||||
hostHeader = coalesce [
|
||||
cfg.headers.set.Host or null
|
||||
cfg.host
|
||||
xvars.get.proxy_host
|
||||
];
|
||||
rewriteReferer = ''
|
||||
set $x_set_referer ${xvars.get.referer};
|
||||
if (${xvars.get.referer_host} = $host) {
|
||||
set $x_set_referer ${config.proxy.parsed.scheme}://${hostHeader}${xvars.get.referer_path};
|
||||
}
|
||||
'';
|
||||
redirect = ''
|
||||
proxy_redirect ${cfg.redirect.fromScheme}://${cfg.redirect.fromHost}/ ${xvars.get.scheme}://${xvars.get.host}/;
|
||||
'';
|
||||
setHeaders' = filterAttrs (_: header: header != null) cfg.headers.set;
|
||||
setHeaders = concatStringsSep "\n" (mapAttrsToList (
|
||||
name: value: "proxy_set_header ${name} ${xvars.escapeString value};"
|
||||
) setHeaders');
|
||||
in {
|
||||
proxy = {
|
||||
enabled = mkOptionDefault (config.proxyPass != null);
|
||||
path = mkIf (hasPrefix "/" name) (mkOptionDefault name);
|
||||
url = mkIf (virtualHost.proxy.url != null) (mkOptionDefault virtualHost.proxy.url);
|
||||
headers = {
|
||||
enableRecommended = mkOptionDefault (
|
||||
if cfg.enable && virtualHost.proxy.headers.enableRecommended != false then true
|
||||
else virtualHost.proxy.headers.enableRecommended
|
||||
);
|
||||
set = mkMerge [
|
||||
(mkOptionDefault { })
|
||||
(mkIf (cfg.headers.enableRecommended == true) (mapOptionDefaults recommendedHeaders))
|
||||
(mkIf (cfg.host != null) {
|
||||
Host = mkIf (cfg.headers.enableRecommended != "nixpkgs") (mkAlmostOptionDefault cfg.host);
|
||||
})
|
||||
(mkIf cfg.headers.rewriteReferer.enable {
|
||||
Referer = mkAlmostOptionDefault "$x_set_referer";
|
||||
})
|
||||
(mkIf cfg.websocket.enable (mapOptionDefaults {
|
||||
Upgrade = "$http_upgrade";
|
||||
Connection = "upgrade";
|
||||
}))
|
||||
];
|
||||
};
|
||||
host = mkOptionDefault (
|
||||
if virtualHost.proxy.host != null then virtualHost.proxy.host
|
||||
else if cfg.headers.enableRecommended == false then null
|
||||
else xvars.get.host
|
||||
);
|
||||
parsed = {
|
||||
scheme = mkOptionDefault (
|
||||
mapNullable (_: url.scheme) config.proxyPass
|
||||
);
|
||||
path = mkOptionDefault (
|
||||
mapNullable (_: url.path) config.proxyPass
|
||||
);
|
||||
host = mkOptionDefault (
|
||||
mapNullable (_: url.host) config.proxyPass
|
||||
);
|
||||
hostport = mkOptionDefault (
|
||||
mapNullable (_: url.hostport) config.proxyPass
|
||||
);
|
||||
port = mkOptionDefault (
|
||||
mapNullable (_: url.port) config.proxyPass
|
||||
);
|
||||
};
|
||||
};
|
||||
proxyPass = mkIf cfg.enable (mkAlmostOptionDefault (removeSuffix "/" cfg.url + cfg.path));
|
||||
recommendedProxySettings = mkAlmostOptionDefault (cfg.headers.enableRecommended == "nixpkgs");
|
||||
extraConfig = mkMerge [
|
||||
(mkIf (cfg.enabled && virtualHost.xvars.enable) (mkJustBefore initProxyVars))
|
||||
(mkIf (cfg.enabled && cfg.headers.rewriteReferer.enable) (mkJustBefore rewriteReferer))
|
||||
(mkIf (cfg.enabled && cfg.redirect.enable) (mkBefore redirect))
|
||||
(mkIf (cfg.enabled && emitHeaders) (mkJustAfter setHeaders))
|
||||
];
|
||||
};
|
||||
};
|
||||
hostModule = { config, nixosConfig, lib, ... }: let
|
||||
inherit (lib.options) mkOption mkEnableOption;
|
||||
inherit (lib.modules) mkIf;
|
||||
inherit (lib.attrsets) attrValues;
|
||||
inherit (lib.lists) any;
|
||||
inherit (nixosConfig.services) nginx;
|
||||
cfg = config.proxy;
|
||||
in {
|
||||
options = with lib.types; {
|
||||
proxy = {
|
||||
host = mkOption {
|
||||
type = nullOr str;
|
||||
default = null;
|
||||
};
|
||||
url = mkOption {
|
||||
type = nullOr str;
|
||||
default = null;
|
||||
};
|
||||
websocket.enable = mkEnableOption "websocket proxy";
|
||||
headers.enableRecommended = mkOption {
|
||||
type = enum [ true false "nixpkgs" ];
|
||||
default = if nginx.recommendedProxySettings then "nixpkgs" else false;
|
||||
};
|
||||
};
|
||||
locations = mkOption {
|
||||
type = attrsOf (submoduleWith {
|
||||
modules = [ locationModule ];
|
||||
shorthandOnlyDefinesConfig = true;
|
||||
});
|
||||
};
|
||||
};
|
||||
config = let
|
||||
needsReferer = loc: loc.proxy.enabled && loc.proxy.headers.rewriteReferer.enable;
|
||||
in {
|
||||
xvars.parseReferer = mkIf (any needsReferer (attrValues config.locations)) true;
|
||||
};
|
||||
};
|
||||
in {
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (lib.options) mkOption;
|
||||
in {
|
||||
options = with lib.types; {
|
||||
services.nginx.virtualHosts = mkOption {
|
||||
type = attrsOf (submodule [hostModule]);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
@ -10,9 +10,11 @@
|
|||
inherit (lib.attrsets) mapAttrsToList;
|
||||
inherit (lib.trivial) warnIf;
|
||||
inherit (config.services) nginx;
|
||||
forceRedirectConfig = virtualHost: ''
|
||||
if ($x_scheme = http) {
|
||||
return ${toString virtualHost.redirectCode} https://$x_forwarded_host$request_uri;
|
||||
forceRedirectConfig = virtualHost: let
|
||||
xvars = virtualHost.xvars.lib;
|
||||
in ''
|
||||
if (${xvars.get.scheme} = http) {
|
||||
return ${toString virtualHost.redirectCode} https://${xvars.get.host}$request_uri;
|
||||
}
|
||||
'';
|
||||
locationModule = { config, virtualHost, ... }: let
|
||||
|
|
@ -23,7 +25,7 @@
|
|||
force = mkEnableOption "redirect to SSL";
|
||||
};
|
||||
config = {
|
||||
proxied.xvars.enable = mkIf emitForce true;
|
||||
xvars.enable = mkIf emitForce true;
|
||||
extraConfig = mkIf emitForce (forceRedirectConfig virtualHost);
|
||||
};
|
||||
};
|
||||
|
|
@ -119,7 +121,7 @@
|
|||
sslCertificate = mkIf (cfg.cert.path != null) (mkAlmostOptionDefault cfg.cert.path);
|
||||
sslCertificateKey = mkIf (cfg.cert.keyPath != null) (mkAlmostOptionDefault cfg.cert.keyPath);
|
||||
|
||||
proxied.xvars.enable = mkIf emitForce true;
|
||||
xvars.enable = mkIf emitForce true;
|
||||
extraConfig = mkIf emitForce (forceRedirectConfig config);
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
inherit (lib.options) mkOption mkEnableOption;
|
||||
inherit (lib.modules) mkIf mkMerge mkBefore mkAfter mkOptionDefault;
|
||||
inherit (lib.attrsets) mapAttrsToList;
|
||||
inherit (lib.strings) toLower replaceStrings;
|
||||
inherit (lib.strings) toLower replaceStrings removePrefix;
|
||||
inherit (config) networking;
|
||||
inherit (config.services) vouch-proxy nginx tailscale;
|
||||
inherit (nginx) vouch;
|
||||
locationModule = {config, virtualHost, ...}: {
|
||||
locationModule = {config, virtualHost, xvars, ...}: {
|
||||
options.vouch = with lib.types; {
|
||||
requireAuth = mkEnableOption "require auth to access this location";
|
||||
setProxyHeader = mkOption {
|
||||
|
|
@ -33,20 +33,19 @@
|
|||
(mkBefore virtualHost.vouch.auth.lua.accessLogic)
|
||||
];
|
||||
};
|
||||
proxied.xvars.enable = mkIf (enableVouchTail || virtualHost.vouch.auth.lua.enable) true;
|
||||
xvars.enable = mkIf (enableVouchTail || virtualHost.vouch.auth.lua.enable) true;
|
||||
proxy.headers.set.X-Vouch-User = mkOptionDefault "$auth_resp_x_vouch_user";
|
||||
extraConfig = assert virtualHost.vouch.enable; mkMerge [
|
||||
(mkIf (!virtualHost.vouch.requireAuth) virtualHost.vouch.auth.requestDirective)
|
||||
(allowOrigin vouch.url)
|
||||
(allowOrigin vouch.authUrl)
|
||||
(mkIf enableVouchLocal (allowOrigin vouch.localUrl))
|
||||
(mkIf enableVouchTail (allowOrigin "$x_scheme://${vouch.tailDomain}"))
|
||||
(mkIf config.vouch.setProxyHeader ''
|
||||
proxy_set_header X-Vouch-User $auth_resp_x_vouch_user;
|
||||
'')
|
||||
(mkIf enableVouchLocal (allowOrigin "sso.local.${networking.domain}"))
|
||||
(mkIf enableVouchTail (allowOrigin "${xvars.get.scheme}://${vouch.tailDomain}"))
|
||||
];
|
||||
};
|
||||
};
|
||||
hostModule = {config, ...}: let
|
||||
hostModule = {config, xvars, ...}: let
|
||||
cfg = config.vouch;
|
||||
mkHeaderVar = header: toLower (replaceStrings [ "-" ] [ "_" ] header);
|
||||
mkUpstreamVar = header: "\$upstream_http_${mkHeaderVar header}";
|
||||
|
|
@ -113,7 +112,7 @@
|
|||
if ngx.ctx.auth_res ~= nil and ngx.ctx.auth_res.status == ngx.HTTP_UNAUTHORIZED then
|
||||
local vouch_url = ngx.var["vouch_url"] or "${vouch.url}"
|
||||
local query_args = ngx.encode_args {
|
||||
url = string.format("%s://%s%s", ngx.var.x_scheme, ngx.var.x_forwarded_host, ngx.var.request_uri),
|
||||
url = string.format("%s://%s%s", ngx.var.${removePrefix "$" xvars.get.scheme}, ngx.var.${removePrefix "$" xvars.get.host}, ngx.var.request_uri),
|
||||
["X-Vouch-Token"] = ngx.ctx.auth_res.header["X-Vouch-Token"] or "",
|
||||
error = ngx.ctx.auth_res.header["X-Vouch-Error"] or "",
|
||||
-- ["vouch-failcount"] is now a session variable and shouldn't be needed anymore
|
||||
|
|
@ -145,13 +144,13 @@
|
|||
};
|
||||
extraConfig = let
|
||||
localVouchUrl = ''
|
||||
if ($x_forwarded_host ~ "\.local\.${networking.domain}$") {
|
||||
if (${xvars.get.host} ~ "\.local\.${networking.domain}$") {
|
||||
set $vouch_url ${vouch.localUrl};
|
||||
}
|
||||
'';
|
||||
tailVouchUrl = ''
|
||||
if ($x_forwarded_host ~ "\.tail\.${networking.domain}$") {
|
||||
set $vouch_url $x_scheme://${vouch.tailDomain};
|
||||
if (${xvars.get.host} ~ "\.tail\.${networking.domain}$") {
|
||||
set $vouch_url ${xvars.get.scheme}://${vouch.tailDomain};
|
||||
}
|
||||
'';
|
||||
setVouchUrl = [
|
||||
|
|
@ -170,33 +169,32 @@
|
|||
mkBefore "auth_request_set \$${authVar} ${mkUpstreamVar header};"
|
||||
)) cfg.auth.variables
|
||||
));
|
||||
proxied.xvars.enable = mkIf cfg.enable true;
|
||||
xvars.enable = mkIf cfg.enable true;
|
||||
locations = mkIf cfg.enable {
|
||||
"/" = mkIf cfg.requireAuth {
|
||||
vouch.requireAuth = mkAlmostOptionDefault true;
|
||||
};
|
||||
${cfg.auth.errorLocation} = mkIf (cfg.auth.errorLocation != null) {
|
||||
proxied.xvars.enable = true;
|
||||
xvars.enable = true;
|
||||
extraConfig = ''
|
||||
return 302 $vouch_url/login?url=$x_scheme://$x_forwarded_host$request_uri&X-Vouch-Token=$auth_resp_jwt&error=$auth_resp_err;
|
||||
return 302 $vouch_url/login?url=${xvars.get.scheme}://${xvars.get.host}$request_uri&X-Vouch-Token=$auth_resp_jwt&error=$auth_resp_err;
|
||||
'';
|
||||
};
|
||||
${cfg.auth.requestLocation} = { config, ... }: {
|
||||
proxyPass = "${vouch.proxyOrigin}/validate";
|
||||
proxy.headers.enableRecommended = false;
|
||||
proxied.rewriteReferer = false;
|
||||
extraConfig = let
|
||||
${cfg.auth.requestLocation} = { config, xvars, ... }: {
|
||||
proxy = {
|
||||
enable = true;
|
||||
url = vouch.proxyOrigin;
|
||||
# nginx-proxied vouch must use X-Forwarded-Host, but vanilla vouch requires Host
|
||||
vouchProxyHost = if vouch.doubleProxy.enable
|
||||
host = if vouch.doubleProxy.enable
|
||||
then (if cfg.localSso.enable then vouch.doubleProxy.localServerName else vouch.doubleProxy.serverName)
|
||||
else "$x_forwarded_host";
|
||||
in ''
|
||||
proxy_set_header Host ${vouchProxyHost};
|
||||
proxy_set_header X-Forwarded-Host $x_forwarded_host;
|
||||
proxy_set_header Referer $x_referer;
|
||||
proxy_set_header X-Forwarded-Proto $x_scheme;
|
||||
else xvars.get.host;
|
||||
headers = {
|
||||
set.Content-Length = "";
|
||||
rewriteReferer.enable = false;
|
||||
};
|
||||
};
|
||||
extraConfig = ''
|
||||
proxy_pass_request_body off;
|
||||
proxy_set_header Content-Length "";
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,30 +0,0 @@
|
|||
{lib, ...}: let
|
||||
inherit (lib.modules) mkIf;
|
||||
inherit (lib.options) mkOption mkEnableOption;
|
||||
wsModule = {config, ...}: {
|
||||
options = with lib.types; {
|
||||
proxy.websocket.enable = mkEnableOption "websocket proxy";
|
||||
};
|
||||
config = mkIf config.proxy.websocket.enable {
|
||||
extraConfig = ''
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
'';
|
||||
};
|
||||
};
|
||||
hostModule = {config, ...}: {
|
||||
imports = [wsModule];
|
||||
|
||||
options = with lib.types; {
|
||||
locations = mkOption {
|
||||
type = attrsOf (submodule wsModule);
|
||||
};
|
||||
};
|
||||
};
|
||||
in {
|
||||
options = with lib.types; {
|
||||
services.nginx.virtualHosts = mkOption {
|
||||
type = attrsOf (submodule hostModule);
|
||||
};
|
||||
};
|
||||
}
|
||||
110
modules/nixos/nginx/xvars.nix
Normal file
110
modules/nixos/nginx/xvars.nix
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
let
|
||||
locationModule = { config, virtualHost, lib, ... }: let
|
||||
inherit (lib.options) mkEnableOption;
|
||||
cfg = config.xvars;
|
||||
in {
|
||||
options.xvars = with lib.types; {
|
||||
enable = mkEnableOption "$x_variables";
|
||||
};
|
||||
config = let
|
||||
in {
|
||||
};
|
||||
};
|
||||
hostModule = { config, nixosConfig, gensokyo-zone, xvars, lib, ... }: let
|
||||
inherit (gensokyo-zone.lib) mkJustBefore;
|
||||
inherit (lib.options) mkOption mkEnableOption;
|
||||
inherit (lib.modules) mkIf mkMerge mkOptionDefault;
|
||||
inherit (lib.strings) concatStringsSep;
|
||||
inherit (lib.attrsets) attrValues filterAttrs mapAttrs mapAttrsToList;
|
||||
inherit (lib.lists) any;
|
||||
cfg = config.xvars;
|
||||
escapeString = value: if value == "" then ''""'' else value;
|
||||
in {
|
||||
options = with lib.types; {
|
||||
xvars = {
|
||||
enable = mkEnableOption "$x_variables";
|
||||
parseReferer = mkEnableOption "$x_referer_{scheme,host,path}";
|
||||
defaults = mkOption {
|
||||
type = attrsOf (nullOr str);
|
||||
default = rec {
|
||||
scheme = "$scheme";
|
||||
forwarded_for = remote_addr;
|
||||
remote_addr = "$remote_addr";
|
||||
forwarded_server = host;
|
||||
host = "$host";
|
||||
referer = "$http_referer";
|
||||
proxy_host = null;
|
||||
proxy_scheme = null;
|
||||
};
|
||||
};
|
||||
lib = mkOption {
|
||||
type = attrs;
|
||||
};
|
||||
};
|
||||
locations = mkOption {
|
||||
type = attrsOf (submoduleWith {
|
||||
modules = [ locationModule ];
|
||||
shorthandOnlyDefinesConfig = true;
|
||||
specialArgs = {
|
||||
inherit nixosConfig gensokyo-zone xvars;
|
||||
virtualHost = config;
|
||||
};
|
||||
});
|
||||
};
|
||||
};
|
||||
config = let
|
||||
defaults = concatStringsSep "\n" (mapAttrsToList (
|
||||
name: value: "set $x_${name} ${escapeString value};"
|
||||
) (filterAttrs (_: value: value != null) cfg.defaults));
|
||||
parseReferer = ''
|
||||
if (${xvars.get.referer} ~ "^(https?)://([^/]*)(/.*)$") {
|
||||
${xvars.init "referer_scheme" "$1"}
|
||||
${xvars.init "referer_host" "$2"}
|
||||
${xvars.init "referer_path" "$3"}
|
||||
}
|
||||
'';
|
||||
in {
|
||||
xvars = {
|
||||
enable = mkMerge [
|
||||
(mkIf (any (loc: loc.xvars.enable) (attrValues config.locations)) true)
|
||||
(mkIf cfg.parseReferer true)
|
||||
];
|
||||
defaults = mkIf cfg.parseReferer (mkOptionDefault {
|
||||
referer_scheme = null;
|
||||
referer_host = null;
|
||||
referer_path = null;
|
||||
});
|
||||
lib = {
|
||||
get = mapAttrs (name: default: if cfg.enable then "$x_${name}" else assert default != null; default) cfg.defaults;
|
||||
init = name: value: assert cfg.enable && cfg.defaults ? ${name}; "set $x_${name} ${escapeString value};";
|
||||
inherit escapeString;
|
||||
};
|
||||
};
|
||||
extraConfig = mkMerge [
|
||||
(mkIf cfg.enable (mkJustBefore defaults))
|
||||
(mkIf (cfg.enable && cfg.parseReferer) (mkJustBefore parseReferer))
|
||||
];
|
||||
_module.args.xvars = config.xvars.lib;
|
||||
};
|
||||
};
|
||||
in {
|
||||
config,
|
||||
lib,
|
||||
gensokyo-zone,
|
||||
...
|
||||
}: let
|
||||
inherit (lib.options) mkOption;
|
||||
in {
|
||||
options = with lib.types; {
|
||||
services.nginx.virtualHosts = mkOption {
|
||||
type = attrsOf (submoduleWith {
|
||||
modules = [ hostModule ];
|
||||
shorthandOnlyDefinesConfig = true;
|
||||
specialArgs = {
|
||||
inherit gensokyo-zone;
|
||||
nixosConfig = config;
|
||||
};
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue