diff --git a/nixos-modules/profiles/auth.nix b/nixos-modules/profiles/auth.nix index 0aa5871..ea5fd07 100644 --- a/nixos-modules/profiles/auth.nix +++ b/nixos-modules/profiles/auth.nix @@ -13,11 +13,11 @@ in }; listen_http = mkOption { type = types.str; - default = "0.0.0.0:9000"; + default = "127.0.0.1:9000"; }; listen_metrics = mkOption { type = types.str; - default = "0.0.0.0:9300"; + default = "127.0.0.1:9300"; }; }; }; @@ -33,6 +33,13 @@ in }; }; + services.nginx.virtualHosts.${cfg.domain} = { + locations."/" = { + proxyWebsockets = true; + proxyPass = "http://" + cfg.listen_http; + }; + }; + services.prometheus.scrapeConfigs = [{ job_name = "authentik"; static_configs = [{ targets = [ cfg.listen_metrics ]; }]; }]; }; } diff --git a/nixos-modules/profiles/default.nix b/nixos-modules/profiles/default.nix index e729993..3b9fcbb 100644 --- a/nixos-modules/profiles/default.nix +++ b/nixos-modules/profiles/default.nix @@ -1,6 +1,7 @@ { imports = [ ./auth.nix + ./ingress.nix ./monitoring.nix ]; } diff --git a/nixos-modules/profiles/ingress.nix b/nixos-modules/profiles/ingress.nix new file mode 100644 index 0000000..3b55160 --- /dev/null +++ b/nixos-modules/profiles/ingress.nix @@ -0,0 +1,30 @@ +{ config, lib, ... }: + +let + cfg = config.profiles.ingress; + inherit (lib) types mkOption mkEnableOption mkIf concatMapAttrs; +in +{ + options = { + profiles.ingress = { + enable = mkEnableOption "ingress"; + }; + }; + + config = mkIf cfg.enable { + services = { + nginx = { + enable = true; + + statusPage = true; + + recommendedGzipSettings = true; + recommendedOptimisation = true; + recommendedTlsSettings = true; + recommendedProxySettings = true; + + virtualHosts._.default = true; + }; + }; + }; +} diff --git a/nixos-modules/profiles/monitoring.nix b/nixos-modules/profiles/monitoring.nix index c313777..1cc63e6 100644 --- a/nixos-modules/profiles/monitoring.nix +++ b/nixos-modules/profiles/monitoring.nix @@ -42,7 +42,7 @@ in server = { inherit (cfg) domain root_url; http_port = 3000; - http_addr = "0.0.0.0"; + http_addr = "127.0.0.1"; }; "auth.generic_oauth" = { enabled = true; @@ -72,10 +72,10 @@ in }; }; - services.nginx.virtualHosts."grafana.localho.st" = { + services.nginx.virtualHosts.${cfg.domain} = { locations."/" = { proxyWebsockets = true; - proxyPass = "http://127.0.0.1:${toString config.services.grafana.settings.server.http_port}/"; + proxyPass = "http://${config.services.grafana.settings.server.http_addr}:${toString config.services.grafana.settings.server.http_port}/"; }; }; }; diff --git a/tests/monitoring-auth.nix b/tests/monitoring-auth.nix index e1692dc..c3fe893 100644 --- a/tests/monitoring-auth.nix +++ b/tests/monitoring-auth.nix @@ -21,12 +21,17 @@ profiles.auth = { enable = true; + domain = "authentik.localho.st"; }; + + profiles.ingress.enable = true; + services.authentik.environmentFile = builtins.toFile "authentik-env-file" '' AUTHENTIK_SECRET_KEY=qwerty123456 AUTHENTIK_BOOTSTRAP_PASSWORD=password AUTHENTIK_BOOTSTRAP_TOKEN=token ''; + services.authentik.blueprints = [{ metadata.name = "grafana-oauth"; entries = [ @@ -53,7 +58,7 @@ sub_mode = "hashed_user_id"; include_claims_in_id_token = true; issuer_mode = "per_provider"; - redirect_uris = "http://localhost:3000/login/generic_oauth"; + redirect_uris = "http://grafana.localho.st/login/generic_oauth"; }; } { @@ -71,14 +76,15 @@ }]; profiles.monitoring = { enable = true; - domain = "localhost"; + domain = "grafana.localho.st"; + root_url = "%(protocol)s://%(domain)s/"; oauth = { name = "Authentik"; client_id_file = builtins.toFile "grafana-client-id" "grafana"; client_secret_file = builtins.toFile "grafana-client-secret" "secret"; - auth_url = "http://127.0.0.1:9000/application/o/authorize/"; - token_url = "http://127.0.0.1:9000/application/o/token/"; - api_url = "http://127.0.0.1:9000/application/o/userinfo/"; + auth_url = "http://authentik.localho.st/application/o/authorize/"; + token_url = "http://authentik.localho.st/application/o/token/"; + api_url = "http://authentik.localho.st/application/o/userinfo/"; }; }; }; @@ -86,33 +92,34 @@ extraPythonPackages = p: [ p.playwright ]; testScript = '' + import os + from playwright.sync_api import sync_playwright, expect + start_all() + machine.forward_port(80, 80) + with subtest("Wait for authentik services to start"): machine.wait_for_unit("postgresql.service") machine.wait_for_unit("redis-authentik.service") machine.wait_for_unit("authentik-migrate.service") machine.wait_for_unit("authentik-worker.service") machine.wait_for_unit("authentik.service") + machine.wait_for_unit("nginx.service") with subtest("Wait for Authentik itself to initialize"): machine.wait_for_open_port(9000) - machine.wait_until_succeeds("curl -fL http://localhost:9000/if/flow/initial-setup/ >&2") + machine.wait_until_succeeds("curl -fL http://authentik.localho.st/if/flow/initial-setup/ >&2") with subtest("Wait for Authentik blueprints to be applied"): - machine.wait_until_succeeds("curl -f http://localhost:9000/application/o/grafana/.well-known/openid-configuration >&2") - - machine.forward_port(3000, 3000) - machine.forward_port(9000, 9000) - - from playwright.sync_api import sync_playwright, expect + machine.wait_until_succeeds("curl -f http://authentik.localho.st/application/o/grafana/.well-known/openid-configuration >&2") with sync_playwright() as p: - browser = p.chromium.launch() + browser = p.chromium.launch(headless=os.environ.get("HEADLESS", "true") != "false") page = browser.new_page() with subtest("Login page"): - page.goto("http://localhost:3000/login") + page.goto("http://grafana.localho.st/login") page.reload() page.get_by_role("link", name="Sign in with Authentik").click() with subtest("Enter username"):