feat(demo): add full inventories for mbazürich and phbern

Both demo sites had only a hosts.yml, so every role ran on its
defaults (authentik.local.test etc.) and nothing was reachable under
the real FQDN. Add the complete group_vars + host_vars analogous to
gymburgdorf, with the mbaz.souveredu.ch / phbe.souveredu.ch domain
bases, matching Bao mounts, DMZ split-horizon (public + *.int.*),
authentik OIDC/LDAP/proxy outposts, nextcloud with S3+LDAP+OIDC,
collabora, drawio, garage, send, opnform, homarr and bookstack.

authentik_domains lists the *.int.* name too so Traefik requests a
cert the DMZ can verify; the storage proxy outpost carries a config
block (required by the outpost blueprint serializer).
This commit is contained in:
Simon Bärlocher 2026-07-02 17:22:21 +02:00
parent a8c8ac3e1e
commit d45e358efc
No known key found for this signature in database
GPG key ID: 63DE20495932047A
44 changed files with 1458 additions and 10 deletions

View file

@ -0,0 +1,19 @@
---
# Proxy (ForwardAuth) outpost co-located with garage on storage. The
# garage-webui Traefik router's ForwardAuth middleware points at this
# container over the local `proxy` docker network, so the auth subrequest
# never leaves storage — the embedded outpost on the application host
# can't be used here because the cross-host hop mangles X-Forwarded-Host.
_authentik: "{{ lookup('community.hashi_vault.hashi_vault', vault_mount + '/data/authentik', url=vault_addr) }}"
# Outpost pulls its config from authentik over the public FQDN (resolves
# via the internal DNS view to the DMZ reverseproxy the storage subnet can
# reach). Token must match the storage-proxy-outpost registered in
# authentik (see application/authentik.yml authentik_proxy_outposts).
# Verify the authentik TLS chain: auth.phbe.* presents a valid Let's
# Encrypt cert via the reverseproxy and the storage subnet reaches it, so
# there's no reason to disable verification (verified: ssl_verify_result=0).
authentik_outpost_proxy_host: "https://auth.phbe.souveredu.ch"
authentik_outpost_proxy_token: "{{ _authentik.proxy_outpost_token }}"
authentik_outpost_proxy_insecure: "false"
authentik_outpost_proxy_network: "proxy"

View file

@ -0,0 +1,51 @@
---
# Bao secret <mount>/data/garage expected to contain:
# rpc_secret, admin_token, metrics_token, webui_password
_garage: "{{ lookup('community.hashi_vault.hashi_vault', vault_mount + '/data/garage', url=vault_addr) }}"
# First entry is the canonical public S3 FQDN. Additional entries
# cover internal *.int.* names so server-to-server S3 traffic (e.g.
# nextcloud → garage) stays in the LAN.
garage_s3_domains:
- "s3.phbe.souveredu.ch"
- "s3.int.phbe.souveredu.ch"
# First entry is the canonical public console FQDN. The *.int.* entry
# gives the DMZ a backend_host whose cert SAN matches (storage/traefik.yml),
# so the DMZ->storage hop verifies TLS instead of failing on a raw IP.
garage_webui_domains:
- "console.s3.phbe.souveredu.ch"
- "console.s3.int.phbe.souveredu.ch"
garage_use_ssl: true
garage_webui_enabled: true
# Gate the WebUI behind authentik (admins-only, via policy-binding on the
# authentik proxy app). Replaces the htpasswd Basic-Auth — AUTH_USER_PASS
# is dropped from the compose env when this is true.
#
# ForwardAuth talks to the storage-local proxy outpost over the docker
# network (role digitalboard.core.authentik_outpost_proxy). The embedded
# outpost on the application host can't be used cross-host: the extra
# reverseproxy hop mangles X-Forwarded-Host (appends :443 / a comma list)
# and the outpost then 404s instead of matching console.s3.* against the
# provider's external_host. A co-located outpost keeps the subrequest on
# the local network with a clean X-Forwarded-Host.
garage_webui_authentik_forward_auth: true
garage_webui_authentik_forward_auth_url: "http://authentik-outpost-proxy-proxy-1:9000/outpost.goauthentik.io/auth/traefik"
# Kept for completeness — only used when authentik ForwardAuth is off.
garage_webui_username: "admin"
garage_webui_password: "{{ _garage.webui_password | default('disabled') }}"
garage_rpc_secret: "{{ _garage.rpc_secret }}"
garage_admin_token: "{{ _garage.admin_token }}"
garage_metrics_token: "{{ _garage.metrics_token }}"
# Initial cluster bootstrap (single-node)
garage_bootstrap_enabled: true
garage_bootstrap_zone: "bern1"
garage_bootstrap_capacity: "100G"
# Buckets and keys consumed by nextcloud
garage_s3_keys:
- name: nextcloud
buckets:
- name: nextcloud
permissions: ["read", "write"]

View file

@ -0,0 +1,2 @@
---
# storage host runs: garage (S3 + WebUI)

View file

@ -0,0 +1,21 @@
---
# Services hosted on `storage` that the DMZ reverseproxy should forward
# public traffic to. See application/traefik.yml for the mechanism.
# The garage-webui ForwardAuth no longer needs an auth FQDN pinned here —
# it talks to the storage-local proxy outpost over the docker network
# (see garage.yml), and the outpost reaches authentik via the public FQDN
# over the reverseproxy (firewall now permits backend -> DMZ).
traefik_dmz_exposed_services:
- name: garage-s3
domain: s3.phbe.souveredu.ch
backend_host: s3.int.phbe.souveredu.ch
port: 443
protocol: https
- name: garage-webui
domain: console.s3.phbe.souveredu.ch
# Internal name so the DMZ verifies the storage backend cert against a
# matching SAN (acme cert_mode, no insecureSkipVerify). garage now
# serves this SAN via garage_webui_domains (see garage.yml).
backend_host: console.s3.int.phbe.souveredu.ch
port: 443
protocol: https