mirror of
https://github.com/gensokyo-zone/infrastructure.git
synced 2026-02-09 12:29:19 -08:00
feat(vouch): local access
This commit is contained in:
parent
ee2618061d
commit
e4596f256f
5 changed files with 182 additions and 73 deletions
|
|
@ -3,73 +3,115 @@
|
||||||
lib,
|
lib,
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
with lib; let
|
let
|
||||||
inherit (config.services) vouch-proxy;
|
inherit (lib.options) mkOption mkEnableOption;
|
||||||
in {
|
inherit (lib.modules) mkIf mkMerge mkBefore mkDefault;
|
||||||
options = with types; {
|
inherit (config) networking;
|
||||||
services.nginx.virtualHosts = let
|
inherit (config.services) vouch-proxy tailscale;
|
||||||
vouchModule = { config, ... }: {
|
vouchModule = { config, ... }: {
|
||||||
options = {
|
options = with lib.types; {
|
||||||
vouch = {
|
vouch = {
|
||||||
enable = mkEnableOption "vouch auth proxy";
|
enable = mkEnableOption "vouch auth proxy";
|
||||||
proxyOrigin = mkOption {
|
proxyOrigin = mkOption {
|
||||||
type = str;
|
type = str;
|
||||||
};
|
default = "https://login.local.${networking.domain}";
|
||||||
authUrl = mkOption {
|
};
|
||||||
type = str;
|
authUrl = mkOption {
|
||||||
};
|
type = str;
|
||||||
url = mkOption {
|
default = "https://id.${networking.domain}";
|
||||||
type = str;
|
};
|
||||||
};
|
url = mkOption {
|
||||||
|
type = str;
|
||||||
|
default = "https://login.${networking.domain}";
|
||||||
|
};
|
||||||
|
localUrl = mkOption {
|
||||||
|
type = str;
|
||||||
|
default = "https://login.local.${networking.domain}";
|
||||||
|
};
|
||||||
|
tailDomain = mkOption {
|
||||||
|
type = str;
|
||||||
|
default = "login.tail.${networking.domain}";
|
||||||
|
};
|
||||||
|
authRequestDirective = mkOption {
|
||||||
|
type = lines;
|
||||||
|
default = ''
|
||||||
|
auth_request /validate;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config = 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;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
vouch.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 = ''
|
||||||
|
add_header Access-Control-Allow-Origin ${config.vouch.url};
|
||||||
|
add_header Access-Control-Allow-Origin ${config.vouch.authUrl};
|
||||||
|
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 $scheme://${config.vouch.tailDomain};
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
in mkMerge [
|
||||||
|
(mkBefore ''
|
||||||
|
set $vouch_url ${config.vouch.url};
|
||||||
|
'')
|
||||||
|
(mkIf (config.local.enable or false) localVouchUrl)
|
||||||
|
(mkIf (config.local.enable or false && tailscale.enable) tailVouchUrl)
|
||||||
|
''
|
||||||
|
return 302 $vouch_url/login?url=$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 = ''
|
||||||
|
proxy_set_header 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;
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
config = mkMerge [
|
})
|
||||||
{
|
];
|
||||||
vouch = mkIf vouch-proxy.enable {
|
};
|
||||||
proxyOrigin = let
|
in {
|
||||||
inherit (vouch-proxy.settings.vouch) listen port;
|
options = with lib.types; {
|
||||||
host = if listen == "0.0.0.0" || listen == "[::]" then "localhost" else listen;
|
services.nginx.virtualHosts = mkOption {
|
||||||
in mkOptionDefault "http://${host}:${toString port}";
|
|
||||||
authUrl = mkOptionDefault vouch-proxy.authUrl;
|
|
||||||
url = mkOptionDefault vouch-proxy.url;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
(mkIf config.vouch.enable {
|
|
||||||
extraConfig = ''
|
|
||||||
auth_request /validate;
|
|
||||||
error_page 401 = @error401;
|
|
||||||
'';
|
|
||||||
locations = {
|
|
||||||
"/" = {
|
|
||||||
extraConfig = ''
|
|
||||||
add_header Access-Control-Allow-Origin ${config.vouch.url};
|
|
||||||
add_header Access-Control-Allow-Origin ${config.vouch.authUrl};
|
|
||||||
proxy_set_header X-Vouch-User $auth_resp_x_vouch_user;
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
"@error401" = {
|
|
||||||
extraConfig = ''
|
|
||||||
return 302 ${config.vouch.url}/login?url=$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 = ''
|
|
||||||
proxy_set_header 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;
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
})
|
|
||||||
];
|
|
||||||
};
|
|
||||||
in mkOption {
|
|
||||||
type = attrsOf (submodule vouchModule);
|
type = attrsOf (submodule vouchModule);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
61
nixos/access/vouch.nix
Normal file
61
nixos/access/vouch.nix
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
inherit (lib.options) mkOption;
|
||||||
|
inherit (lib.modules) mkIf mkDefault mkOptionDefault;
|
||||||
|
inherit (config.services) tailscale;
|
||||||
|
cfg = config.services.vouch-proxy;
|
||||||
|
access = config.services.nginx.access.vouch;
|
||||||
|
in {
|
||||||
|
options.services.nginx.access.vouch = with lib.types; {
|
||||||
|
url = mkOption {
|
||||||
|
type = str;
|
||||||
|
};
|
||||||
|
domain = mkOption {
|
||||||
|
type = str;
|
||||||
|
default = "login.${config.networking.domain}";
|
||||||
|
};
|
||||||
|
localDomain = mkOption {
|
||||||
|
type = str;
|
||||||
|
default = "login.local.${config.networking.domain}";
|
||||||
|
};
|
||||||
|
tailDomain = mkOption {
|
||||||
|
type = str;
|
||||||
|
default = "login.tail.${config.networking.domain}";
|
||||||
|
};
|
||||||
|
useACMEHost = mkOption {
|
||||||
|
type = nullOr str;
|
||||||
|
default = null;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config.services.nginx = {
|
||||||
|
access.vouch = mkIf cfg.enable {
|
||||||
|
url = let
|
||||||
|
inherit (cfg.settings.vouch) listen;
|
||||||
|
host = if listen == "0.0.0.0" || listen == "[::]" then "localhost" else listen;
|
||||||
|
in mkOptionDefault "http://${host}:${toString cfg.port}";
|
||||||
|
};
|
||||||
|
virtualHosts = let
|
||||||
|
location = {
|
||||||
|
proxy.websocket.enable = true;
|
||||||
|
proxyPass = access.url;
|
||||||
|
recommendedProxySettings = false;
|
||||||
|
};
|
||||||
|
in {
|
||||||
|
${access.localDomain} = mkIf (access.useACMEHost != null) {
|
||||||
|
local.enable = true;
|
||||||
|
locations."/" = location;
|
||||||
|
useACMEHost = mkDefault access.useACMEHost;
|
||||||
|
forceSSL = true;
|
||||||
|
};
|
||||||
|
${access.tailDomain} = mkIf tailscale.enable {
|
||||||
|
local.enable = true;
|
||||||
|
locations."/" = location;
|
||||||
|
useACMEHost = mkDefault access.useACMEHost;
|
||||||
|
addSSL = mkIf (access.useACMEHost != null) (mkDefault true);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -28,6 +28,7 @@ in {
|
||||||
nixos.access.nginx
|
nixos.access.nginx
|
||||||
nixos.access.global
|
nixos.access.global
|
||||||
nixos.access.gensokyo
|
nixos.access.gensokyo
|
||||||
|
nixos.access.vouch
|
||||||
nixos.access.kanidm
|
nixos.access.kanidm
|
||||||
nixos.access.freeipa
|
nixos.access.freeipa
|
||||||
nixos.access.kitchencam
|
nixos.access.kitchencam
|
||||||
|
|
@ -59,6 +60,14 @@ in {
|
||||||
inherit (config.services) nginx tailscale;
|
inherit (config.services) nginx tailscale;
|
||||||
inherit (nginx) access;
|
inherit (nginx) access;
|
||||||
in {
|
in {
|
||||||
|
${access.vouch.localDomain} = {
|
||||||
|
inherit (nginx) group;
|
||||||
|
extraDomainNames = mkMerge [
|
||||||
|
(mkIf tailscale.enable [
|
||||||
|
access.vouch.tailDomain
|
||||||
|
])
|
||||||
|
];
|
||||||
|
};
|
||||||
${access.kanidm.domain} = {
|
${access.kanidm.domain} = {
|
||||||
inherit (nginx) group;
|
inherit (nginx) group;
|
||||||
extraDomainNames = mkMerge [
|
extraDomainNames = mkMerge [
|
||||||
|
|
@ -128,15 +137,14 @@ in {
|
||||||
|
|
||||||
services.nginx = let
|
services.nginx = let
|
||||||
inherit (config.services.nginx) access;
|
inherit (config.services.nginx) access;
|
||||||
vouch = {
|
|
||||||
authUrl = vouch-proxy.authUrl;
|
|
||||||
url = vouch-proxy.url;
|
|
||||||
proxyOrigin = "http://${tei.networking.access.hostnameForNetwork.tail}:${toString vouch-proxy.settings.vouch.port}";
|
|
||||||
};
|
|
||||||
in {
|
in {
|
||||||
access.plex = assert plex.enable; {
|
access.plex = assert plex.enable; {
|
||||||
url = "http://${mediabox.networking.access.hostnameForNetwork.local}:32400";
|
url = "http://${mediabox.networking.access.hostnameForNetwork.local}:32400";
|
||||||
};
|
};
|
||||||
|
access.vouch = assert vouch-proxy.enable; {
|
||||||
|
url = "http://${tei.networking.access.hostnameForNetwork.tail}:${toString vouch-proxy.settings.vouch.port}";
|
||||||
|
useACMEHost = access.vouch.localDomain;
|
||||||
|
};
|
||||||
access.kanidm = assert kanidm.enableServer; {
|
access.kanidm = assert kanidm.enableServer; {
|
||||||
inherit (kanidm.server.frontend) domain port;
|
inherit (kanidm.server.frontend) domain port;
|
||||||
host = tei.networking.access.hostnameForNetwork.local;
|
host = tei.networking.access.hostnameForNetwork.local;
|
||||||
|
|
@ -168,10 +176,8 @@ in {
|
||||||
useACMEHost = access.plex.domain;
|
useACMEHost = access.plex.domain;
|
||||||
};
|
};
|
||||||
${access.kitchencam.domain} = {
|
${access.kitchencam.domain} = {
|
||||||
inherit vouch;
|
|
||||||
};
|
};
|
||||||
${access.invidious.domain} = {
|
${access.invidious.domain} = {
|
||||||
inherit vouch;
|
|
||||||
useACMEHost = access.invidious.domain;
|
useACMEHost = access.invidious.domain;
|
||||||
forceSSL = true;
|
forceSSL = true;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
config,
|
config,
|
||||||
lib,
|
lib,
|
||||||
meta,
|
meta,
|
||||||
pkgs,
|
|
||||||
...
|
...
|
||||||
}: let
|
}: let
|
||||||
inherit (lib.modules) mkIf mkMerge;
|
inherit (lib.modules) mkIf mkMerge;
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ module "hakurei_system_records" {
|
||||||
local_subdomains = [
|
local_subdomains = [
|
||||||
"prox",
|
"prox",
|
||||||
"id",
|
"id",
|
||||||
|
"login",
|
||||||
"ldap",
|
"ldap",
|
||||||
"freeipa",
|
"freeipa",
|
||||||
"smb",
|
"smb",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue