feat(alertmanager): UI behind Authelia, admin only; verify admin tools redirect to login #250

Merged
jfraeys merged 2 commits from jfraeys/fix/alertmanager-behind-authelia into main 2026-10-16 19:09:42 -04:00
Owner

Audit result (live + repo) of what should be behind Authelia:

  • Prometheus: bound to 127.0.0.1:9090; route prometheus.jfraeys.com with the authelia middleware and an admin-only access rule. Verified live: anonymous GET -> login.
  • Vaultwarden /admin: separate router with the authelia middleware plus ADMIN_TOKEN. Verified live: anonymous GET -> login.
  • Traefik dashboard: api.dashboard=true but no api@internal router and no published port. Unreachable.
  • Grafana: route has the authelia middleware and OIDC; disabled in production.
  • Loki: disabled; when enabled it is bound to 127.0.0.1:3100, has no UI and is called by Grafana/log shippers, so it stays unrouted (forward-auth would break its machine clients). If remote log shipping is ever needed, bind it to the tailnet and restrict by ACL.
  • Forgejo, Vaultwarden, Headscale: their own login/OIDC (public by design).
  • Alertmanager: THE GAP. UI published on the tailnet address with no login of its own.

Change: alertmanager_hostname (alertmanager.; the proxied wildcard already resolves it and Traefik issues the certificate by DNS-01) gets a Traefik route with the authelia middleware and is added to Authelia's admin-only domain list, like Prometheus. With a hostname no port is published and external-url becomes the https link. Unsetting it restores the old tailnet port. Prometheus reaches Alertmanager via alertmanager:9093 on the Docker network, so alert delivery is unaffected.

Tests: scripts/tests/test_admin_tools_authelia.py (8 cases rendering the real Traefik/Authelia/compose templates; removing the middleware makes two fail; in lint.yml). check-exposure.py gains login-redirect checks; run against production now: prometheus OK, vault /admin OK, alertmanager FAIL (526, no route yet), which is the gap.
Not checked: a real deploy and Authelia's own validation of this exact rendered config (the change is one extra entry in an existing domain list; staging brings Authelia up with it before promotion).

Deploy: staging, promotion, then ./infra deploy --tags traefik,authelia,alertmanager --limit services (Authelia and Alertmanager restart briefly; SSO is unavailable for a moment). Verify: python3 scripts/checks/check-exposure.py (all login checks OK), open https://alertmanager.jfraeys.com/ and sign in as an admin, and send a test alert to confirm the link in the notification works.
Follow-up once deployed: the services:9093 rule in the Headscale ACL (#246) is no longer needed and can be removed.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Ge5tovcwdEUBtPwUktsZZZ

Audit result (live + repo) of what should be behind Authelia: - Prometheus: bound to 127.0.0.1:9090; route prometheus.jfraeys.com with the authelia middleware and an admin-only access rule. Verified live: anonymous GET -> login. - Vaultwarden /admin: separate router with the authelia middleware plus ADMIN_TOKEN. Verified live: anonymous GET -> login. - Traefik dashboard: api.dashboard=true but no api@internal router and no published port. Unreachable. - Grafana: route has the authelia middleware and OIDC; disabled in production. - Loki: disabled; when enabled it is bound to 127.0.0.1:3100, has no UI and is called by Grafana/log shippers, so it stays unrouted (forward-auth would break its machine clients). If remote log shipping is ever needed, bind it to the tailnet and restrict by ACL. - Forgejo, Vaultwarden, Headscale: their own login/OIDC (public by design). - Alertmanager: THE GAP. UI published on the tailnet address with no login of its own. Change: alertmanager_hostname (alertmanager.<domain>; the proxied wildcard already resolves it and Traefik issues the certificate by DNS-01) gets a Traefik route with the authelia middleware and is added to Authelia's admin-only domain list, like Prometheus. With a hostname no port is published and external-url becomes the https link. Unsetting it restores the old tailnet port. Prometheus reaches Alertmanager via alertmanager:9093 on the Docker network, so alert delivery is unaffected. Tests: scripts/tests/test_admin_tools_authelia.py (8 cases rendering the real Traefik/Authelia/compose templates; removing the middleware makes two fail; in lint.yml). check-exposure.py gains login-redirect checks; run against production now: prometheus OK, vault /admin OK, alertmanager FAIL (526, no route yet), which is the gap. Not checked: a real deploy and Authelia's own validation of this exact rendered config (the change is one extra entry in an existing domain list; staging brings Authelia up with it before promotion). Deploy: staging, promotion, then ./infra deploy --tags traefik,authelia,alertmanager --limit services (Authelia and Alertmanager restart briefly; SSO is unavailable for a moment). Verify: python3 scripts/checks/check-exposure.py (all login checks OK), open https://alertmanager.jfraeys.com/ and sign in as an admin, and send a test alert to confirm the link in the notification works. Follow-up once deployed: the services:9093 rule in the Headscale ACL (#246) is no longer needed and can be removed. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01Ge5tovcwdEUBtPwUktsZZZ
feat(alertmanager): UI behind Authelia (admin only); check that admin tools redirect to the login
Some checks failed
Lint / lint (pull_request) Has started running
Secret scan / scan (pull_request) Has been cancelled
970057b14a
Alertmanager's UI had no login of its own and was published on the tailnet address. alertmanager_hostname (alertmanager.<domain>, covered by the proxied
wildcard) now routes through Traefik with the authelia middleware and the admin-only access rule, like Prometheus, and no port is published;
external-url becomes the https link so alert links work from a phone after login. Unsetting the hostname restores the tailnet port. Prometheus reaches
Alertmanager by container name, so delivery is unaffected.
Tests: test_admin_tools_authelia.py renders the real Traefik, Authelia and compose templates (every admin-tool route has the authelia middleware; the
only routes without it are authelia, demo, forgejo; alertmanager listed admin-only; no port when it has a hostname); removing the middleware fails it.
scripts/checks/check-exposure.py now also checks that prometheus, alertmanager and vault /admin send an anonymous visitor to the Authelia login
(Cloudflare 403s Python's default user agent; Authelia answers non-browsers with 401 + Location).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ge5tovcwdEUBtPwUktsZZZ
docs+ci: Alertmanager role notes match the new routing; run the admin-tools Authelia test in lint
All checks were successful
Lint / lint (pull_request) Successful in 2m31s
Secret scan / scan (pull_request) Successful in 18s
abd4cbd6ca
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ge5tovcwdEUBtPwUktsZZZ
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
jfraeys/infra!250
No description provided.