feat(garage,authentik): console multi-domain + standalone proxy outpost

Two related additions for gating a cross-host service (garage WebUI on a
storage host) behind authentik without breaking on TLS or X-Forwarded-Host:

garage role:
- Add garage_webui_domains (list), mirroring garage_s3_domains. The
  console router now accepts every entry, so a DMZ reverseproxy can use a
  backend_host whose cert SAN matches an internal *.int.* name instead of
  connecting by IP (which fails acme cert verification). Defaults to the
  single garage_webui_domain so existing inventories are unaffected.

authentik_outpost_proxy role (new):
- Standalone proxy (ForwardAuth) outpost, modelled on authentik_outpost_ldap.
  Co-locate it with the protected service so the ForwardAuth subrequest
  reaches authentik over the local docker network. The embedded outpost
  only works for services on the authentik host: a cross-host subrequest
  routed through an extra reverse-proxy hop arrives with a polluted
  X-Forwarded-Host (port/comma-appended), which the outpost no longer
  matches against the provider's external_host (404).
This commit is contained in:
Simon Bärlocher 2026-06-05 14:22:36 +02:00
parent a8954f525c
commit 0733d5710f
No known key found for this signature in database
GPG key ID: 63DE20495932047A
12 changed files with 195 additions and 2 deletions

View file

@ -20,7 +20,15 @@ garage_image: "dxflrs/garage:v2.1.0"
garage_s3_domains:
- "storage.local.test"
garage_web_domain: "web.storage.local.test"
# Canonical WebUI console hostname (first entry of garage_webui_domains).
garage_webui_domain: "console.storage.local.test"
# FQDNs the WebUI console router accepts. The first entry is the canonical
# public domain; further entries cover internal *.int.* names so a DMZ
# reverseproxy can use a backend_host whose cert SAN matches (same pattern
# as garage_s3_domains). Defaults to just the canonical domain so existing
# inventories that only set garage_webui_domain keep working unchanged.
garage_webui_domains:
- "{{ garage_webui_domain }}"
# Garage WebUI configuration
garage_webui_enabled: true

View file

@ -45,7 +45,16 @@ argument_specs:
garage_webui_domain:
type: str
default: console.storage.local.test
description: Hostname serving the WebUI console.
description: Canonical WebUI console hostname (first entry of C(garage_webui_domains)).
garage_webui_domains:
type: list
elements: str
default: ['console.storage.local.test']
description:
- FQDNs the WebUI console router accepts. The first entry is the
canonical public domain; further entries cover internal
C(*.int.*) names so a DMZ reverseproxy can use a C(backend_host)
whose cert SAN matches. Defaults to just C(garage_webui_domain).
garage_webui_enabled:
type: bool

View file

@ -49,7 +49,7 @@ services:
labels:
- traefik.enable=true
- traefik.docker.network={{ garage_traefik_network }}
- traefik.http.routers.{{ garage_service_name }}-console.rule=Host(`{{ garage_webui_domain }}`)
- traefik.http.routers.{{ garage_service_name }}-console.rule={% for d in garage_webui_domains %}Host(`{{ d }}`){% if not loop.last %} || {% endif %}{% endfor +%}
{% if garage_use_ssl %}
- traefik.http.routers.{{ garage_service_name }}-console.entrypoints=websecure
- traefik.http.routers.{{ garage_service_name }}-console.tls=true