From ec03929d95fccd0db6b997371497f616af6a723b Mon Sep 17 00:00:00 2001 From: Frank Date: Mon, 31 Aug 2026 01:48:30 -0700 Subject: [PATCH] grafana: auth_proxy behind the Authentik guard chain MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Grafana leaves the exempt-by-construction set: grafana.franksdank.cloud now terminates at the Anubis guard (anubis:8923) and authenticated traffic returns at the internal :8017 listener, where an @grafana Host handler proxies through to grafana:3000 with the outpost-proxy trust token (GRAFANA_PROXY_TOKEN = client_id_client_secret of the new 'grafana-proxy' ProxyProvider on the embedded outpost; created via ak shell before this route flip — provider-first ordering per the External Exposure Policy). The Grafana admin account is intentionally kept: auth.proxy in auto-upsert mode only creates non-admin users, so the local admin remains the only way to administer Grafana. The old edge-basicauth wrapper is retired (shared family password, no per-user audit trail). - Caddyfile: grafana vhost flipped to the guarded chain; @grafana handler added at the :8017 return listener. - compose.yaml: GF_AUTH_PROXY_ENABLED/HEADERS/TOKEN on the grafana service (auth_proxy trusted-proxy CIDRs left at the image default — the proxying Caddy container is not statically addressable on 10.89.0.0/24, so Grafana trusts any in-network source and relies on the token as the capability). - .env.example: GRAFANA_PROXY_TOKEN placeholder so test env_consistency keeps guarding the compose<->env contract. --- dankclaw/.env.example | 16 +++++++++------- dankclaw/Caddyfile | 35 ++++++++++++++++++++++------------- dankclaw/compose.yaml | 10 ++++++++-- 3 files changed, 39 insertions(+), 22 deletions(-) diff --git a/dankclaw/.env.example b/dankclaw/.env.example index e7e2566..da213b4 100644 --- a/dankclaw/.env.example +++ b/dankclaw/.env.example @@ -20,16 +20,18 @@ WIREGUARD_PERSISTENT_KEEPALIVE_INTERVAL=25s # Gitea database GITEA_DB_PASSWORD=changeme -# Grafana admin -GRAFANA_ADMIN_USER=admin -GRAFANA_ADMIN_PASSWORD=changeme +# Grafana auth-proxy trust token. The outpost proxy provider 'grafana-proxy' +# forwards authenticated traffic to Grafana with Authorization: Bearer +# _; the live .env must set this to that exact +# concatenation (provider created via ak shell on authentik-server). +GRAFANA_PROXY_TOKEN=changeme # Caddy (the homelab's single reverse proxy, on this host) # bcrypt hash (caddy hash-password). deploy.sh renders it into -# /home/dank/Containers/caddy/Caddyfile. -# CADDY_BASICAUTH_HASH: the shared family password, still used by the -# vhosts that carry basicauth rather than Authentik forward_auth -# (grafana, pihole). Username: dankuser. +# /home/dank/Containers/caddy/Caddyfile, which the container mounts. +# CADDY_BASICAUTH_HASH: the shared family password, now used only by the +# pihole vhost (grafana moved behind the Authentik guard chain 2026-09-01). +# Username: dankuser. CADDY_BASICAUTH_HASH=changeme # (The homepage's per-user hashes were retired: the homepage and its /admin/ # page are now behind Authentik forward_auth, not basicauth.) diff --git a/dankclaw/Caddyfile b/dankclaw/Caddyfile index 6445ee9..c019d5d 100644 --- a/dankclaw/Caddyfile +++ b/dankclaw/Caddyfile @@ -22,15 +22,16 @@ # CHALLENGE everyone else) → Caddy's internal listener http://:8016 (auth # decision; Host headers survive every hop) → authenticated traffic is # forwarded back to http://:8017 and routed straight to the app. -# Apps with their own auth (Grafana, Gitea, OpenWebUI, Jellyfin, *arr, Pi-hole) -# and the Authentik IdP itself (auth.franksdank.cloud — its login flow must never -# sit behind a challenge) are exempt by construction: their vhosts never route -# through Anubis. ComfyUI left this exempt set on 2026-08-31: it now sits behind -# the guard chain with the comfyui-proxy provider registered on the embedded outpost. -# their vhosts never route through Anubis. The basicauth hash is a -# placeholder; deploy.sh renders the real hash (CADDY_BASICAUTH_HASH from the -# host .env, git-ignored) into /home/dank/Containers/caddy/Caddyfile, which -# the container mounts. +# Apps with their own auth (Gitea, OpenWebUI, Jellyfin, *arr, Pi-hole) and the +# Authentik IdP itself (auth.franksdank.cloud — its login flow must never sit +# behind a challenge) are exempt by construction: their vhosts never route +# through Anubis. ComfyUI left this exempt set on 2026-08-31 and Grafana left +# it on 2026-09-01 (auth_proxy mode; the outpost proxies authenticated traffic +# through to it): both now sit behind the guard chain with their proxy +# providers registered on the embedded outpost. +# The pihole vhost keeps its basicauth edge; the hash placeholder below is +# rendered by deploy.sh from CADDY_BASICAUTH_HASH (host .env, git-ignored) into +# /home/dank/Containers/caddy/Caddyfile, which the container mounts. # # TLS: real Let's Encrypt certs. Site addresses carry no http:// prefix, # so Caddy serves HTTPS (and auto-redirects HTTP). Certs are issued via @@ -132,12 +133,15 @@ gitea.franksdank.cloud { reverse_proxy 192.168.0.143:3000 } -# --- Grafana --- +# --- Grafana (guarded: Anubis → Authentik; grafana-proxy provider, auth_proxy mode) --- +# Authenticated traffic returns at the internal :8017 listener and is proxied +# through by the outpost with Authorization: Bearer _; +# Grafana's auth.proxy trusts that token and auto-upserts a user per login. +# The basicauth edge this replaces (CADDY_BASICAUTH_HASH) is retired. grafana.franksdank.cloud { - basicauth { - dankuser REPLACE_WITH_HASH + reverse_proxy anubis:8923 { + header_up X-Real-Ip {remote_host} } - reverse_proxy grafana:3000 } # --- Prometheus --- @@ -302,6 +306,11 @@ http://:8017 { reverse_proxy loki:3100 } + @grafana host grafana.franksdank.cloud + handle @grafana { + reverse_proxy grafana:3000 + } + @prometheus host prometheus.franksdank.cloud handle @prometheus { reverse_proxy prometheus:9090 diff --git a/dankclaw/compose.yaml b/dankclaw/compose.yaml index 5c5f7b8..9bcfffa 100644 --- a/dankclaw/compose.yaml +++ b/dankclaw/compose.yaml @@ -177,8 +177,14 @@ services: user: "0:0" environment: GF_SERVER_ROOT_URL: "https://grafana.franksdank.cloud" - GF_SECURITY_ADMIN_USER: "${GRAFANA_ADMIN_USER}" - GF_SECURITY_ADMIN_PASSWORD: "${GRAFANA_ADMIN_PASSWORD}" + # Auth proxy mode: the authentik embedded outpost proxies authenticated + # traffic through with Authorization: Bearer _ + # (the grafana-proxy provider on the outpost). The token lives in the + # host .env (never committed); auto-upsert maps each authenticated + # authentik user to a Grafana user by email, default role Viewer. + GF_AUTH_PROXY_ENABLED: "true" + GF_AUTH_PROXY_HEADERS: "name Auth;logo https://grafana.franksdank.cloud/public/img/login-app-logo.png;auto-upsert" + GF_AUTH_PROXY_TOKEN: "${GRAFANA_PROXY_TOKEN}" ports: - "3002:3000" volumes: