From 129559b503004e887d0db922a5e4e476cce7a0b5 Mon Sep 17 00:00:00 2001 From: oddlama Date: Thu, 9 May 2024 17:19:52 +0200 Subject: [PATCH] chore: update to loki 3.0.0, update kanidm, fix upstream oauth2 module --- hosts/sentinel/net.nix | 4 + hosts/sire/guests/loki.nix | 5 +- hosts/ward/guests/forgejo.nix | 4 - modules/kanidm.nix | 5 +- modules/oa2p.nix | 139 ++++++++++++++++++++++++++++++++++ modules/oauth2-proxy.nix | 4 +- 6 files changed, 150 insertions(+), 11 deletions(-) create mode 100644 modules/oa2p.nix diff --git a/hosts/sentinel/net.nix b/hosts/sentinel/net.nix index 1dd8be5..3ac0573 100644 --- a/hosts/sentinel/net.nix +++ b/hosts/sentinel/net.nix @@ -35,6 +35,10 @@ }; networking.nftables.firewall.zones.untrusted.interfaces = ["wan"]; + networking.nftables.chains.forward.dnat = { + after = ["conntrack"]; + rules = ["ct status dnat accept"]; + }; wireguard.proxy-sentinel.server = { host = config.networking.fqdn; diff --git a/hosts/sire/guests/loki.nix b/hosts/sire/guests/loki.nix index 2b15fdc..2b9cabe 100644 --- a/hosts/sire/guests/loki.nix +++ b/hosts/sire/guests/loki.nix @@ -97,7 +97,7 @@ in { from = "2023-06-01"; store = "tsdb"; object_store = "filesystem"; - schema = "v12"; + schema = "v13"; index = { prefix = "index_"; period = "24h"; @@ -110,7 +110,6 @@ in { active_index_directory = "${lokiDir}/tsdb-index"; cache_location = "${lokiDir}/tsdb-cache"; cache_ttl = "24h"; - shared_store = "filesystem"; }; filesystem.directory = "${lokiDir}/chunks"; }; @@ -119,6 +118,7 @@ in { limits_config = { reject_old_samples = true; reject_old_samples_max_age = "168h"; + allow_structured_metadata = false; }; # Do not delete old logs automatically @@ -129,7 +129,6 @@ in { compactor = { working_directory = lokiDir; - shared_store = "filesystem"; compactor_ring.kvstore.store = "inmemory"; }; }; diff --git a/hosts/ward/guests/forgejo.nix b/hosts/ward/guests/forgejo.nix index 9857f9c..61a1692 100644 --- a/hosts/ward/guests/forgejo.nix +++ b/hosts/ward/guests/forgejo.nix @@ -31,10 +31,6 @@ in { # Make sure to masquerade 9922 (wan) -> 22 (proxy-sentinel) networking.nftables.chains = { - forward.dnat = { - after = ["conntrack"]; - rules = ["ct status dnat accept"]; - }; postrouting.to-forgejo = { after = ["hook"]; rules = [ diff --git a/modules/kanidm.nix b/modules/kanidm.nix index 96d7384..1d1e767 100644 --- a/modules/kanidm.nix +++ b/modules/kanidm.nix @@ -169,13 +169,16 @@ # Wait for the kanidm server to come online count=0 + main_pid_existed=false while ! test -e /run/kanidmd/sock; do sleep 0.1 if [[ "$count" -eq 600 ]]; then echo "Tried for 60 seconds, giving up..." exit 1 fi - if [[ ! -d "/proc/$MAINPID" ]]; then + if [[ -d "/proc/$MAINPID" ]]; then + main_pid_existed=true + elif [[ "$main_pid_existed" == true ]]; then echo "Main server died, giving up..." exit 1 fi diff --git a/modules/oa2p.nix b/modules/oa2p.nix new file mode 100644 index 0000000..5c8b87a --- /dev/null +++ b/modules/oa2p.nix @@ -0,0 +1,139 @@ +{ + config, + lib, + ... +}: let + cfg = config.services.oauth2-proxy.nginx; +in { + disabledModules = ["services/security/oauth2-proxy-nginx.nix"]; + 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 + ''; + }; + + 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. + 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. + ''; + }; + + virtualHosts = lib.mkOption { + type = let + vhostSubmodule = lib.types.submodule { + options = { + 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 = 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 = 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 = 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.genAttrs + x (_: {}); + newType = lib.types.attrsOf vhostSubmodule; + in + lib.types.coercedTo oldType convertFunc newType; + default = {}; + example = { + "protected.foo.com" = { + allowed_groups = ["admins"]; + allowed_emails = ["boss@foo.com"]; + }; + }; + description = '' + Nginx virtual hosts to put behind the oauth2 proxy. + You can exclude specific locations by setting `auth_request off;` in the locations extraConfig setting. + ''; + }; + }; + + config.services.oauth2-proxy = lib.mkIf (cfg.virtualHosts != {} && (lib.hasPrefix "127.0.0.1:" cfg.proxy)) { + enable = true; + }; + + config.services.nginx = lib.mkIf (cfg.virtualHosts != {} && config.services.oauth2-proxy.enable) (lib.mkMerge ([ + { + virtualHosts.${cfg.domain}.locations."/oauth2/" = { + proxyPass = cfg.proxy; + extraConfig = '' + proxy_set_header X-Scheme $scheme; + proxy_set_header X-Auth-Request-Redirect $scheme://$host$request_uri; + ''; + }; + } + ] + ++ lib.optional (cfg.virtualHosts != {}) { + recommendedProxySettings = true; # needed because duplicate headers + } + ++ (lib.mapAttrsToList (vhost: conf: { + virtualHosts.${vhost} = { + locations = { + "/oauth2/auth" = let + maybeQueryArg = name: value: + if value == null + then null + else "${name}=${lib.concatStringsSep "," (builtins.map lib.escapeURL value)}"; + allArgs = lib.mapAttrsToList maybeQueryArg conf; + cleanArgs = builtins.filter (x: x != null) allArgs; + cleanArgsStr = lib.concatStringsSep "&" cleanArgs; + in { + # nginx doesn't support passing query string arguments to auth_request, + # so pass them here instead + proxyPass = "${cfg.proxy}/oauth2/auth?${cleanArgsStr}"; + extraConfig = '' + auth_request off; + proxy_set_header X-Scheme $scheme; + # nginx auth_request includes headers but not body + proxy_set_header Content-Length ""; + proxy_pass_request_body off; + ''; + }; + "@redirectToAuth2ProxyLogin" = { + return = "307 https://${cfg.domain}/oauth2/start?rd=$scheme://$host$request_uri"; + extraConfig = '' + auth_request off; + ''; + }; + }; + + extraConfig = '' + auth_request /oauth2/auth; + error_page 401 = @redirectToAuth2ProxyLogin; + + # pass information via X-User and X-Email headers to backend, + # requires running with --set-xauthrequest flag + auth_request_set $user $upstream_http_x_auth_request_user; + auth_request_set $email $upstream_http_x_auth_request_email; + proxy_set_header X-User $user; + proxy_set_header X-Email $email; + + # if you enabled --cookie-refresh, this is needed for it to work with auth_request + auth_request_set $auth_cookie $upstream_http_set_cookie; + add_header Set-Cookie $auth_cookie; + ''; + }; + }) + cfg.virtualHosts))); +} diff --git a/modules/oauth2-proxy.nix b/modules/oauth2-proxy.nix index d16fc46..58c58c3 100644 --- a/modules/oauth2-proxy.nix +++ b/modules/oauth2-proxy.nix @@ -16,6 +16,7 @@ cfg = config.meta.oauth2-proxy; in { + imports = [./oa2p.nix]; options.meta.oauth2-proxy = { enable = mkEnableOption "oauth2 proxy"; @@ -90,9 +91,6 @@ in { services.oauth2-proxy = { enable = true; - # Needed to prevent evaluation error (should theoretically be fixed upstream...) - nginx.domain = "dummy"; - cookie.domain = ".${cfg.cookieDomain}"; cookie.secure = true; # FIXME disabled because of errors. My closest guess is that this