mirror of
https://github.com/gensokyo-zone/infrastructure.git
synced 2026-02-09 12:29:19 -08:00
refactor(nginx): ssl module
This commit is contained in:
parent
69c014b24e
commit
a7e35fbc88
28 changed files with 794 additions and 546 deletions
71
modules/nixos/nginx/listen.nix
Normal file
71
modules/nixos/nginx/listen.nix
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (lib.options) mkOption mkEnableOption;
|
||||
inherit (lib.modules) mkIf mkDefault mkOptionDefault mkForce mkOverride;
|
||||
inherit (lib.attrsets) mapAttrsToList filterAttrs removeAttrs;
|
||||
inherit (lib.lists) concatMap;
|
||||
mkAlmostOptionDefault = mkOverride 1250;
|
||||
inherit (config.services) nginx;
|
||||
extraListenAttrs = [ "enable" ];
|
||||
listenModule = { config, virtualHost, ... }: {
|
||||
options = with lib.types; {
|
||||
enable = mkEnableOption "this port" // {
|
||||
default = true;
|
||||
};
|
||||
ssl = mkOption {
|
||||
type = bool;
|
||||
default = false;
|
||||
};
|
||||
port = mkOption {
|
||||
type = nullOr port;
|
||||
};
|
||||
};
|
||||
config = {
|
||||
enable = mkIf (config.ssl && !virtualHost.ssl.enable) (mkForce false);
|
||||
_module.freeformType = with lib.types; attrsOf (oneOf [
|
||||
str (listOf str) (nullOr port) bool
|
||||
]);
|
||||
port = mkOptionDefault (
|
||||
if config.ssl then nginx.defaultSSLListenPort else nginx.defaultHTTPListenPort
|
||||
);
|
||||
};
|
||||
};
|
||||
hostModule = { config, ... }: let
|
||||
cfg = config.listenPorts;
|
||||
enabledPorts = filterAttrs (_: port: port.enable) cfg;
|
||||
in {
|
||||
options = with lib.types; {
|
||||
listenPorts = mkOption {
|
||||
type = attrsOf (submoduleWith {
|
||||
modules = [ listenModule ];
|
||||
specialArgs = {
|
||||
virtualHost = config;
|
||||
};
|
||||
});
|
||||
default = { };
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
listen = let
|
||||
addresses = if config.listenAddresses != [ ] then config.listenAddresses else nginx.defaultListenAddresses;
|
||||
in mkIf (cfg != { }) (mkAlmostOptionDefault (
|
||||
concatMap (addr: mapAttrsToList (_: listen: {
|
||||
addr = mkDefault addr;
|
||||
} // removeAttrs listen extraListenAttrs) enabledPorts) addresses
|
||||
));
|
||||
};
|
||||
};
|
||||
in {
|
||||
options = with lib.types; {
|
||||
services.nginx.virtualHosts = mkOption {
|
||||
type = attrsOf (submoduleWith {
|
||||
modules = [ hostModule ];
|
||||
shorthandOnlyDefinesConfig = true;
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
@ -62,7 +62,7 @@
|
|||
enable = mkOptionDefault virtualHost.local.enable;
|
||||
denyGlobal = mkOptionDefault virtualHost.local.denyGlobal;
|
||||
trusted = mkOptionDefault virtualHost.local.trusted;
|
||||
emitDenyGlobal = virtualHost.local.emitDenyGlobal;
|
||||
emitDenyGlobal = config.local.denyGlobal && !virtualHost.local.emitDenyGlobal;
|
||||
};
|
||||
};
|
||||
hostModule = {config, ...}: {
|
||||
|
|
|
|||
69
modules/nixos/nginx/name.nix
Normal file
69
modules/nixos/nginx/name.nix
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (lib.options) mkOption;
|
||||
inherit (lib.modules) mkIf mkDefault mkOptionDefault;
|
||||
inherit (lib.strings) optionalString;
|
||||
inherit (config.services) tailscale;
|
||||
inherit (config) networking;
|
||||
hostModule = {config, ...}: let
|
||||
cfg = config.name;
|
||||
in {
|
||||
options = with lib.types; {
|
||||
name = {
|
||||
shortServer = mkOption {
|
||||
type = nullOr str;
|
||||
default = null;
|
||||
};
|
||||
qualifier = mkOption {
|
||||
type = nullOr str;
|
||||
};
|
||||
includeLocal = mkOption {
|
||||
type = bool;
|
||||
default = false;
|
||||
};
|
||||
includeTailscale = mkOption {
|
||||
type = bool;
|
||||
};
|
||||
};
|
||||
allServerNames = mkOption {
|
||||
type = listOf str;
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
name = {
|
||||
qualifier = mkOptionDefault (
|
||||
if config.local.enable then "local"
|
||||
else null
|
||||
);
|
||||
includeTailscale = mkOptionDefault (
|
||||
config.local.enable && tailscale.enable && cfg.qualifier != "tail"
|
||||
);
|
||||
};
|
||||
serverName = mkIf (cfg.shortServer != null) (mkDefault (
|
||||
cfg.shortServer
|
||||
+ optionalString (cfg.qualifier != null) ".${cfg.qualifier}"
|
||||
+ ".${networking.domain}"
|
||||
));
|
||||
serverAliases = mkIf (cfg.shortServer != null) (mkDefault [
|
||||
(mkIf cfg.includeLocal "${cfg.shortServer}.local.${networking.domain}")
|
||||
(mkIf cfg.includeTailscale "${cfg.shortServer}.tail.${networking.domain}")
|
||||
]);
|
||||
allServerNames = mkOptionDefault (
|
||||
[ config.serverName ] ++ config.serverAliases
|
||||
);
|
||||
};
|
||||
};
|
||||
in {
|
||||
options = with lib.types; {
|
||||
services.nginx.virtualHosts = mkOption {
|
||||
type = attrsOf (submoduleWith {
|
||||
modules = [hostModule];
|
||||
shorthandOnlyDefinesConfig = true;
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
204
modules/nixos/nginx/proxied.nix
Normal file
204
modules/nixos/nginx/proxied.nix
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (lib.options) mkOption mkEnableOption;
|
||||
inherit (lib.modules) mkIf mkMerge mkBefore mkAfter mkOrder mkDefault mkOptionDefault mkOverride;
|
||||
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;
|
||||
mkAlmostAfter = mkOrder 1250;
|
||||
mkAlmostOptionDefault = mkOverride 1250;
|
||||
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;
|
||||
if ($http_x_forwarded_proto) {
|
||||
set $x_scheme $http_x_forwarded_proto;
|
||||
}
|
||||
if ($http_x_real_ip) {
|
||||
set $x_remote_addr $http_x_real_ip;
|
||||
}
|
||||
if ($http_x_forwarded_host) {
|
||||
set $x_forwarded_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;
|
||||
}
|
||||
'';
|
||||
locationModule = { config, virtualHost, ... }: let
|
||||
cfg = config.proxied;
|
||||
in {
|
||||
options = with lib.types; {
|
||||
proxied = {
|
||||
enable = mkOption {
|
||||
type = enum [ false true "cloudflared" ];
|
||||
default = false;
|
||||
};
|
||||
enabled = mkOption {
|
||||
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" ];
|
||||
};
|
||||
};
|
||||
force = mkEnableOption "redirect to SSL";
|
||||
};
|
||||
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
|
||||
);
|
||||
};
|
||||
recommendedProxySettings = mkMerge [
|
||||
(mkAlmostOptionDefault (config.proxy.headers.enableRecommended == "nixpkgs"))
|
||||
];
|
||||
extraConfig = mkMerge [
|
||||
(mkIf emitVars (
|
||||
mkBefore xHeadersProxied
|
||||
))
|
||||
(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
|
||||
cfg = config.proxied;
|
||||
in {
|
||||
options = with lib.types; {
|
||||
proxied = {
|
||||
enable = mkOption {
|
||||
type = enum [ false true "cloudflared" ];
|
||||
default = false;
|
||||
};
|
||||
enabled = mkOption {
|
||||
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 {
|
||||
modules = [ locationModule ];
|
||||
shorthandOnlyDefinesConfig = true;
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
proxied = {
|
||||
xvars.enable = mkIf (any (loc: loc.proxied.xvars.enable) (attrValues config.locations)) true;
|
||||
};
|
||||
local.denyGlobal = mkIf (cfg.enable == "cloudflared") (mkDefault true);
|
||||
extraConfig = mkIf cfg.xvars.enable (mkBefore ''
|
||||
${xHeadersDefaults}
|
||||
${optionalString cfg.enabled xHeadersProxied}
|
||||
'');
|
||||
};
|
||||
};
|
||||
in {
|
||||
options = with lib.types; {
|
||||
services.nginx.virtualHosts = mkOption {
|
||||
type = attrsOf (submoduleWith {
|
||||
modules = [ hostModule ];
|
||||
shorthandOnlyDefinesConfig = true;
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
92
modules/nixos/nginx/ssl.nix
Normal file
92
modules/nixos/nginx/ssl.nix
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
inherit (lib.options) mkOption mkEnableOption;
|
||||
inherit (lib.modules) mkIf mkDefault mkOptionDefault mkOverride;
|
||||
mkAlmostOptionDefault = mkOverride 1250;
|
||||
forceRedirectConfig = virtualHost: ''
|
||||
if ($x_scheme = http) {
|
||||
return ${toString virtualHost.redirectCode} https://$host$request_uri;
|
||||
}
|
||||
'';
|
||||
locationModule = { config, virtualHost, ... }: let
|
||||
cfg = config.ssl;
|
||||
emitForce = cfg.force && !virtualHost.ssl.forced;
|
||||
in {
|
||||
options.ssl = {
|
||||
force = mkEnableOption "redirect to SSL";
|
||||
};
|
||||
config = {
|
||||
proxied.xvars.enable = mkIf emitForce true;
|
||||
extraConfig = mkIf emitForce (forceRedirectConfig virtualHost);
|
||||
};
|
||||
};
|
||||
hostModule = { config, name, ... }: let
|
||||
cfg = config.ssl;
|
||||
emitForce = cfg.forced && config.proxied.enabled;
|
||||
in {
|
||||
options = with lib.types; {
|
||||
ssl = {
|
||||
enable = mkOption {
|
||||
type = bool;
|
||||
};
|
||||
force = mkOption {
|
||||
# TODO: "force-nonlocal"? exceptions for tailscale?
|
||||
type = enum [ false true "only" "reject" ];
|
||||
default = false;
|
||||
};
|
||||
forced = mkOption {
|
||||
type = bool;
|
||||
readOnly = true;
|
||||
};
|
||||
cert = {
|
||||
name = mkOption {
|
||||
type = nullOr str;
|
||||
default = null;
|
||||
};
|
||||
keyPath = mkOption {
|
||||
type = nullOr path;
|
||||
default = null;
|
||||
};
|
||||
path = mkOption {
|
||||
type = nullOr path;
|
||||
default = null;
|
||||
};
|
||||
};
|
||||
};
|
||||
locations = mkOption {
|
||||
type = attrsOf (submoduleWith {
|
||||
modules = [ locationModule ];
|
||||
shorthandOnlyDefinesConfig = true;
|
||||
});
|
||||
};
|
||||
};
|
||||
config = {
|
||||
ssl = {
|
||||
enable = mkOptionDefault (cfg.cert.name != null || cfg.cert.keyPath != null);
|
||||
forced = mkOptionDefault (cfg.force != false && cfg.force != "reject");
|
||||
};
|
||||
addSSL = mkIf (cfg.enable && (cfg.force == false || emitForce)) (mkDefault true);
|
||||
forceSSL = mkIf (cfg.enable && cfg.force == true && !emitForce) (mkDefault true);
|
||||
onlySSL = mkIf (cfg.enable && cfg.force == "only" && !emitForce) (mkDefault true);
|
||||
rejectSSL = mkIf (cfg.force == "reject") (mkDefault true);
|
||||
useACMEHost = mkAlmostOptionDefault cfg.cert.name;
|
||||
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;
|
||||
extraConfig = mkIf emitForce (forceRedirectConfig config);
|
||||
};
|
||||
};
|
||||
in {
|
||||
options = with lib.types; {
|
||||
services.nginx.virtualHosts = mkOption {
|
||||
type = attrsOf (submoduleWith {
|
||||
modules = [ hostModule ];
|
||||
shorthandOnlyDefinesConfig = true;
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
@ -6,11 +6,123 @@
|
|||
inherit (lib.options) mkOption mkEnableOption;
|
||||
inherit (lib.modules) mkIf mkMerge mkBefore mkDefault;
|
||||
inherit (config) networking;
|
||||
inherit (config.services) vouch-proxy tailscale;
|
||||
vouchModule = {config, ...}: {
|
||||
inherit (config.services) vouch-proxy nginx tailscale;
|
||||
inherit (nginx) vouch;
|
||||
locationModule = {config, virtualHost, ...}: {
|
||||
options.vouch = with lib.types; {
|
||||
requireAuth = mkEnableOption "require auth to access this location";
|
||||
};
|
||||
config = mkIf config.vouch.requireAuth {
|
||||
proxied.xvars.enable = true;
|
||||
extraConfig = assert virtualHost.vouch.enable; mkMerge [
|
||||
''
|
||||
add_header Access-Control-Allow-Origin ${vouch.url};
|
||||
add_header Access-Control-Allow-Origin ${vouch.authUrl};
|
||||
''
|
||||
(mkIf (vouch.localSso.enable && config.local.enable) ''
|
||||
add_header Access-Control-Allow-Origin ${vouch.localUrl};
|
||||
'')
|
||||
(mkIf (vouch.localSso.enable && config.local.enable && tailscale.enable) ''
|
||||
add_header Access-Control-Allow-Origin $x_scheme://${vouch.tailDomain};
|
||||
'')
|
||||
''
|
||||
proxy_set_header X-Vouch-User $auth_resp_x_vouch_user;
|
||||
''
|
||||
];
|
||||
};
|
||||
};
|
||||
hostModule = {config, ...}: let
|
||||
cfg = config.vouch;
|
||||
in {
|
||||
options = with lib.types; {
|
||||
locations = mkOption {
|
||||
type = attrsOf (submodule locationModule);
|
||||
};
|
||||
vouch = {
|
||||
enable = mkEnableOption "vouch auth proxy";
|
||||
requireAuth = mkEnableOption "require auth to access this host" // {
|
||||
default = true;
|
||||
};
|
||||
errorLocation = mkOption {
|
||||
type = str;
|
||||
default = "@error401";
|
||||
};
|
||||
authRequestLocation = mkOption {
|
||||
type = str;
|
||||
default = "/validate";
|
||||
};
|
||||
authRequestDirective = mkOption {
|
||||
type = lines;
|
||||
default = ''
|
||||
auth_request ${cfg.authRequestLocation};
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
config = {
|
||||
extraConfig = mkIf (cfg.enable && cfg.requireAuth) ''
|
||||
${cfg.authRequestDirective}
|
||||
error_page 401 = ${cfg.errorLocation};
|
||||
'';
|
||||
locations = mkIf cfg.enable {
|
||||
"/" = mkIf cfg.requireAuth {
|
||||
vouch.requireAuth = true;
|
||||
};
|
||||
${cfg.errorLocation} = {
|
||||
proxied.xvars.enable = true;
|
||||
extraConfig = let
|
||||
localVouchUrl = ''
|
||||
if ($x_forwarded_host ~ "\.local\.${networking.domain}$") {
|
||||
set $vouch_url ${vouch.localUrl};
|
||||
}
|
||||
'';
|
||||
tailVouchUrl = ''
|
||||
if ($x_forwarded_host ~ "\.tail\.${networking.domain}$") {
|
||||
set $vouch_url $x_scheme://${vouch.tailDomain};
|
||||
}
|
||||
'';
|
||||
in
|
||||
mkMerge [
|
||||
(mkBefore ''
|
||||
set $vouch_url ${vouch.url};
|
||||
'')
|
||||
(mkIf (vouch.localSso.enable && config.local.enable or false) localVouchUrl)
|
||||
(mkIf (vouch.localSso.enable && config.local.enable or false && tailscale.enable) tailVouchUrl)
|
||||
''
|
||||
return 302 $vouch_url/login?url=$x_scheme://$x_forwarded_host$request_uri&vouch-failcount=$auth_resp_failcount&X-Vouch-Token=$auth_resp_jwt&error=$auth_resp_err;
|
||||
''
|
||||
];
|
||||
};
|
||||
${cfg.authRequestLocation} = {
|
||||
proxyPass = "${vouch.proxyOrigin}/validate";
|
||||
proxy.headers.enableRecommended = true;
|
||||
extraConfig = let
|
||||
# nginx-proxied vouch must use X-Forwarded-Host, but vanilla vouch requires Host
|
||||
vouchProxyHost = if vouch.doubleProxy
|
||||
then "''"
|
||||
else "$x_forwarded_host";
|
||||
in ''
|
||||
set $x_proxy_host ${vouchProxyHost};
|
||||
proxy_pass_request_body off;
|
||||
proxy_set_header Content-Length "";
|
||||
auth_request_set $auth_resp_x_vouch_user $upstream_http_x_vouch_user;
|
||||
auth_request_set $auth_resp_jwt $upstream_http_x_vouch_jwt;
|
||||
auth_request_set $auth_resp_err $upstream_http_x_vouch_err;
|
||||
auth_request_set $auth_resp_failcount $upstream_http_x_vouch_failcount;
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
in {
|
||||
options = with lib.types; {
|
||||
services.nginx = {
|
||||
vouch = {
|
||||
enable = mkEnableOption "vouch auth proxy";
|
||||
localSso = {
|
||||
# NOTE: this won't work without multiple vouch-proxy instances with different auth urls...
|
||||
enable = mkEnableOption "lan-local auth";
|
||||
};
|
||||
proxyOrigin = mkOption {
|
||||
type = str;
|
||||
default = "https://login.local.${networking.domain}";
|
||||
|
|
@ -35,117 +147,32 @@
|
|||
type = str;
|
||||
default = "login.tail.${networking.domain}";
|
||||
};
|
||||
authRequestDirective = mkOption {
|
||||
type = lines;
|
||||
default = ''
|
||||
auth_request /validate;
|
||||
'';
|
||||
};
|
||||
};
|
||||
virtualHosts = mkOption {
|
||||
type = attrsOf (submodule hostModule);
|
||||
};
|
||||
};
|
||||
config = mkMerge [
|
||||
};
|
||||
config.services.nginx = {
|
||||
vouch = mkMerge [
|
||||
{
|
||||
vouch = mkIf vouch-proxy.enable {
|
||||
proxyOrigin = let
|
||||
inherit (vouch-proxy.settings.vouch) listen port;
|
||||
host =
|
||||
if listen == "0.0.0.0" || listen == "[::]"
|
||||
then "localhost"
|
||||
else listen;
|
||||
in
|
||||
mkDefault "http://${host}:${toString port}";
|
||||
authUrl = mkDefault vouch-proxy.authUrl;
|
||||
url = mkDefault vouch-proxy.url;
|
||||
doubleProxy = mkDefault false;
|
||||
};
|
||||
}
|
||||
{
|
||||
vouch.proxyOrigin = mkIf (tailscale.enable && !vouch-proxy.enable) (
|
||||
mkDefault
|
||||
"http://login.tail.${networking.domain}"
|
||||
proxyOrigin = mkIf (tailscale.enable && !vouch-proxy.enable) (
|
||||
mkDefault "http://login.tail.${networking.domain}"
|
||||
);
|
||||
}
|
||||
(mkIf config.vouch.enable {
|
||||
extraConfig = ''
|
||||
${config.vouch.authRequestDirective}
|
||||
error_page 401 = @error401;
|
||||
'';
|
||||
locations = {
|
||||
"/" = {
|
||||
extraConfig = mkMerge [
|
||||
''
|
||||
add_header Access-Control-Allow-Origin ${config.vouch.url};
|
||||
add_header Access-Control-Allow-Origin ${config.vouch.authUrl};
|
||||
''
|
||||
(mkIf config.local.enable ''
|
||||
add_header Access-Control-Allow-Origin ${config.vouch.localUrl};
|
||||
'')
|
||||
(mkIf (config.local.enable && tailscale.enable) ''
|
||||
add_header Access-Control-Allow-Origin $scheme://${config.vouch.tailDomain};
|
||||
'')
|
||||
''
|
||||
proxy_set_header X-Vouch-User $auth_resp_x_vouch_user;
|
||||
''
|
||||
];
|
||||
};
|
||||
"@error401" = {
|
||||
extraConfig = let
|
||||
localVouchUrl = ''
|
||||
if ($http_host ~ "\.local\.${networking.domain}$") {
|
||||
set $vouch_url ${config.vouch.localUrl};
|
||||
}
|
||||
'';
|
||||
tailVouchUrl = ''
|
||||
if ($http_host ~ "\.tail\.${networking.domain}$") {
|
||||
set $vouch_url $vouch_scheme://${config.vouch.tailDomain};
|
||||
}
|
||||
'';
|
||||
in
|
||||
mkMerge [
|
||||
(mkBefore ''
|
||||
set $vouch_url ${config.vouch.url};
|
||||
set $vouch_scheme $scheme;
|
||||
'')
|
||||
(mkIf config.local.trusted (mkBefore ''
|
||||
if ($http_x_forwarded_proto) {
|
||||
set $vouch_scheme $http_x_forwarded_proto;
|
||||
}
|
||||
''))
|
||||
(mkIf (config.local.enable or false) localVouchUrl)
|
||||
(mkIf (config.local.enable or false && tailscale.enable) tailVouchUrl)
|
||||
''
|
||||
return 302 $vouch_url/login?url=$vouch_scheme://$http_host$request_uri&vouch-failcount=$auth_resp_failcount&X-Vouch-Token=$auth_resp_jwt&error=$auth_resp_err;
|
||||
''
|
||||
];
|
||||
};
|
||||
"/validate" = {
|
||||
recommendedProxySettings = false;
|
||||
proxyPass = "${config.vouch.proxyOrigin}/validate";
|
||||
extraConfig = mkMerge [
|
||||
(mkIf (!config.vouch.doubleProxy) ''
|
||||
proxy_set_header Host $host;
|
||||
'')
|
||||
(mkIf config.vouch.doubleProxy ''
|
||||
proxy_set_header X-Host $host;
|
||||
'')
|
||||
''
|
||||
proxy_pass_request_body off;
|
||||
proxy_set_header Content-Length "";
|
||||
auth_request_set $auth_resp_x_vouch_user $upstream_http_x_vouch_user;
|
||||
auth_request_set $auth_resp_jwt $upstream_http_x_vouch_jwt;
|
||||
auth_request_set $auth_resp_err $upstream_http_x_vouch_err;
|
||||
auth_request_set $auth_resp_failcount $upstream_http_x_vouch_failcount;
|
||||
''
|
||||
];
|
||||
};
|
||||
};
|
||||
(mkIf vouch-proxy.enable {
|
||||
proxyOrigin = let
|
||||
inherit (vouch-proxy.settings.vouch) listen port;
|
||||
host =
|
||||
if listen == "0.0.0.0" || listen == "[::]"
|
||||
then "localhost"
|
||||
else listen;
|
||||
in
|
||||
mkDefault "http://${host}:${toString port}";
|
||||
authUrl = mkDefault vouch-proxy.authUrl;
|
||||
url = mkDefault vouch-proxy.url;
|
||||
doubleProxy = mkDefault false;
|
||||
})
|
||||
];
|
||||
};
|
||||
in {
|
||||
options = with lib.types; {
|
||||
services.nginx.virtualHosts = mkOption {
|
||||
type = attrsOf (submodule vouchModule);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@
|
|||
};
|
||||
config = mkIf config.proxy.websocket.enable {
|
||||
extraConfig = ''
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
'';
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue