Compare commits
No commits in common. "d45e358efcb2dd0f50db8a8ba5ee070eb8a889fd" and "2206b809e7cd18f2553c085533f4790aa9157ea3" have entirely different histories.
d45e358efc
...
2206b809e7
56 changed files with 129 additions and 1582 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
---
|
---
|
||||||
# Bao secret expected at <mount>/data/authentik with keys:
|
# Bao secret expected at <mount>/data/authentik with keys:
|
||||||
# secret_key, postgres_password, admin_password,
|
# secret_key, postgres_password, admin_password,
|
||||||
# ldap_outpost_token, proxy_outpost_token,
|
# ldap_outpost_token,
|
||||||
# nextcloud_oidc_secret,
|
# nextcloud_oidc_secret,
|
||||||
# opnform_oidc_secret, homarr_oidc_secret, bookstack_oidc_secret
|
# opnform_oidc_secret, homarr_oidc_secret, bookstack_oidc_secret
|
||||||
_authentik: "{{ lookup('community.hashi_vault.hashi_vault', vault_mount + '/data/authentik', url=vault_addr) }}"
|
_authentik: "{{ lookup('community.hashi_vault.hashi_vault', vault_mount + '/data/authentik', url=vault_addr) }}"
|
||||||
|
|
@ -10,9 +10,26 @@ _authentik: "{{ lookup('community.hashi_vault.hashi_vault', vault_mount + '/data
|
||||||
authentik_domains:
|
authentik_domains:
|
||||||
- "auth.gymb.souveredu.ch"
|
- "auth.gymb.souveredu.ch"
|
||||||
|
|
||||||
|
# Internal FQDN for server-to-server calls (Nextcloud OIDC discovery,
|
||||||
|
# token, userinfo; LDAP outpost configuration pull). Traefik rewrites
|
||||||
|
# the Host header to `authentik_domains[0]` on these routers so authentik
|
||||||
|
# still emits issuer URLs against the public hostname — that keeps the
|
||||||
|
# iss claim matching what the browser sees while the traffic itself
|
||||||
|
# stays inside the LAN (the DMZ has no hairpin-NAT for the public IP).
|
||||||
|
authentik_host_rewrite_domains:
|
||||||
|
- "auth.int.gymb.souveredu.ch"
|
||||||
authentik_secret_key: "{{ _authentik.secret_key }}"
|
authentik_secret_key: "{{ _authentik.secret_key }}"
|
||||||
authentik_postgres_password: "{{ _authentik.postgres_password }}"
|
authentik_postgres_password: "{{ _authentik.postgres_password }}"
|
||||||
|
|
||||||
|
# Dedicated FQDN for cross-host ForwardAuth (storage Traefik calling
|
||||||
|
# /outpost.goauthentik.io/auth/traefik). Routing through the public
|
||||||
|
# auth.gymb.* FQDN doesn't work — Authentik sees Host: auth.gymb.* and
|
||||||
|
# routes to ASGI which 404s the outpost path. This FQDN sits outside
|
||||||
|
# authentik_domains so the same request falls through to the embedded
|
||||||
|
# outpost handler (which matches the protected app via X-Forwarded-Host).
|
||||||
|
authentik_outpost_domains:
|
||||||
|
- "outpost.auth.int.gymb.souveredu.ch"
|
||||||
|
|
||||||
# LDAP outpost (provider for nextcloud)
|
# LDAP outpost (provider for nextcloud)
|
||||||
authentik_ldap_apps:
|
authentik_ldap_apps:
|
||||||
- slug: ldap
|
- slug: ldap
|
||||||
|
|
@ -24,10 +41,9 @@ authentik_ldap_outpost:
|
||||||
name: "ldap-outpost"
|
name: "ldap-outpost"
|
||||||
token: "{{ _authentik.ldap_outpost_token }}"
|
token: "{{ _authentik.ldap_outpost_token }}"
|
||||||
config:
|
config:
|
||||||
# Outpost pulls config from authentik over the public FQDN, which
|
# Outpost pulls config from authentik over the internal FQDN — keeps
|
||||||
# resolves (internal DNS view) to the DMZ reverseproxy the backend
|
# the round-trip in the LAN with a valid cert.
|
||||||
# subnet can reach — keeps the round-trip in the LAN with a valid cert.
|
authentik_host: "https://auth.int.gymb.souveredu.ch/"
|
||||||
authentik_host: "https://auth.gymb.souveredu.ch/"
|
|
||||||
log_level: "info"
|
log_level: "info"
|
||||||
|
|
||||||
# Proxy providers (ForwardAuth) — gate downstream services behind
|
# Proxy providers (ForwardAuth) — gate downstream services behind
|
||||||
|
|
@ -63,25 +79,15 @@ authentik_proxy_apps:
|
||||||
authorization_slug: default-provider-authorization-implicit-consent
|
authorization_slug: default-provider-authorization-implicit-consent
|
||||||
invalidation_slug: default-provider-invalidation-flow
|
invalidation_slug: default-provider-invalidation-flow
|
||||||
|
|
||||||
# Outpost bindings. drawio runs on this (application) host, so its
|
# Bind both proxy providers to authentik's built-in embedded outpost so
|
||||||
# ForwardAuth can use the embedded outpost (same host:9000 as the
|
# we don't have to deploy a separate proxy outpost container. The
|
||||||
# authentik server). garage-webui runs on the storage host; a cross-host
|
# embedded outpost listens on the same host:9000 as the authentik server
|
||||||
# ForwardAuth to the embedded outpost arrives with a mangled
|
# and exposes /outpost.goauthentik.io/auth/traefik for ForwardAuth.
|
||||||
# X-Forwarded-Host (an extra reverseproxy hop appends :443 / a comma list)
|
|
||||||
# and the outpost then fails to match the provider's external_host (404).
|
|
||||||
# So garage-webui is bound to a dedicated proxy outpost deployed on
|
|
||||||
# storage (role digitalboard.core.authentik_outpost_proxy), whose
|
|
||||||
# ForwardAuth endpoint the local storage Traefik reaches over the docker
|
|
||||||
# network — no extra hop, clean X-Forwarded-Host.
|
|
||||||
authentik_proxy_outposts:
|
authentik_proxy_outposts:
|
||||||
- name: "authentik Embedded Outpost"
|
- name: "authentik Embedded Outpost"
|
||||||
type: proxy
|
type: proxy
|
||||||
providers:
|
providers:
|
||||||
- drawio
|
- drawio
|
||||||
- name: "storage-proxy-outpost"
|
|
||||||
type: proxy
|
|
||||||
token: "{{ _authentik.proxy_outpost_token }}"
|
|
||||||
providers:
|
|
||||||
- garage-webui
|
- garage-webui
|
||||||
|
|
||||||
# OIDC clients
|
# OIDC clients
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,5 @@
|
||||||
# authenticate against the authentik server it talks to.
|
# authenticate against the authentik server it talks to.
|
||||||
_authentik: "{{ lookup('community.hashi_vault.hashi_vault', vault_mount + '/data/authentik', url=vault_addr) }}"
|
_authentik: "{{ lookup('community.hashi_vault.hashi_vault', vault_mount + '/data/authentik', url=vault_addr) }}"
|
||||||
|
|
||||||
# Public FQDN resolves (internal DNS view) to the DMZ reverseproxy the
|
authentik_outpost_ldap_host: "https://auth.int.gymb.souveredu.ch"
|
||||||
# backend subnet can reach, so the outpost->authentik round-trip stays in
|
|
||||||
# the LAN with a valid cert and matches the iss claim authentik emits.
|
|
||||||
authentik_outpost_ldap_host: "https://auth.gymb.souveredu.ch"
|
|
||||||
authentik_outpost_ldap_token: "{{ _authentik.ldap_outpost_token }}"
|
authentik_outpost_ldap_token: "{{ _authentik.ldap_outpost_token }}"
|
||||||
# auth.gymb.* presents a valid Let's Encrypt cert via the reverseproxy, so
|
|
||||||
# verify the chain instead of relying on the role's insecure default.
|
|
||||||
authentik_outpost_ldap_insecure: "false"
|
|
||||||
|
|
|
||||||
|
|
@ -20,11 +20,11 @@ bookstack_admin_email: "admin@gymb.souveredu.ch"
|
||||||
bookstack_admin_name: "BookStack Admin"
|
bookstack_admin_name: "BookStack Admin"
|
||||||
|
|
||||||
# OIDC against Authentik. BookStack compares OIDC_ISSUER strictly against
|
# OIDC against Authentik. BookStack compares OIDC_ISSUER strictly against
|
||||||
# the `iss` claim in the discovery response, and Authentik emits the
|
# the `iss` claim in the discovery response. Authentik emits the public
|
||||||
# public auth.gymb.* hostname there, so the issuer must use the public
|
# auth.gymb.* hostname there (host-rewrite middleware ensures the claim
|
||||||
# FQDN. That FQDN resolves (internal DNS view) to the DMZ reverseproxy,
|
# matches what browsers see during login), so the issuer URL must use the
|
||||||
# which the backend subnet can reach, so the server-to-server calls stay
|
# public FQDN. Pinning auth.gymb.* in /etc/hosts below keeps the actual
|
||||||
# in the LAN.
|
# server-to-server traffic on the LAN.
|
||||||
bookstack_oidc_enabled: true
|
bookstack_oidc_enabled: true
|
||||||
bookstack_oidc_name: "Authentik"
|
bookstack_oidc_name: "Authentik"
|
||||||
bookstack_oidc_issuer: "https://auth.gymb.souveredu.ch/application/o/bookstack/"
|
bookstack_oidc_issuer: "https://auth.gymb.souveredu.ch/application/o/bookstack/"
|
||||||
|
|
@ -34,3 +34,10 @@ bookstack_oidc_additional_scopes: "openid profile email"
|
||||||
bookstack_oidc_user_to_groups: true
|
bookstack_oidc_user_to_groups: true
|
||||||
bookstack_oidc_groups_claim: "groups"
|
bookstack_oidc_groups_claim: "groups"
|
||||||
bookstack_oidc_auto_initiate: false
|
bookstack_oidc_auto_initiate: false
|
||||||
|
|
||||||
|
# Pin auth.gymb.* to the application host so server-to-server OIDC calls
|
||||||
|
# (discovery, token, userinfo, jwks) stay in the LAN and reach authentik
|
||||||
|
# directly without hairpinning through the DMZ (which has no NAT loop
|
||||||
|
# back to its own public IP).
|
||||||
|
bookstack_extra_hosts:
|
||||||
|
- "auth.gymb.souveredu.ch:172.16.19.101"
|
||||||
|
|
|
||||||
|
|
@ -18,11 +18,12 @@ homarr_admin_password: "{{ _homarr.admin_password }}"
|
||||||
# AUTH_OIDC_AUTO_LOGIN bypasses the normal /login page.
|
# AUTH_OIDC_AUTO_LOGIN bypasses the normal /login page.
|
||||||
#
|
#
|
||||||
# Issuer must match the `iss` claim authentik emits, which is always the
|
# Issuer must match the `iss` claim authentik emits, which is always the
|
||||||
# public FQDN. Homarr (oauth4webapi) does a strict 1:1 comparison between
|
# public FQDN (authentik's host-rewrite middleware aligns the claim with
|
||||||
# the discovery response's issuer and this URL — an internal FQDN here
|
# what browsers see). Homarr (oauth4webapi) does a strict 1:1 comparison
|
||||||
# fails with OAUTH_JSON_ATTRIBUTE_COMPARISON_FAILED. The public FQDN
|
# between the discovery response's issuer and this URL — using the
|
||||||
# resolves (internal DNS view) to the DMZ reverseproxy, which the backend
|
# internal FQDN here fails with OAUTH_JSON_ATTRIBUTE_COMPARISON_FAILED.
|
||||||
# subnet can reach, so discovery/token/userinfo stay in the LAN.
|
# The extra_hosts pin below keeps the actual discovery/token/userinfo
|
||||||
|
# traffic on the LAN.
|
||||||
homarr_auth_providers: "credentials,oidc"
|
homarr_auth_providers: "credentials,oidc"
|
||||||
homarr_oidc_issuer: "https://auth.gymb.souveredu.ch/application/o/homarr/"
|
homarr_oidc_issuer: "https://auth.gymb.souveredu.ch/application/o/homarr/"
|
||||||
homarr_oidc_client_id: "homarr"
|
homarr_oidc_client_id: "homarr"
|
||||||
|
|
@ -32,6 +33,14 @@ homarr_oidc_scopes: "openid profile email groups"
|
||||||
homarr_oidc_groups_attribute: "groups"
|
homarr_oidc_groups_attribute: "groups"
|
||||||
homarr_oidc_auto_login: "true"
|
homarr_oidc_auto_login: "true"
|
||||||
|
|
||||||
|
# Pin the public authentik FQDN to the application host so OIDC
|
||||||
|
# discovery (and downstream token/userinfo) calls from the homarr
|
||||||
|
# container stay in the LAN. Without this, fetch() to auth.gymb.* would
|
||||||
|
# hit the public IP and time out in the DMZ (no hairpin-NAT). Same
|
||||||
|
# pattern as nextcloud_extra_hosts.
|
||||||
|
homarr_extra_hosts:
|
||||||
|
- "auth.gymb.souveredu.ch:172.16.19.101"
|
||||||
|
|
||||||
# Default board with shortcuts to the other gymburgdorf services. Width
|
# Default board with shortcuts to the other gymburgdorf services. Width
|
||||||
# values describe horizontal grid cells (1-10 desktop / 6 tablet / 2
|
# values describe horizontal grid cells (1-10 desktop / 6 tablet / 2
|
||||||
# mobile, packed left-to-right).
|
# mobile, packed left-to-right).
|
||||||
|
|
|
||||||
|
|
@ -62,16 +62,25 @@ nextcloud_s3_port: 443
|
||||||
nextcloud_s3_ssl: true
|
nextcloud_s3_ssl: true
|
||||||
nextcloud_s3_usepath_style: true
|
nextcloud_s3_usepath_style: true
|
||||||
|
|
||||||
# OIDC discovery/token/userinfo and the S3 backend both target FQDNs
|
# OIDC server-to-server discovery / token / userinfo goes to
|
||||||
# that resolve to RFC1918 addresses (auth.gymb.* via the reverseproxy,
|
# auth.int.gymb.souveredu.ch (LAN, RFC1918). Nextcloud's DnsPinMiddleware
|
||||||
# s3.int.* directly), which Nextcloud's DnsPinMiddleware would otherwise
|
# would otherwise block that as "local server access".
|
||||||
# block as "local server access".
|
|
||||||
nextcloud_allow_local_remote_servers: true
|
nextcloud_allow_local_remote_servers: true
|
||||||
|
|
||||||
# Share the LDAP docker network with the authentik LDAP outpost
|
# Share the LDAP docker network with the authentik LDAP outpost
|
||||||
nextcloud_extra_networks:
|
nextcloud_extra_networks:
|
||||||
- ldap
|
- ldap
|
||||||
|
|
||||||
|
# Pin the public authentik FQDN to the application host so server-to-server
|
||||||
|
# OIDC traffic (token, userinfo, jwks — endpoints the discovery doc lists
|
||||||
|
# under auth.gymb.* even when discovery itself is fetched via auth.int.*)
|
||||||
|
# stays in the LAN. Without this, curl in the PHP container would hit the
|
||||||
|
# public IP and time out in the DMZ (no hairpin-NAT). The DnsPin middleware
|
||||||
|
# only honours /etc/hosts when allow_local_remote_servers is enabled, so
|
||||||
|
# that flag (set above) is what makes this entry effective.
|
||||||
|
nextcloud_extra_hosts:
|
||||||
|
- "auth.gymb.souveredu.ch:172.16.19.101"
|
||||||
|
|
||||||
# LDAP backend (Authentik LDAP outpost)
|
# LDAP backend (Authentik LDAP outpost)
|
||||||
nextcloud_ldap_enabled: true
|
nextcloud_ldap_enabled: true
|
||||||
nextcloud_ldap_config:
|
nextcloud_ldap_config:
|
||||||
|
|
@ -109,12 +118,13 @@ nextcloud_oidc_providers:
|
||||||
display_name: "Login with Authentik"
|
display_name: "Login with Authentik"
|
||||||
client_id: nextcloud
|
client_id: nextcloud
|
||||||
client_secret: "{{ _authentik.nextcloud_oidc_secret }}"
|
client_secret: "{{ _authentik.nextcloud_oidc_secret }}"
|
||||||
# Discovery via the public FQDN. It resolves (internal DNS view) to
|
# Discovery via the internal FQDN (LAN-only) — the DMZ has no
|
||||||
# the DMZ reverseproxy, which the backend subnet can now reach, so
|
# hairpin-NAT for the public IP, so server-to-server calls to
|
||||||
# the server-to-server call stays in the LAN while the iss claim and
|
# auth.gymb.* would time out. The traefik router for auth.int.*
|
||||||
# all listed endpoints match the public hostname the browser sees
|
# rewrites the Host header to auth.gymb.souveredu.ch before the
|
||||||
# during login — no host-rewrite or /etc/hosts pin needed.
|
# request reaches authentik, so the iss claim authentik emits still
|
||||||
discovery_url: "https://auth.gymb.souveredu.ch/application/o/nextcloud/.well-known/openid-configuration"
|
# matches the public hostname the browser sees during login.
|
||||||
|
discovery_url: "https://auth.int.gymb.souveredu.ch/application/o/nextcloud/.well-known/openid-configuration"
|
||||||
scope: "openid email profile"
|
scope: "openid email profile"
|
||||||
unique_uid: true
|
unique_uid: true
|
||||||
mapping:
|
mapping:
|
||||||
|
|
|
||||||
|
|
@ -23,13 +23,18 @@ opnform_admin_name: "OpnForm Admin"
|
||||||
opnform_admin_email: "admin@gymb.souveredu.ch"
|
opnform_admin_email: "admin@gymb.souveredu.ch"
|
||||||
opnform_admin_password: "{{ _opnform.admin_password }}"
|
opnform_admin_password: "{{ _opnform.admin_password }}"
|
||||||
|
|
||||||
# OIDC against Authentik. The public auth.gymb.* FQDN resolves (internal
|
# OIDC against Authentik. Discovery via the internal FQDN keeps
|
||||||
# DNS view) to the DMZ reverseproxy, which the backend subnet can reach,
|
# server-to-server traffic in the LAN; Authentik's host-rewrite router
|
||||||
# so OpnForm's discovery/token/userinfo calls stay in the LAN while the
|
# rewrites the Host header to auth.gymb.* before the request reaches
|
||||||
# iss claim matches the public hostname browsers see during login.
|
# authentik so the iss claim still matches the public hostname browsers
|
||||||
|
# see during login.
|
||||||
opnform_oidc_enabled: true
|
opnform_oidc_enabled: true
|
||||||
# Issuer must use the public FQDN: OpnForm validates the token's `iss`
|
# Issuer must use the public auth.gymb.* FQDN: OpnForm does OIDC
|
||||||
# claim against this value, and Authentik emits the public hostname there.
|
# discovery and then validates the token's `iss` claim against this
|
||||||
|
# value. Authentik emits the public hostname in `iss` (its host-rewrite
|
||||||
|
# middleware keeps the claim aligned with what browsers see), so an
|
||||||
|
# internal-FQDN issuer here would fail iss validation. The extra_hosts
|
||||||
|
# pin below keeps the actual discovery/token/userinfo traffic on the LAN.
|
||||||
opnform_oidc_issuer: "https://auth.gymb.souveredu.ch/application/o/opnform/"
|
opnform_oidc_issuer: "https://auth.gymb.souveredu.ch/application/o/opnform/"
|
||||||
opnform_oidc_client_id: "opnform"
|
opnform_oidc_client_id: "opnform"
|
||||||
opnform_oidc_client_secret: "{{ _opnform.oidc_client_secret }}"
|
opnform_oidc_client_secret: "{{ _opnform.oidc_client_secret }}"
|
||||||
|
|
@ -48,3 +53,10 @@ opnform_oidc_force_login: true
|
||||||
# Break-glass: /login?bypass=1 reaches the email form when the IdP is
|
# Break-glass: /login?bypass=1 reaches the email form when the IdP is
|
||||||
# down.
|
# down.
|
||||||
opnform_oidc_sso_entrypoint: true
|
opnform_oidc_sso_entrypoint: true
|
||||||
|
|
||||||
|
# Pin auth.gymb.* to the application host so server-to-server OIDC
|
||||||
|
# calls (token, userinfo, jwks — endpoints discovery returns under the
|
||||||
|
# public hostname even when discovery itself is fetched via auth.int.*)
|
||||||
|
# stay in the LAN.
|
||||||
|
opnform_extra_hosts:
|
||||||
|
- "auth.gymb.souveredu.ch:172.16.19.101"
|
||||||
|
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
---
|
|
||||||
# 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.gymb.* 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.gymb.souveredu.ch"
|
|
||||||
authentik_outpost_proxy_token: "{{ _authentik.proxy_outpost_token }}"
|
|
||||||
authentik_outpost_proxy_insecure: "false"
|
|
||||||
authentik_outpost_proxy_network: "proxy"
|
|
||||||
|
|
@ -9,27 +9,22 @@ _garage: "{{ lookup('community.hashi_vault.hashi_vault', vault_mount + '/data/ga
|
||||||
garage_s3_domains:
|
garage_s3_domains:
|
||||||
- "s3.gymb.souveredu.ch"
|
- "s3.gymb.souveredu.ch"
|
||||||
- "s3.int.gymb.souveredu.ch"
|
- "s3.int.gymb.souveredu.ch"
|
||||||
# First entry is the canonical public console FQDN. The *.int.* entry
|
garage_webui_domain: "console.s3.gymb.souveredu.ch"
|
||||||
# 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.gymb.souveredu.ch"
|
|
||||||
- "console.s3.int.gymb.souveredu.ch"
|
|
||||||
garage_use_ssl: true
|
garage_use_ssl: true
|
||||||
garage_webui_enabled: true
|
garage_webui_enabled: true
|
||||||
# Gate the WebUI behind authentik (admins-only, via policy-binding on the
|
# Gate the WebUI behind authentik (admins-only, via policy-binding on the
|
||||||
# authentik proxy app). Replaces the htpasswd Basic-Auth — AUTH_USER_PASS
|
# authentik proxy app). Replaces the htpasswd Basic-Auth — AUTH_USER_PASS
|
||||||
# is dropped from the compose env when this is true.
|
# is dropped from the compose env when this is true. The forwardauth URL
|
||||||
#
|
# uses a dedicated outpost-only FQDN that's deliberately outside
|
||||||
# ForwardAuth talks to the storage-local proxy outpost over the docker
|
# authentik_domains so Authentik routes it to the embedded outpost (not
|
||||||
# network (role digitalboard.core.authentik_outpost_proxy). The embedded
|
# ASGI). The public auth.gymb.* FQDN would 404 here — Authentik routes
|
||||||
# outpost on the application host can't be used cross-host: the extra
|
# any Host matching an auth-domain to ASGI which doesn't serve the outpost
|
||||||
# reverseproxy hop mangles X-Forwarded-Host (appends :443 / a comma list)
|
# path. The outpost itself then matches the protected app via
|
||||||
# and the outpost then 404s instead of matching console.s3.* against the
|
# X-Forwarded-Host (Traefik forwards it via trustForwardHeader=true).
|
||||||
# provider's external_host. A co-located outpost keeps the subrequest on
|
# The FQDN is pinned to the application host via traefik_extra_hosts so
|
||||||
# the local network with a clean X-Forwarded-Host.
|
# the request stays in the LAN.
|
||||||
garage_webui_authentik_forward_auth: true
|
garage_webui_authentik_forward_auth: true
|
||||||
garage_webui_authentik_forward_auth_url: "http://authentik-outpost-proxy-proxy-1:9000/outpost.goauthentik.io/auth/traefik"
|
garage_webui_authentik_forward_auth_url: "https://outpost.auth.int.gymb.souveredu.ch/outpost.goauthentik.io/auth/traefik"
|
||||||
# Kept for completeness — only used when authentik ForwardAuth is off.
|
# Kept for completeness — only used when authentik ForwardAuth is off.
|
||||||
garage_webui_username: "admin"
|
garage_webui_username: "admin"
|
||||||
garage_webui_password: "{{ _garage.webui_password | default('disabled') }}"
|
garage_webui_password: "{{ _garage.webui_password | default('disabled') }}"
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,21 @@
|
||||||
---
|
---
|
||||||
|
# Local traefik needs to reach authentik for the ForwardAuth subrequest
|
||||||
|
# the garage-webui router fires. The public IP is unreachable from this
|
||||||
|
# subnet (no DMZ hairpin), so pin both auth FQDNs directly at the
|
||||||
|
# application host where authentik runs. Without this the forwardauth
|
||||||
|
# middleware would time out and every garage-console request would 502.
|
||||||
|
# - auth.gymb.* covers any future server-to-server traffic on the public
|
||||||
|
# FQDN.
|
||||||
|
# - outpost.auth.int.gymb.* is the dedicated outpost endpoint actually
|
||||||
|
# used by the ForwardAuth middleware (see garage.yml). It exists only
|
||||||
|
# to skip Authentik's ASGI handler, which 404s the outpost path when
|
||||||
|
# Host is one of the configured authentik_domains.
|
||||||
|
traefik_extra_hosts:
|
||||||
|
- "auth.gymb.souveredu.ch:172.16.19.101"
|
||||||
|
- "outpost.auth.int.gymb.souveredu.ch:172.16.19.101"
|
||||||
|
|
||||||
# Services hosted on `storage` that the DMZ reverseproxy should forward
|
# Services hosted on `storage` that the DMZ reverseproxy should forward
|
||||||
# public traffic to. See application/traefik.yml for the mechanism.
|
# 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:
|
traefik_dmz_exposed_services:
|
||||||
- name: garage-s3
|
- name: garage-s3
|
||||||
domain: s3.gymb.souveredu.ch
|
domain: s3.gymb.souveredu.ch
|
||||||
|
|
@ -13,9 +24,8 @@ traefik_dmz_exposed_services:
|
||||||
protocol: https
|
protocol: https
|
||||||
- name: garage-webui
|
- name: garage-webui
|
||||||
domain: console.s3.gymb.souveredu.ch
|
domain: console.s3.gymb.souveredu.ch
|
||||||
# Internal name so the DMZ verifies the storage backend cert against a
|
# No internal FQDN/cert SAN for console.s3 yet — would need an
|
||||||
# matching SAN (acme cert_mode, no insecureSkipVerify). garage now
|
# extra_domain on garage-webui. Until then this route will 500
|
||||||
# serves this SAN via garage_webui_domains (see garage.yml).
|
# against the storage backend (cert mismatch on raw IP).
|
||||||
backend_host: console.s3.int.gymb.souveredu.ch
|
|
||||||
port: 443
|
port: 443
|
||||||
protocol: https
|
protocol: https
|
||||||
|
|
|
||||||
|
|
@ -48,14 +48,6 @@ all:
|
||||||
hosts:
|
hosts:
|
||||||
application:
|
application:
|
||||||
|
|
||||||
# Proxy (ForwardAuth) outpost co-located with garage on storage, so
|
|
||||||
# the garage-webui ForwardAuth subrequest stays on the local docker
|
|
||||||
# network instead of crossing an extra reverseproxy hop (which mangles
|
|
||||||
# X-Forwarded-Host and breaks the embedded outpost's app matching).
|
|
||||||
authentik_outpost_proxy_servers:
|
|
||||||
hosts:
|
|
||||||
storage:
|
|
||||||
|
|
||||||
send_servers:
|
send_servers:
|
||||||
hosts:
|
hosts:
|
||||||
application:
|
application:
|
||||||
|
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
---
|
|
||||||
ansible_python_interpreter: /usr/bin/python3
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
docker_registry_mirrors: ["https://registry-mirror.wksbern.ch"]
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
vault_addr: "https://bao.digitalboard.ch"
|
|
||||||
vault_mount: "demo-mbazürich"
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
traefik_mode: backend
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
_acme_tsig: "{{ lookup('community.hashi_vault.hashi_vault', vault_mount + '/data/acme-tsig', url=vault_addr ) }}"
|
|
||||||
|
|
||||||
traefik_use_ssl: true
|
|
||||||
traefik_cert_mode: "acme"
|
|
||||||
traefik_ssl_email: "hostmaster@digitalboard.ch"
|
|
||||||
traefik_log_level: DEBUG
|
|
||||||
traefik_network: proxy
|
|
||||||
|
|
||||||
traefik_acme_dns_zone: "demo-mbaz._acme.digitalboard.ch"
|
|
||||||
traefik_acme_dns_nameserver: "{{ _acme_tsig.server }}"
|
|
||||||
traefik_acme_tsig_algorithm: "hmac-sha256"
|
|
||||||
traefik_acme_tsig_key: "{{ _acme_tsig.tsig_key }}"
|
|
||||||
traefik_acme_tsig_secret: "{{ _acme_tsig.tsig_secret }}"
|
|
||||||
|
|
||||||
# UDP/53 egress from the traefik container reaches ns1.digitalboard.ch
|
|
||||||
# unreliably (i/o timeouts on lego's recursive SOA pre-check), while
|
|
||||||
# TCP/53 to the same nameserver is open. Force lego to do its DNS
|
|
||||||
# lookups over TCP so the DNS-01 challenge can proceed.
|
|
||||||
traefik_acme_tcp_only: true
|
|
||||||
|
|
@ -1,167 +0,0 @@
|
||||||
---
|
|
||||||
# Bao secret expected at <mount>/data/authentik with keys:
|
|
||||||
# secret_key, postgres_password, admin_password,
|
|
||||||
# ldap_outpost_token, proxy_outpost_token,
|
|
||||||
# nextcloud_oidc_secret, opnform_oidc_secret,
|
|
||||||
# homarr_oidc_secret, bookstack_oidc_secret
|
|
||||||
_authentik: "{{ lookup('community.hashi_vault.hashi_vault', vault_mount + '/data/authentik', url=vault_addr) }}"
|
|
||||||
|
|
||||||
# First entry is the canonical public FQDN (browsers + OIDC iss-claim).
|
|
||||||
# The *.int.* entry makes the router match the internal name too, so
|
|
||||||
# Traefik requests a cert covering it — the DMZ reverseproxy uses
|
|
||||||
# auth.int.mbaz as backend_host and verifies the chain (acme mode,
|
|
||||||
# no insecureSkipVerify), which fails against the default cert otherwise.
|
|
||||||
authentik_domains:
|
|
||||||
- "auth.mbaz.souveredu.ch"
|
|
||||||
- "auth.int.mbaz.souveredu.ch"
|
|
||||||
|
|
||||||
authentik_secret_key: "{{ _authentik.secret_key }}"
|
|
||||||
authentik_postgres_password: "{{ _authentik.postgres_password }}"
|
|
||||||
|
|
||||||
# LDAP outpost (provider for nextcloud)
|
|
||||||
authentik_ldap_apps:
|
|
||||||
- slug: ldap
|
|
||||||
name: LDAP
|
|
||||||
base_dn: "dc=mbaz,dc=souveredu,dc=ch"
|
|
||||||
search_group: admins
|
|
||||||
|
|
||||||
authentik_ldap_outpost:
|
|
||||||
name: "ldap-outpost"
|
|
||||||
token: "{{ _authentik.ldap_outpost_token }}"
|
|
||||||
config:
|
|
||||||
# Outpost pulls config from authentik over the public FQDN, which
|
|
||||||
# resolves (internal DNS view) to the DMZ reverseproxy the backend
|
|
||||||
# subnet can reach — keeps the round-trip in the LAN with a valid cert.
|
|
||||||
authentik_host: "https://auth.mbaz.souveredu.ch/"
|
|
||||||
log_level: "info"
|
|
||||||
|
|
||||||
# Proxy providers (ForwardAuth) — gate downstream services behind
|
|
||||||
# authentik. The embedded outpost (which authentik ships out of the box)
|
|
||||||
# hosts these providers under /outpost.goauthentik.io/auth/traefik on the
|
|
||||||
# canonical FQDN; the service-side traefik attaches a ForwardAuth
|
|
||||||
# middleware that talks to that endpoint.
|
|
||||||
authentik_proxy_apps:
|
|
||||||
- slug: drawio
|
|
||||||
name: Drawio
|
|
||||||
external_host: "https://draw.mbaz.souveredu.ch"
|
|
||||||
internal_host: "http://drawio:8080"
|
|
||||||
# drawio is embedded in Nextcloud as an iframe (nextcloud_enable_drawio).
|
|
||||||
# Every authenticated Nextcloud user must therefore pass the ForwardAuth
|
|
||||||
# gate, otherwise the editor loads a 403 inside the iframe. Allow both
|
|
||||||
# standard groups; tightening this back to admins-only would break the
|
|
||||||
# Nextcloud integration for regular users.
|
|
||||||
allowed_groups:
|
|
||||||
- admins
|
|
||||||
- users
|
|
||||||
flows:
|
|
||||||
authentication_slug: default-authentication-flow
|
|
||||||
authorization_slug: default-provider-authorization-implicit-consent
|
|
||||||
invalidation_slug: default-provider-invalidation-flow
|
|
||||||
- slug: garage-webui
|
|
||||||
name: "Garage S3 Console"
|
|
||||||
external_host: "https://console.s3.mbaz.souveredu.ch"
|
|
||||||
internal_host: "http://garage-webui:3909"
|
|
||||||
allowed_groups:
|
|
||||||
- admins
|
|
||||||
flows:
|
|
||||||
authentication_slug: default-authentication-flow
|
|
||||||
authorization_slug: default-provider-authorization-implicit-consent
|
|
||||||
invalidation_slug: default-provider-invalidation-flow
|
|
||||||
|
|
||||||
# Outpost bindings. drawio runs on this (application) host, so its
|
|
||||||
# ForwardAuth can use the embedded outpost (same host:9000 as the
|
|
||||||
# authentik server). garage-webui runs on the storage host; a cross-host
|
|
||||||
# ForwardAuth to the embedded outpost arrives with a mangled
|
|
||||||
# X-Forwarded-Host (an extra reverseproxy hop appends :443 / a comma list)
|
|
||||||
# and the outpost then fails to match the provider's external_host (404).
|
|
||||||
# So garage-webui is bound to a dedicated proxy outpost deployed on
|
|
||||||
# storage (role digitalboard.core.authentik_outpost_proxy), whose
|
|
||||||
# ForwardAuth endpoint the local storage Traefik reaches over the docker
|
|
||||||
# network — no extra hop, clean X-Forwarded-Host.
|
|
||||||
authentik_proxy_outposts:
|
|
||||||
- name: "authentik Embedded Outpost"
|
|
||||||
type: proxy
|
|
||||||
providers:
|
|
||||||
- drawio
|
|
||||||
- name: "storage-proxy-outpost"
|
|
||||||
type: proxy
|
|
||||||
token: "{{ _authentik.proxy_outpost_token }}"
|
|
||||||
providers:
|
|
||||||
- garage-webui
|
|
||||||
# config is required by the outpost blueprint serializer. The outpost
|
|
||||||
# runs on the storage host and reaches authentik over the public FQDN
|
|
||||||
# (resolves to the DMZ reverseproxy the storage subnet can reach).
|
|
||||||
config:
|
|
||||||
authentik_host: "https://auth.mbaz.souveredu.ch/"
|
|
||||||
log_level: "info"
|
|
||||||
|
|
||||||
# OIDC clients
|
|
||||||
authentik_oidc_apps:
|
|
||||||
- slug: nextcloud
|
|
||||||
name: Nextcloud
|
|
||||||
client_id: nextcloud
|
|
||||||
client_secret: "{{ _authentik.nextcloud_oidc_secret }}"
|
|
||||||
redirect_uris:
|
|
||||||
- url: "https://cloud.mbaz.souveredu.ch/apps/user_oidc/code"
|
|
||||||
matching_mode: strict
|
|
||||||
signing_key_name: "authentik Self-signed Certificate"
|
|
||||||
flows:
|
|
||||||
authorization_slug: default-provider-authorization-implicit-consent
|
|
||||||
invalidation_slug: default-provider-invalidation-flow
|
|
||||||
scopes: [openid, email, profile, offline_access]
|
|
||||||
- slug: opnform
|
|
||||||
name: OpnForm
|
|
||||||
client_id: opnform
|
|
||||||
client_secret: "{{ _authentik.opnform_oidc_secret }}"
|
|
||||||
redirect_uris:
|
|
||||||
- url: "https://forms.mbaz.souveredu.ch/auth/authentik/callback"
|
|
||||||
matching_mode: strict
|
|
||||||
signing_key_name: "authentik Self-signed Certificate"
|
|
||||||
flows:
|
|
||||||
authorization_slug: default-provider-authorization-implicit-consent
|
|
||||||
invalidation_slug: default-provider-invalidation-flow
|
|
||||||
# No separate `groups` scope — authentik's default `profile` mapping
|
|
||||||
# already emits a `groups` claim built from request.user.groups, so
|
|
||||||
# OpnForm's admin-group mapping works without an extra scope.
|
|
||||||
scopes: [openid, email, profile]
|
|
||||||
- slug: homarr
|
|
||||||
name: Homarr
|
|
||||||
client_id: homarr
|
|
||||||
client_secret: "{{ _authentik.homarr_oidc_secret }}"
|
|
||||||
redirect_uris:
|
|
||||||
- url: "https://home.mbaz.souveredu.ch/api/auth/callback/oidc"
|
|
||||||
matching_mode: strict
|
|
||||||
signing_key_name: "authentik Self-signed Certificate"
|
|
||||||
flows:
|
|
||||||
authorization_slug: default-provider-authorization-implicit-consent
|
|
||||||
invalidation_slug: default-provider-invalidation-flow
|
|
||||||
scopes: [openid, email, profile]
|
|
||||||
- slug: bookstack
|
|
||||||
name: BookStack
|
|
||||||
client_id: bookstack
|
|
||||||
client_secret: "{{ _authentik.bookstack_oidc_secret }}"
|
|
||||||
redirect_uris:
|
|
||||||
- url: "https://wiki.mbaz.souveredu.ch/oidc/callback"
|
|
||||||
matching_mode: strict
|
|
||||||
signing_key_name: "authentik Self-signed Certificate"
|
|
||||||
flows:
|
|
||||||
authorization_slug: default-provider-authorization-implicit-consent
|
|
||||||
invalidation_slug: default-provider-invalidation-flow
|
|
||||||
scopes: [openid, email, profile]
|
|
||||||
|
|
||||||
authentik_groups:
|
|
||||||
- name: admins
|
|
||||||
- name: users
|
|
||||||
- name: opnform-admins
|
|
||||||
- name: homarr-admins
|
|
||||||
- name: bookstack-admins
|
|
||||||
|
|
||||||
authentik_local_users:
|
|
||||||
- username: akadmin
|
|
||||||
name: "Authentik Admin"
|
|
||||||
email: "admin@mbaz.souveredu.ch"
|
|
||||||
password: "{{ _authentik.admin_password }}"
|
|
||||||
is_active: true
|
|
||||||
groups:
|
|
||||||
- authentik Admins
|
|
||||||
- admins
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
---
|
|
||||||
# Same token as authentik_ldap_outpost.token above — outpost uses it to
|
|
||||||
# authenticate against the authentik server it talks to.
|
|
||||||
_authentik: "{{ lookup('community.hashi_vault.hashi_vault', vault_mount + '/data/authentik', url=vault_addr) }}"
|
|
||||||
|
|
||||||
# Public FQDN resolves (internal DNS view) to the DMZ reverseproxy the
|
|
||||||
# backend subnet can reach, so the outpost->authentik round-trip stays in
|
|
||||||
# the LAN with a valid cert and matches the iss claim authentik emits.
|
|
||||||
authentik_outpost_ldap_host: "https://auth.mbaz.souveredu.ch"
|
|
||||||
authentik_outpost_ldap_token: "{{ _authentik.ldap_outpost_token }}"
|
|
||||||
# auth.mba.* presents a valid Let's Encrypt cert via the reverseproxy, so
|
|
||||||
# verify the chain instead of relying on the role's insecure default.
|
|
||||||
authentik_outpost_ldap_insecure: "false"
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
---
|
|
||||||
# Bao secret <mount>/data/bookstack expected to contain:
|
|
||||||
# db_root_password, db_password, admin_password, oidc_client_secret,
|
|
||||||
# app_key (optional — only set when restoring)
|
|
||||||
_bookstack: "{{ lookup('community.hashi_vault.hashi_vault', vault_mount + '/data/bookstack', url=vault_addr) }}"
|
|
||||||
|
|
||||||
bookstack_domain: "wiki.mbaz.souveredu.ch"
|
|
||||||
bookstack_extra_domains:
|
|
||||||
- "wiki.int.mbaz.souveredu.ch"
|
|
||||||
bookstack_base_url: "https://wiki.mbaz.souveredu.ch"
|
|
||||||
|
|
||||||
# Override the role-default certresolver ("le") with the value used
|
|
||||||
# across this demo (matches traefik_ssl_cert_resolver in group_vars).
|
|
||||||
bookstack_traefik_certresolver: "dns"
|
|
||||||
|
|
||||||
bookstack_db_root_password: "{{ _bookstack.db_root_password }}"
|
|
||||||
bookstack_db_password: "{{ _bookstack.db_password }}"
|
|
||||||
bookstack_admin_password: "{{ _bookstack.admin_password }}"
|
|
||||||
bookstack_admin_email: "admin@mbaz.souveredu.ch"
|
|
||||||
bookstack_admin_name: "BookStack Admin"
|
|
||||||
|
|
||||||
# OIDC against Authentik. BookStack compares OIDC_ISSUER strictly against
|
|
||||||
# the `iss` claim in the discovery response, and Authentik emits the
|
|
||||||
# public auth.mbaz.* hostname there, so the issuer must use the public
|
|
||||||
# FQDN. That FQDN resolves (internal DNS view) to the DMZ reverseproxy,
|
|
||||||
# which the backend subnet can reach, so the server-to-server calls stay
|
|
||||||
# in the LAN.
|
|
||||||
bookstack_oidc_enabled: true
|
|
||||||
bookstack_oidc_name: "Authentik"
|
|
||||||
bookstack_oidc_issuer: "https://auth.mbaz.souveredu.ch/application/o/bookstack/"
|
|
||||||
bookstack_oidc_client_id: "bookstack"
|
|
||||||
bookstack_oidc_client_secret: "{{ _bookstack.oidc_client_secret }}"
|
|
||||||
bookstack_oidc_additional_scopes: "openid profile email"
|
|
||||||
bookstack_oidc_user_to_groups: true
|
|
||||||
bookstack_oidc_groups_claim: "groups"
|
|
||||||
bookstack_oidc_auto_initiate: false
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
---
|
|
||||||
# First entry is the canonical public FQDN. Additional entries cover
|
|
||||||
# internal *.int.* names so nextcloud's WOPI discovery hits collabora
|
|
||||||
# in the LAN with a valid internal cert.
|
|
||||||
collabora_domains:
|
|
||||||
- "office.mbaz.souveredu.ch"
|
|
||||||
- "office.int.mbaz.souveredu.ch"
|
|
||||||
|
|
||||||
# Hosts allowed to issue WOPI calls. Both names are listed so collabora
|
|
||||||
# accepts the callback from nextcloud regardless of which FQDN it uses.
|
|
||||||
collabora_allowed_domains:
|
|
||||||
- "cloud.mbaz.souveredu.ch"
|
|
||||||
- "cloud.int.mbaz.souveredu.ch"
|
|
||||||
|
|
||||||
collabora_frame_ancestors:
|
|
||||||
- "cloud.mbaz.souveredu.ch"
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
---
|
|
||||||
drawio_domain: "draw.mbaz.souveredu.ch"
|
|
||||||
|
|
||||||
# Internal FQDN the DMZ reverseproxy uses as backend host so its TLS
|
|
||||||
# verify matches a cert SAN (the canonical IP-only route has no SAN
|
|
||||||
# and breaks with "cannot validate certificate ... no IP SANs"). Same
|
|
||||||
# split-horizon pattern as cloud.int.* / auth.int.* / office.int.*.
|
|
||||||
drawio_extra_domains:
|
|
||||||
- "draw.int.mbaz.souveredu.ch"
|
|
||||||
|
|
||||||
# Gate drawio behind the authentik embedded outpost. The allow-list is
|
|
||||||
# managed on the authentik proxy application (admins + users) so the
|
|
||||||
# Nextcloud drawio iframe works for every authenticated user.
|
|
||||||
# ForwardAuth talks to the embedded outpost on the authentik server's
|
|
||||||
# in-network address. Going via the public FQDN routes through a second
|
|
||||||
# traefik hop that strips/rewrites X-Forwarded-Host, which breaks
|
|
||||||
# authentik's provider matching (it returns 404). Plain HTTP to the
|
|
||||||
# container is the path docs recommend for the embedded outpost.
|
|
||||||
drawio_authentik_forward_auth: true
|
|
||||||
drawio_authentik_forward_auth_url: "http://authentik-server-1:9000/outpost.goauthentik.io/auth/traefik"
|
|
||||||
|
|
@ -1,78 +0,0 @@
|
||||||
---
|
|
||||||
# Bao secret <mount>/data/homarr expected to contain:
|
|
||||||
# secret_encryption_key (64 hex chars), admin_password, oidc_client_secret
|
|
||||||
_homarr: "{{ lookup('community.hashi_vault.hashi_vault', vault_mount + '/data/homarr', url=vault_addr) }}"
|
|
||||||
|
|
||||||
homarr_domain: "home.mbaz.souveredu.ch"
|
|
||||||
homarr_extra_domains:
|
|
||||||
- "home.int.mbaz.souveredu.ch"
|
|
||||||
homarr_base_url: "https://home.mbaz.souveredu.ch"
|
|
||||||
|
|
||||||
homarr_secret_encryption_key: "{{ _homarr.secret_encryption_key }}"
|
|
||||||
homarr_admin_username: "admin"
|
|
||||||
homarr_admin_email: "admin@mbaz.souveredu.ch"
|
|
||||||
homarr_admin_password: "{{ _homarr.admin_password }}"
|
|
||||||
|
|
||||||
# OIDC against Authentik. credentials provider stays enabled as a
|
|
||||||
# break-glass account — reach it via /auth/login/credentials when
|
|
||||||
# AUTH_OIDC_AUTO_LOGIN bypasses the normal /login page.
|
|
||||||
#
|
|
||||||
# Issuer must match the `iss` claim authentik emits, which is always the
|
|
||||||
# public FQDN. Homarr (oauth4webapi) does a strict 1:1 comparison between
|
|
||||||
# the discovery response's issuer and this URL — an internal FQDN here
|
|
||||||
# fails with OAUTH_JSON_ATTRIBUTE_COMPARISON_FAILED. The public FQDN
|
|
||||||
# resolves (internal DNS view) to the DMZ reverseproxy, which the backend
|
|
||||||
# subnet can reach, so discovery/token/userinfo stay in the LAN.
|
|
||||||
homarr_auth_providers: "credentials,oidc"
|
|
||||||
homarr_oidc_issuer: "https://auth.mbaz.souveredu.ch/application/o/homarr/"
|
|
||||||
homarr_oidc_client_id: "homarr"
|
|
||||||
homarr_oidc_client_secret: "{{ _homarr.oidc_client_secret }}"
|
|
||||||
homarr_oidc_client_name: "Authentik"
|
|
||||||
homarr_oidc_scopes: "openid profile email groups"
|
|
||||||
homarr_oidc_groups_attribute: "groups"
|
|
||||||
homarr_oidc_auto_login: "true"
|
|
||||||
|
|
||||||
# Default board with shortcuts to the other mbazürich services. Width
|
|
||||||
# values describe horizontal grid cells (1-10 desktop / 6 tablet / 2
|
|
||||||
# mobile, packed left-to-right).
|
|
||||||
homarr_apps:
|
|
||||||
- id: nextcloud
|
|
||||||
name: Nextcloud
|
|
||||||
description: "Cloud Storage & Collaboration"
|
|
||||||
icon: https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/nextcloud.png
|
|
||||||
href: https://cloud.mbaz.souveredu.ch
|
|
||||||
width: 2
|
|
||||||
- id: collabora
|
|
||||||
name: Collabora Office
|
|
||||||
icon: https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/collaboraonline.png
|
|
||||||
href: https://office.mbaz.souveredu.ch
|
|
||||||
width: 2
|
|
||||||
- id: drawio
|
|
||||||
name: Draw.io
|
|
||||||
icon: https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/drawio.png
|
|
||||||
href: https://draw.mbaz.souveredu.ch
|
|
||||||
width: 2
|
|
||||||
- id: send
|
|
||||||
name: Send
|
|
||||||
description: "Encrypted file-share"
|
|
||||||
icon: https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/firefox-send.png
|
|
||||||
href: https://send.mbaz.souveredu.ch
|
|
||||||
width: 2
|
|
||||||
- id: opnform
|
|
||||||
name: OpnForm
|
|
||||||
description: "Self-hosted forms"
|
|
||||||
icon: https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/opnform.png
|
|
||||||
href: https://forms.mbaz.souveredu.ch
|
|
||||||
width: 2
|
|
||||||
- id: bookstack
|
|
||||||
name: BookStack
|
|
||||||
description: "Wiki & documentation"
|
|
||||||
icon: https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/bookstack.png
|
|
||||||
href: https://wiki.mbaz.souveredu.ch
|
|
||||||
width: 2
|
|
||||||
- id: authentik
|
|
||||||
name: Authentik
|
|
||||||
description: "Identity provider"
|
|
||||||
icon: https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/authentik.png
|
|
||||||
href: https://auth.mbaz.souveredu.ch
|
|
||||||
width: 2
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
---
|
|
||||||
# application host runs: authentik, authentik-ldap-outpost,
|
|
||||||
# nextcloud, collabora, drawio
|
|
||||||
|
|
@ -1,122 +0,0 @@
|
||||||
---
|
|
||||||
# Bao secret <mount>/data/nextcloud expected to contain:
|
|
||||||
# postgres_password, admin_password
|
|
||||||
_nextcloud: "{{ lookup('community.hashi_vault.hashi_vault', vault_mount + '/data/nextcloud', url=vault_addr) }}"
|
|
||||||
_authentik: "{{ lookup('community.hashi_vault.hashi_vault', vault_mount + '/data/authentik', url=vault_addr) }}"
|
|
||||||
|
|
||||||
# No nextcloud_image pin: the role default (nextcloud:fpm) already ships
|
|
||||||
# the fix for the PHP UserConfig::getValueBool TypeError (#59629), so the
|
|
||||||
# 33.0.3 pin gymb still carries is unnecessary here.
|
|
||||||
|
|
||||||
# First entry is the canonical public FQDN (used for OVERWRITEHOST and
|
|
||||||
# OIDC redirects). Additional entries cover internal *.int.* names so
|
|
||||||
# collabora's WOPI callbacks hit nextcloud on a name with a valid
|
|
||||||
# internal cert instead of routing through the DMZ.
|
|
||||||
nextcloud_domains:
|
|
||||||
- "cloud.mbaz.souveredu.ch"
|
|
||||||
- "cloud.int.mbaz.souveredu.ch"
|
|
||||||
nextcloud_postgres_password: "{{ _nextcloud.postgres_password }}"
|
|
||||||
nextcloud_admin_user: admin
|
|
||||||
nextcloud_admin_password: "{{ _nextcloud.admin_password }}"
|
|
||||||
|
|
||||||
nextcloud_enable_notify_push: true
|
|
||||||
# Use the internal FQDN for the notify_push setup check so curl from the
|
|
||||||
# nextcloud container hits the local traefik directly instead of
|
|
||||||
# hairpinning through the DMZ reverseproxy.
|
|
||||||
nextcloud_notify_push_domain: "cloud.int.mbaz.souveredu.ch"
|
|
||||||
|
|
||||||
# Collabora integration
|
|
||||||
# wopi_url (server-to-server: nextcloud calls collabora for discovery /
|
|
||||||
# capabilities) goes to the internal FQDN so the call stays in the LAN.
|
|
||||||
# public_wopi_url is what the browser loads the office iframe from — that
|
|
||||||
# stays on the public name reachable through the DMZ.
|
|
||||||
nextcloud_enable_collabora: true
|
|
||||||
nextcloud_collabora_domain: "office.int.mbaz.souveredu.ch"
|
|
||||||
nextcloud_collabora_public_domain: "office.mbaz.souveredu.ch"
|
|
||||||
|
|
||||||
# Draw.io integration
|
|
||||||
nextcloud_enable_drawio: true
|
|
||||||
nextcloud_drawio_url: "https://draw.mbaz.souveredu.ch"
|
|
||||||
|
|
||||||
nextcloud_apps_to_install:
|
|
||||||
- groupfolders
|
|
||||||
- richdocuments
|
|
||||||
- spreed
|
|
||||||
- user_ldap
|
|
||||||
- user_oidc
|
|
||||||
- whiteboard
|
|
||||||
- drawio
|
|
||||||
- files_lock
|
|
||||||
- notify_push
|
|
||||||
|
|
||||||
# S3 primary storage via Garage — server-to-server, so use the internal FQDN.
|
|
||||||
# Resolves through the internal DNS to the storage host and presents a valid
|
|
||||||
# cert from the local traefik on storage.
|
|
||||||
nextcloud_use_s3_storage: true
|
|
||||||
nextcloud_s3_key: "{{ lookup('digitalboard.core.garage_credentials', 'nextcloud', host='storage')['key_id'] }}"
|
|
||||||
nextcloud_s3_secret: "{{ lookup('digitalboard.core.garage_credentials', 'nextcloud', host='storage')['secret_key'] }}"
|
|
||||||
nextcloud_s3_bucket: "nextcloud"
|
|
||||||
nextcloud_s3_host: "s3.int.mbaz.souveredu.ch"
|
|
||||||
nextcloud_s3_port: 443
|
|
||||||
nextcloud_s3_ssl: true
|
|
||||||
nextcloud_s3_usepath_style: true
|
|
||||||
|
|
||||||
# OIDC discovery/token/userinfo and the S3 backend both target FQDNs
|
|
||||||
# that resolve to RFC1918 addresses (auth.mba.* via the reverseproxy,
|
|
||||||
# s3.int.* directly), which Nextcloud's DnsPinMiddleware would otherwise
|
|
||||||
# block as "local server access".
|
|
||||||
nextcloud_allow_local_remote_servers: true
|
|
||||||
|
|
||||||
# Share the LDAP docker network with the authentik LDAP outpost
|
|
||||||
nextcloud_extra_networks:
|
|
||||||
- ldap
|
|
||||||
|
|
||||||
# LDAP backend (Authentik LDAP outpost)
|
|
||||||
nextcloud_ldap_enabled: true
|
|
||||||
nextcloud_ldap_config:
|
|
||||||
ldapHost: "ldap://authentik-outpost-ldap-ldap-1"
|
|
||||||
ldapPort: "3389"
|
|
||||||
ldapAgentName: "cn=akadmin,ou=users,dc=mbaz,dc=souveredu,dc=ch"
|
|
||||||
ldapAgentPassword: "{{ _authentik.admin_password }}"
|
|
||||||
ldapBase: "dc=mbaz,dc=souveredu,dc=ch"
|
|
||||||
ldapBaseUsers: "ou=users,dc=mbaz,dc=souveredu,dc=ch"
|
|
||||||
ldapTLS: "0"
|
|
||||||
turnOffCertCheck: "1"
|
|
||||||
ldapUserFilter: "(&(objectClass=user)(cn=*))"
|
|
||||||
ldapUserFilterObjectclass: "user"
|
|
||||||
ldapLoginFilter: "(&(objectClass=user)(cn=%uid))"
|
|
||||||
ldapLoginFilterUsername: "1"
|
|
||||||
ldapUserDisplayName: "cn"
|
|
||||||
ldapEmailAttribute: "mail"
|
|
||||||
ldapExpertUsernameAttr: "cn"
|
|
||||||
ldapExpertUUIDUserAttr: "uid"
|
|
||||||
ldapExpertUUIDGroupAttr: "uid"
|
|
||||||
ldapBaseGroups: "ou=groups,dc=mbaz,dc=souveredu,dc=ch"
|
|
||||||
ldapGroupFilter: "(&(objectClass=group))"
|
|
||||||
ldapGroupFilterObjectclass: "group"
|
|
||||||
ldapGroupDisplayName: "cn"
|
|
||||||
ldapGroupMemberAssocAttr: "member"
|
|
||||||
ldapAdminGroup: "admins"
|
|
||||||
ldapCacheTTL: "600"
|
|
||||||
ldapPagingSize: "500"
|
|
||||||
ldapExperiencedAdmin: "1"
|
|
||||||
ldapConfigurationActive: "1"
|
|
||||||
|
|
||||||
# OIDC providers for login (Authentik)
|
|
||||||
nextcloud_oidc_providers:
|
|
||||||
- identifier: authentik
|
|
||||||
display_name: "Login with Authentik"
|
|
||||||
client_id: nextcloud
|
|
||||||
client_secret: "{{ _authentik.nextcloud_oidc_secret }}"
|
|
||||||
# Discovery via the public FQDN. It resolves (internal DNS view) to
|
|
||||||
# the DMZ reverseproxy, which the backend subnet can now reach, so
|
|
||||||
# the server-to-server call stays in the LAN while the iss claim and
|
|
||||||
# all listed endpoints match the public hostname the browser sees
|
|
||||||
# during login — no host-rewrite or /etc/hosts pin needed.
|
|
||||||
discovery_url: "https://auth.mbaz.souveredu.ch/application/o/nextcloud/.well-known/openid-configuration"
|
|
||||||
scope: "openid email profile"
|
|
||||||
unique_uid: true
|
|
||||||
mapping:
|
|
||||||
uid: preferred_username
|
|
||||||
display_name: name
|
|
||||||
email: email
|
|
||||||
|
|
@ -1,50 +0,0 @@
|
||||||
---
|
|
||||||
# Bao secret <mount>/data/opnform expected to contain:
|
|
||||||
# app_key (must start with "base64:"), jwt_secret, front_api_secret,
|
|
||||||
# db_password, admin_password, oidc_client_secret
|
|
||||||
_opnform: "{{ lookup('community.hashi_vault.hashi_vault', vault_mount + '/data/opnform', url=vault_addr) }}"
|
|
||||||
_authentik: "{{ lookup('community.hashi_vault.hashi_vault', vault_mount + '/data/authentik', url=vault_addr) }}"
|
|
||||||
|
|
||||||
opnform_domain: "forms.mbaz.souveredu.ch"
|
|
||||||
opnform_extra_domains:
|
|
||||||
- "forms.int.mbaz.souveredu.ch"
|
|
||||||
opnform_base_url: "https://forms.mbaz.souveredu.ch"
|
|
||||||
|
|
||||||
opnform_app_key: "{{ _opnform.app_key }}"
|
|
||||||
opnform_jwt_secret: "{{ _opnform.jwt_secret }}"
|
|
||||||
opnform_front_api_secret: "{{ _opnform.front_api_secret }}"
|
|
||||||
opnform_db_password: "{{ _opnform.db_password }}"
|
|
||||||
|
|
||||||
# Bootstrap admin via API on first run so the manual setup page is
|
|
||||||
# skipped. The admin credentials are also required to seed the OIDC
|
|
||||||
# IdentityConnection through OpnForm's API (only an authenticated admin
|
|
||||||
# can create connections).
|
|
||||||
opnform_admin_name: "OpnForm Admin"
|
|
||||||
opnform_admin_email: "admin@mbaz.souveredu.ch"
|
|
||||||
opnform_admin_password: "{{ _opnform.admin_password }}"
|
|
||||||
|
|
||||||
# OIDC against Authentik. The public auth.mbaz.* FQDN resolves (internal
|
|
||||||
# DNS view) to the DMZ reverseproxy, which the backend subnet can reach,
|
|
||||||
# so OpnForm's discovery/token/userinfo calls stay in the LAN while the
|
|
||||||
# iss claim matches the public hostname browsers see during login.
|
|
||||||
opnform_oidc_enabled: true
|
|
||||||
# Issuer must use the public FQDN: OpnForm validates the token's `iss`
|
|
||||||
# claim against this value, and Authentik emits the public hostname there.
|
|
||||||
opnform_oidc_issuer: "https://auth.mbaz.souveredu.ch/application/o/opnform/"
|
|
||||||
opnform_oidc_client_id: "opnform"
|
|
||||||
opnform_oidc_client_secret: "{{ _opnform.oidc_client_secret }}"
|
|
||||||
opnform_oidc_client_name: "Authentik"
|
|
||||||
opnform_oidc_slug: "authentik"
|
|
||||||
opnform_oidc_domain: "mbaz.souveredu.ch"
|
|
||||||
opnform_oidc_admin_group: "opnform-admins"
|
|
||||||
|
|
||||||
# Disable password login entirely — every user goes through Authentik.
|
|
||||||
# All real users have @mbaz.souveredu.ch addresses (matching
|
|
||||||
# opnform_oidc_domain above), so no password fallback is needed.
|
|
||||||
opnform_oidc_force_login: true
|
|
||||||
|
|
||||||
# `/` and `/login` are intercepted and jump straight to Authentik.
|
|
||||||
# Public form deep-links (`/forms/<slug>`, `/admin/...`) keep working.
|
|
||||||
# Break-glass: /login?bypass=1 reaches the email form when the IdP is
|
|
||||||
# down.
|
|
||||||
opnform_oidc_sso_entrypoint: true
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
---
|
|
||||||
# Send: anonymized self-hosted file-share (no login). First entry is the
|
|
||||||
# canonical public FQDN (used as BASE_URL); the *.int.* entry covers the
|
|
||||||
# server-to-server hop from the DMZ reverseproxy with a cert SAN that
|
|
||||||
# matches the backend hostname (same split-horizon pattern as cloud/draw).
|
|
||||||
send_domains:
|
|
||||||
- "send.mbaz.souveredu.ch"
|
|
||||||
- "send.int.mbaz.souveredu.ch"
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
||||||
---
|
|
||||||
# Services hosted on `application` that the DMZ reverseproxy should
|
|
||||||
# forward public traffic to. The DMZ traefik picks this up via
|
|
||||||
# hostvars[backend].traefik_dmz_exposed_services and renders a router +
|
|
||||||
# service for each entry into /config/services.yml.
|
|
||||||
traefik_dmz_exposed_services:
|
|
||||||
- name: authentik
|
|
||||||
domain: auth.mbaz.souveredu.ch
|
|
||||||
backend_host: auth.int.mbaz.souveredu.ch
|
|
||||||
port: 443
|
|
||||||
protocol: https
|
|
||||||
- name: nextcloud
|
|
||||||
domain: cloud.mbaz.souveredu.ch
|
|
||||||
backend_host: cloud.int.mbaz.souveredu.ch
|
|
||||||
port: 443
|
|
||||||
protocol: https
|
|
||||||
- name: collabora
|
|
||||||
domain: office.mbaz.souveredu.ch
|
|
||||||
backend_host: office.int.mbaz.souveredu.ch
|
|
||||||
port: 443
|
|
||||||
protocol: https
|
|
||||||
- name: drawio
|
|
||||||
domain: draw.mbaz.souveredu.ch
|
|
||||||
backend_host: draw.int.mbaz.souveredu.ch
|
|
||||||
port: 443
|
|
||||||
protocol: https
|
|
||||||
- name: send
|
|
||||||
domain: send.mbaz.souveredu.ch
|
|
||||||
backend_host: send.int.mbaz.souveredu.ch
|
|
||||||
port: 443
|
|
||||||
protocol: https
|
|
||||||
- name: opnform
|
|
||||||
domain: forms.mbaz.souveredu.ch
|
|
||||||
backend_host: forms.int.mbaz.souveredu.ch
|
|
||||||
port: 443
|
|
||||||
protocol: https
|
|
||||||
- name: homarr
|
|
||||||
domain: home.mbaz.souveredu.ch
|
|
||||||
backend_host: home.int.mbaz.souveredu.ch
|
|
||||||
port: 443
|
|
||||||
protocol: https
|
|
||||||
- name: bookstack
|
|
||||||
domain: wiki.mbaz.souveredu.ch
|
|
||||||
backend_host: wiki.int.mbaz.souveredu.ch
|
|
||||||
port: 443
|
|
||||||
protocol: https
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
---
|
|
||||||
traefik_mode: dmz
|
|
||||||
|
|
||||||
# The DMZ traefik discovers which services to expose by reading
|
|
||||||
# traefik_dmz_exposed_services from each backend host's host_vars
|
|
||||||
# (application/traefik.yml, storage/traefik.yml). See the role's
|
|
||||||
# tasks/main.yml — set_fact "Build service registry from backend
|
|
||||||
# servers (DMZ mode)".
|
|
||||||
|
|
||||||
# From the DMZ network the public ns1 IP (193.43.183.169) is not
|
|
||||||
# reachable on port 53, but the internal address (172.16.9.169) is.
|
|
||||||
# Override the group-level traefik_acme_dns_nameserver from bao so
|
|
||||||
# lego's RFC2136 updates land at the internal interface. The TSIG
|
|
||||||
# key/secret are the same; only the transport target changes.
|
|
||||||
traefik_acme_dns_nameserver: "172.16.9.169"
|
|
||||||
|
|
||||||
# Lego's propagation check normally polls the NS hostnames listed in
|
|
||||||
# the zone's SOA (ns1.digitalboard.ch.) — which resolves to the
|
|
||||||
# public IP that's unreachable from this DMZ host. Skip that check;
|
|
||||||
# lego still polls via the resolver above before asking LE to
|
|
||||||
# validate.
|
|
||||||
traefik_acme_disable_ans_checks: true
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
---
|
|
||||||
# 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.mba.* 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.mbaz.souveredu.ch"
|
|
||||||
authentik_outpost_proxy_token: "{{ _authentik.proxy_outpost_token }}"
|
|
||||||
authentik_outpost_proxy_insecure: "false"
|
|
||||||
authentik_outpost_proxy_network: "proxy"
|
|
||||||
|
|
@ -1,51 +0,0 @@
|
||||||
---
|
|
||||||
# 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.mbaz.souveredu.ch"
|
|
||||||
- "s3.int.mbaz.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.mbaz.souveredu.ch"
|
|
||||||
- "console.s3.int.mbaz.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: "zurich1"
|
|
||||||
garage_bootstrap_capacity: "100G"
|
|
||||||
|
|
||||||
# Buckets and keys consumed by nextcloud
|
|
||||||
garage_s3_keys:
|
|
||||||
- name: nextcloud
|
|
||||||
buckets:
|
|
||||||
- name: nextcloud
|
|
||||||
permissions: ["read", "write"]
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
---
|
|
||||||
# storage host runs: garage (S3 + WebUI)
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
---
|
|
||||||
# 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.mbaz.souveredu.ch
|
|
||||||
backend_host: s3.int.mbaz.souveredu.ch
|
|
||||||
port: 443
|
|
||||||
protocol: https
|
|
||||||
- name: garage-webui
|
|
||||||
domain: console.s3.mbaz.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.mbaz.souveredu.ch
|
|
||||||
port: 443
|
|
||||||
protocol: https
|
|
||||||
|
|
@ -22,7 +22,6 @@ all:
|
||||||
backend_servers:
|
backend_servers:
|
||||||
hosts:
|
hosts:
|
||||||
application:
|
application:
|
||||||
storage:
|
|
||||||
|
|
||||||
garage_servers:
|
garage_servers:
|
||||||
hosts:
|
hosts:
|
||||||
|
|
@ -32,6 +31,10 @@ all:
|
||||||
hosts:
|
hosts:
|
||||||
application:
|
application:
|
||||||
|
|
||||||
|
opencloud_servers:
|
||||||
|
hosts:
|
||||||
|
application:
|
||||||
|
|
||||||
collabora_servers:
|
collabora_servers:
|
||||||
hosts:
|
hosts:
|
||||||
application:
|
application:
|
||||||
|
|
@ -42,33 +45,4 @@ all:
|
||||||
|
|
||||||
authentik_servers:
|
authentik_servers:
|
||||||
hosts:
|
hosts:
|
||||||
application:
|
application:
|
||||||
|
|
||||||
authentik_outpost_ldap_servers:
|
|
||||||
hosts:
|
|
||||||
application:
|
|
||||||
|
|
||||||
# Proxy (ForwardAuth) outpost co-located with garage on storage, so
|
|
||||||
# the garage-webui ForwardAuth subrequest stays on the local docker
|
|
||||||
# network instead of crossing an extra reverseproxy hop (which mangles
|
|
||||||
# X-Forwarded-Host and breaks the embedded outpost's app matching).
|
|
||||||
authentik_outpost_proxy_servers:
|
|
||||||
hosts:
|
|
||||||
storage:
|
|
||||||
|
|
||||||
|
|
||||||
send_servers:
|
|
||||||
hosts:
|
|
||||||
application:
|
|
||||||
|
|
||||||
opnform_servers:
|
|
||||||
hosts:
|
|
||||||
application:
|
|
||||||
|
|
||||||
homarr_servers:
|
|
||||||
hosts:
|
|
||||||
application:
|
|
||||||
|
|
||||||
bookstack_servers:
|
|
||||||
hosts:
|
|
||||||
application:
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
---
|
|
||||||
ansible_python_interpreter: /usr/bin/python3
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
docker_registry_mirrors: ["https://registry-mirror.wksbern.ch"]
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
vault_addr: "https://bao.digitalboard.ch"
|
|
||||||
vault_mount: "demo-phbern"
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
traefik_mode: backend
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
_acme_tsig: "{{ lookup('community.hashi_vault.hashi_vault', vault_mount + '/data/acme-tsig', url=vault_addr ) }}"
|
|
||||||
|
|
||||||
traefik_use_ssl: true
|
|
||||||
traefik_cert_mode: "acme"
|
|
||||||
traefik_ssl_email: "hostmaster@digitalboard.ch"
|
|
||||||
traefik_log_level: DEBUG
|
|
||||||
traefik_network: proxy
|
|
||||||
|
|
||||||
traefik_acme_dns_zone: "demo-phbe._acme.digitalboard.ch"
|
|
||||||
traefik_acme_dns_nameserver: "{{ _acme_tsig.server }}"
|
|
||||||
traefik_acme_tsig_algorithm: "hmac-sha256"
|
|
||||||
traefik_acme_tsig_key: "{{ _acme_tsig.tsig_key }}"
|
|
||||||
traefik_acme_tsig_secret: "{{ _acme_tsig.tsig_secret }}"
|
|
||||||
|
|
||||||
# UDP/53 egress from the traefik container reaches ns1.digitalboard.ch
|
|
||||||
# unreliably (i/o timeouts on lego's recursive SOA pre-check), while
|
|
||||||
# TCP/53 to the same nameserver is open. Force lego to do its DNS
|
|
||||||
# lookups over TCP so the DNS-01 challenge can proceed.
|
|
||||||
traefik_acme_tcp_only: true
|
|
||||||
|
|
@ -1,167 +0,0 @@
|
||||||
---
|
|
||||||
# Bao secret expected at <mount>/data/authentik with keys:
|
|
||||||
# secret_key, postgres_password, admin_password,
|
|
||||||
# ldap_outpost_token, proxy_outpost_token,
|
|
||||||
# nextcloud_oidc_secret, opnform_oidc_secret,
|
|
||||||
# homarr_oidc_secret, bookstack_oidc_secret
|
|
||||||
_authentik: "{{ lookup('community.hashi_vault.hashi_vault', vault_mount + '/data/authentik', url=vault_addr) }}"
|
|
||||||
|
|
||||||
# First entry is the canonical public FQDN (browsers + OIDC iss-claim).
|
|
||||||
# The *.int.* entry makes the router match the internal name too, so
|
|
||||||
# Traefik requests a cert covering it — the DMZ reverseproxy uses
|
|
||||||
# auth.int.phbe as backend_host and verifies the chain (acme mode,
|
|
||||||
# no insecureSkipVerify), which fails against the default cert otherwise.
|
|
||||||
authentik_domains:
|
|
||||||
- "auth.phbe.souveredu.ch"
|
|
||||||
- "auth.int.phbe.souveredu.ch"
|
|
||||||
|
|
||||||
authentik_secret_key: "{{ _authentik.secret_key }}"
|
|
||||||
authentik_postgres_password: "{{ _authentik.postgres_password }}"
|
|
||||||
|
|
||||||
# LDAP outpost (provider for nextcloud)
|
|
||||||
authentik_ldap_apps:
|
|
||||||
- slug: ldap
|
|
||||||
name: LDAP
|
|
||||||
base_dn: "dc=phbe,dc=souveredu,dc=ch"
|
|
||||||
search_group: admins
|
|
||||||
|
|
||||||
authentik_ldap_outpost:
|
|
||||||
name: "ldap-outpost"
|
|
||||||
token: "{{ _authentik.ldap_outpost_token }}"
|
|
||||||
config:
|
|
||||||
# Outpost pulls config from authentik over the public FQDN, which
|
|
||||||
# resolves (internal DNS view) to the DMZ reverseproxy the backend
|
|
||||||
# subnet can reach — keeps the round-trip in the LAN with a valid cert.
|
|
||||||
authentik_host: "https://auth.phbe.souveredu.ch/"
|
|
||||||
log_level: "info"
|
|
||||||
|
|
||||||
# Proxy providers (ForwardAuth) — gate downstream services behind
|
|
||||||
# authentik. The embedded outpost (which authentik ships out of the box)
|
|
||||||
# hosts these providers under /outpost.goauthentik.io/auth/traefik on the
|
|
||||||
# canonical FQDN; the service-side traefik attaches a ForwardAuth
|
|
||||||
# middleware that talks to that endpoint.
|
|
||||||
authentik_proxy_apps:
|
|
||||||
- slug: drawio
|
|
||||||
name: Drawio
|
|
||||||
external_host: "https://draw.phbe.souveredu.ch"
|
|
||||||
internal_host: "http://drawio:8080"
|
|
||||||
# drawio is embedded in Nextcloud as an iframe (nextcloud_enable_drawio).
|
|
||||||
# Every authenticated Nextcloud user must therefore pass the ForwardAuth
|
|
||||||
# gate, otherwise the editor loads a 403 inside the iframe. Allow both
|
|
||||||
# standard groups; tightening this back to admins-only would break the
|
|
||||||
# Nextcloud integration for regular users.
|
|
||||||
allowed_groups:
|
|
||||||
- admins
|
|
||||||
- users
|
|
||||||
flows:
|
|
||||||
authentication_slug: default-authentication-flow
|
|
||||||
authorization_slug: default-provider-authorization-implicit-consent
|
|
||||||
invalidation_slug: default-provider-invalidation-flow
|
|
||||||
- slug: garage-webui
|
|
||||||
name: "Garage S3 Console"
|
|
||||||
external_host: "https://console.s3.phbe.souveredu.ch"
|
|
||||||
internal_host: "http://garage-webui:3909"
|
|
||||||
allowed_groups:
|
|
||||||
- admins
|
|
||||||
flows:
|
|
||||||
authentication_slug: default-authentication-flow
|
|
||||||
authorization_slug: default-provider-authorization-implicit-consent
|
|
||||||
invalidation_slug: default-provider-invalidation-flow
|
|
||||||
|
|
||||||
# Outpost bindings. drawio runs on this (application) host, so its
|
|
||||||
# ForwardAuth can use the embedded outpost (same host:9000 as the
|
|
||||||
# authentik server). garage-webui runs on the storage host; a cross-host
|
|
||||||
# ForwardAuth to the embedded outpost arrives with a mangled
|
|
||||||
# X-Forwarded-Host (an extra reverseproxy hop appends :443 / a comma list)
|
|
||||||
# and the outpost then fails to match the provider's external_host (404).
|
|
||||||
# So garage-webui is bound to a dedicated proxy outpost deployed on
|
|
||||||
# storage (role digitalboard.core.authentik_outpost_proxy), whose
|
|
||||||
# ForwardAuth endpoint the local storage Traefik reaches over the docker
|
|
||||||
# network — no extra hop, clean X-Forwarded-Host.
|
|
||||||
authentik_proxy_outposts:
|
|
||||||
- name: "authentik Embedded Outpost"
|
|
||||||
type: proxy
|
|
||||||
providers:
|
|
||||||
- drawio
|
|
||||||
- name: "storage-proxy-outpost"
|
|
||||||
type: proxy
|
|
||||||
token: "{{ _authentik.proxy_outpost_token }}"
|
|
||||||
providers:
|
|
||||||
- garage-webui
|
|
||||||
# config is required by the outpost blueprint serializer. The outpost
|
|
||||||
# runs on the storage host and reaches authentik over the public FQDN
|
|
||||||
# (resolves to the DMZ reverseproxy the storage subnet can reach).
|
|
||||||
config:
|
|
||||||
authentik_host: "https://auth.phbe.souveredu.ch/"
|
|
||||||
log_level: "info"
|
|
||||||
|
|
||||||
# OIDC clients
|
|
||||||
authentik_oidc_apps:
|
|
||||||
- slug: nextcloud
|
|
||||||
name: Nextcloud
|
|
||||||
client_id: nextcloud
|
|
||||||
client_secret: "{{ _authentik.nextcloud_oidc_secret }}"
|
|
||||||
redirect_uris:
|
|
||||||
- url: "https://cloud.phbe.souveredu.ch/apps/user_oidc/code"
|
|
||||||
matching_mode: strict
|
|
||||||
signing_key_name: "authentik Self-signed Certificate"
|
|
||||||
flows:
|
|
||||||
authorization_slug: default-provider-authorization-implicit-consent
|
|
||||||
invalidation_slug: default-provider-invalidation-flow
|
|
||||||
scopes: [openid, email, profile, offline_access]
|
|
||||||
- slug: opnform
|
|
||||||
name: OpnForm
|
|
||||||
client_id: opnform
|
|
||||||
client_secret: "{{ _authentik.opnform_oidc_secret }}"
|
|
||||||
redirect_uris:
|
|
||||||
- url: "https://forms.phbe.souveredu.ch/auth/authentik/callback"
|
|
||||||
matching_mode: strict
|
|
||||||
signing_key_name: "authentik Self-signed Certificate"
|
|
||||||
flows:
|
|
||||||
authorization_slug: default-provider-authorization-implicit-consent
|
|
||||||
invalidation_slug: default-provider-invalidation-flow
|
|
||||||
# No separate `groups` scope — authentik's default `profile` mapping
|
|
||||||
# already emits a `groups` claim built from request.user.groups, so
|
|
||||||
# OpnForm's admin-group mapping works without an extra scope.
|
|
||||||
scopes: [openid, email, profile]
|
|
||||||
- slug: homarr
|
|
||||||
name: Homarr
|
|
||||||
client_id: homarr
|
|
||||||
client_secret: "{{ _authentik.homarr_oidc_secret }}"
|
|
||||||
redirect_uris:
|
|
||||||
- url: "https://home.phbe.souveredu.ch/api/auth/callback/oidc"
|
|
||||||
matching_mode: strict
|
|
||||||
signing_key_name: "authentik Self-signed Certificate"
|
|
||||||
flows:
|
|
||||||
authorization_slug: default-provider-authorization-implicit-consent
|
|
||||||
invalidation_slug: default-provider-invalidation-flow
|
|
||||||
scopes: [openid, email, profile]
|
|
||||||
- slug: bookstack
|
|
||||||
name: BookStack
|
|
||||||
client_id: bookstack
|
|
||||||
client_secret: "{{ _authentik.bookstack_oidc_secret }}"
|
|
||||||
redirect_uris:
|
|
||||||
- url: "https://wiki.phbe.souveredu.ch/oidc/callback"
|
|
||||||
matching_mode: strict
|
|
||||||
signing_key_name: "authentik Self-signed Certificate"
|
|
||||||
flows:
|
|
||||||
authorization_slug: default-provider-authorization-implicit-consent
|
|
||||||
invalidation_slug: default-provider-invalidation-flow
|
|
||||||
scopes: [openid, email, profile]
|
|
||||||
|
|
||||||
authentik_groups:
|
|
||||||
- name: admins
|
|
||||||
- name: users
|
|
||||||
- name: opnform-admins
|
|
||||||
- name: homarr-admins
|
|
||||||
- name: bookstack-admins
|
|
||||||
|
|
||||||
authentik_local_users:
|
|
||||||
- username: akadmin
|
|
||||||
name: "Authentik Admin"
|
|
||||||
email: "admin@phbe.souveredu.ch"
|
|
||||||
password: "{{ _authentik.admin_password }}"
|
|
||||||
is_active: true
|
|
||||||
groups:
|
|
||||||
- authentik Admins
|
|
||||||
- admins
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
---
|
|
||||||
# Same token as authentik_ldap_outpost.token above — outpost uses it to
|
|
||||||
# authenticate against the authentik server it talks to.
|
|
||||||
_authentik: "{{ lookup('community.hashi_vault.hashi_vault', vault_mount + '/data/authentik', url=vault_addr) }}"
|
|
||||||
|
|
||||||
# Public FQDN resolves (internal DNS view) to the DMZ reverseproxy the
|
|
||||||
# backend subnet can reach, so the outpost->authentik round-trip stays in
|
|
||||||
# the LAN with a valid cert and matches the iss claim authentik emits.
|
|
||||||
authentik_outpost_ldap_host: "https://auth.phbe.souveredu.ch"
|
|
||||||
authentik_outpost_ldap_token: "{{ _authentik.ldap_outpost_token }}"
|
|
||||||
# auth.phbe.* presents a valid Let's Encrypt cert via the reverseproxy, so
|
|
||||||
# verify the chain instead of relying on the role's insecure default.
|
|
||||||
authentik_outpost_ldap_insecure: "false"
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
---
|
|
||||||
# Bao secret <mount>/data/bookstack expected to contain:
|
|
||||||
# db_root_password, db_password, admin_password, oidc_client_secret,
|
|
||||||
# app_key (optional — only set when restoring)
|
|
||||||
_bookstack: "{{ lookup('community.hashi_vault.hashi_vault', vault_mount + '/data/bookstack', url=vault_addr) }}"
|
|
||||||
|
|
||||||
bookstack_domain: "wiki.phbe.souveredu.ch"
|
|
||||||
bookstack_extra_domains:
|
|
||||||
- "wiki.int.phbe.souveredu.ch"
|
|
||||||
bookstack_base_url: "https://wiki.phbe.souveredu.ch"
|
|
||||||
|
|
||||||
# Override the role-default certresolver ("le") with the value used
|
|
||||||
# across this demo (matches traefik_ssl_cert_resolver in group_vars).
|
|
||||||
bookstack_traefik_certresolver: "dns"
|
|
||||||
|
|
||||||
bookstack_db_root_password: "{{ _bookstack.db_root_password }}"
|
|
||||||
bookstack_db_password: "{{ _bookstack.db_password }}"
|
|
||||||
bookstack_admin_password: "{{ _bookstack.admin_password }}"
|
|
||||||
bookstack_admin_email: "admin@phbe.souveredu.ch"
|
|
||||||
bookstack_admin_name: "BookStack Admin"
|
|
||||||
|
|
||||||
# OIDC against Authentik. BookStack compares OIDC_ISSUER strictly against
|
|
||||||
# the `iss` claim in the discovery response, and Authentik emits the
|
|
||||||
# public auth.phbe.* hostname there, so the issuer must use the public
|
|
||||||
# FQDN. That FQDN resolves (internal DNS view) to the DMZ reverseproxy,
|
|
||||||
# which the backend subnet can reach, so the server-to-server calls stay
|
|
||||||
# in the LAN.
|
|
||||||
bookstack_oidc_enabled: true
|
|
||||||
bookstack_oidc_name: "Authentik"
|
|
||||||
bookstack_oidc_issuer: "https://auth.phbe.souveredu.ch/application/o/bookstack/"
|
|
||||||
bookstack_oidc_client_id: "bookstack"
|
|
||||||
bookstack_oidc_client_secret: "{{ _bookstack.oidc_client_secret }}"
|
|
||||||
bookstack_oidc_additional_scopes: "openid profile email"
|
|
||||||
bookstack_oidc_user_to_groups: true
|
|
||||||
bookstack_oidc_groups_claim: "groups"
|
|
||||||
bookstack_oidc_auto_initiate: false
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
---
|
|
||||||
# First entry is the canonical public FQDN. Additional entries cover
|
|
||||||
# internal *.int.* names so nextcloud's WOPI discovery hits collabora
|
|
||||||
# in the LAN with a valid internal cert.
|
|
||||||
collabora_domains:
|
|
||||||
- "office.phbe.souveredu.ch"
|
|
||||||
- "office.int.phbe.souveredu.ch"
|
|
||||||
|
|
||||||
# Hosts allowed to issue WOPI calls. Both names are listed so collabora
|
|
||||||
# accepts the callback from nextcloud regardless of which FQDN it uses.
|
|
||||||
collabora_allowed_domains:
|
|
||||||
- "cloud.phbe.souveredu.ch"
|
|
||||||
- "cloud.int.phbe.souveredu.ch"
|
|
||||||
|
|
||||||
collabora_frame_ancestors:
|
|
||||||
- "cloud.phbe.souveredu.ch"
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
---
|
|
||||||
drawio_domain: "draw.phbe.souveredu.ch"
|
|
||||||
|
|
||||||
# Internal FQDN the DMZ reverseproxy uses as backend host so its TLS
|
|
||||||
# verify matches a cert SAN (the canonical IP-only route has no SAN
|
|
||||||
# and breaks with "cannot validate certificate ... no IP SANs"). Same
|
|
||||||
# split-horizon pattern as cloud.int.* / auth.int.* / office.int.*.
|
|
||||||
drawio_extra_domains:
|
|
||||||
- "draw.int.phbe.souveredu.ch"
|
|
||||||
|
|
||||||
# Gate drawio behind the authentik embedded outpost. The allow-list is
|
|
||||||
# managed on the authentik proxy application (admins + users) so the
|
|
||||||
# Nextcloud drawio iframe works for every authenticated user.
|
|
||||||
# ForwardAuth talks to the embedded outpost on the authentik server's
|
|
||||||
# in-network address. Going via the public FQDN routes through a second
|
|
||||||
# traefik hop that strips/rewrites X-Forwarded-Host, which breaks
|
|
||||||
# authentik's provider matching (it returns 404). Plain HTTP to the
|
|
||||||
# container is the path docs recommend for the embedded outpost.
|
|
||||||
drawio_authentik_forward_auth: true
|
|
||||||
drawio_authentik_forward_auth_url: "http://authentik-server-1:9000/outpost.goauthentik.io/auth/traefik"
|
|
||||||
|
|
@ -1,78 +0,0 @@
|
||||||
---
|
|
||||||
# Bao secret <mount>/data/homarr expected to contain:
|
|
||||||
# secret_encryption_key (64 hex chars), admin_password, oidc_client_secret
|
|
||||||
_homarr: "{{ lookup('community.hashi_vault.hashi_vault', vault_mount + '/data/homarr', url=vault_addr) }}"
|
|
||||||
|
|
||||||
homarr_domain: "home.phbe.souveredu.ch"
|
|
||||||
homarr_extra_domains:
|
|
||||||
- "home.int.phbe.souveredu.ch"
|
|
||||||
homarr_base_url: "https://home.phbe.souveredu.ch"
|
|
||||||
|
|
||||||
homarr_secret_encryption_key: "{{ _homarr.secret_encryption_key }}"
|
|
||||||
homarr_admin_username: "admin"
|
|
||||||
homarr_admin_email: "admin@phbe.souveredu.ch"
|
|
||||||
homarr_admin_password: "{{ _homarr.admin_password }}"
|
|
||||||
|
|
||||||
# OIDC against Authentik. credentials provider stays enabled as a
|
|
||||||
# break-glass account — reach it via /auth/login/credentials when
|
|
||||||
# AUTH_OIDC_AUTO_LOGIN bypasses the normal /login page.
|
|
||||||
#
|
|
||||||
# Issuer must match the `iss` claim authentik emits, which is always the
|
|
||||||
# public FQDN. Homarr (oauth4webapi) does a strict 1:1 comparison between
|
|
||||||
# the discovery response's issuer and this URL — an internal FQDN here
|
|
||||||
# fails with OAUTH_JSON_ATTRIBUTE_COMPARISON_FAILED. The public FQDN
|
|
||||||
# resolves (internal DNS view) to the DMZ reverseproxy, which the backend
|
|
||||||
# subnet can reach, so discovery/token/userinfo stay in the LAN.
|
|
||||||
homarr_auth_providers: "credentials,oidc"
|
|
||||||
homarr_oidc_issuer: "https://auth.phbe.souveredu.ch/application/o/homarr/"
|
|
||||||
homarr_oidc_client_id: "homarr"
|
|
||||||
homarr_oidc_client_secret: "{{ _homarr.oidc_client_secret }}"
|
|
||||||
homarr_oidc_client_name: "Authentik"
|
|
||||||
homarr_oidc_scopes: "openid profile email groups"
|
|
||||||
homarr_oidc_groups_attribute: "groups"
|
|
||||||
homarr_oidc_auto_login: "true"
|
|
||||||
|
|
||||||
# Default board with shortcuts to the other phbern services. Width
|
|
||||||
# values describe horizontal grid cells (1-10 desktop / 6 tablet / 2
|
|
||||||
# mobile, packed left-to-right).
|
|
||||||
homarr_apps:
|
|
||||||
- id: nextcloud
|
|
||||||
name: Nextcloud
|
|
||||||
description: "Cloud Storage & Collaboration"
|
|
||||||
icon: https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/nextcloud.png
|
|
||||||
href: https://cloud.phbe.souveredu.ch
|
|
||||||
width: 2
|
|
||||||
- id: collabora
|
|
||||||
name: Collabora Office
|
|
||||||
icon: https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/collaboraonline.png
|
|
||||||
href: https://office.phbe.souveredu.ch
|
|
||||||
width: 2
|
|
||||||
- id: drawio
|
|
||||||
name: Draw.io
|
|
||||||
icon: https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/drawio.png
|
|
||||||
href: https://draw.phbe.souveredu.ch
|
|
||||||
width: 2
|
|
||||||
- id: send
|
|
||||||
name: Send
|
|
||||||
description: "Encrypted file-share"
|
|
||||||
icon: https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/firefox-send.png
|
|
||||||
href: https://send.phbe.souveredu.ch
|
|
||||||
width: 2
|
|
||||||
- id: opnform
|
|
||||||
name: OpnForm
|
|
||||||
description: "Self-hosted forms"
|
|
||||||
icon: https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/opnform.png
|
|
||||||
href: https://forms.phbe.souveredu.ch
|
|
||||||
width: 2
|
|
||||||
- id: bookstack
|
|
||||||
name: BookStack
|
|
||||||
description: "Wiki & documentation"
|
|
||||||
icon: https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/bookstack.png
|
|
||||||
href: https://wiki.phbe.souveredu.ch
|
|
||||||
width: 2
|
|
||||||
- id: authentik
|
|
||||||
name: Authentik
|
|
||||||
description: "Identity provider"
|
|
||||||
icon: https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/png/authentik.png
|
|
||||||
href: https://auth.phbe.souveredu.ch
|
|
||||||
width: 2
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
---
|
|
||||||
# application host runs: authentik, authentik-ldap-outpost,
|
|
||||||
# nextcloud, collabora, drawio, send, opnform, homarr, bookstack
|
|
||||||
|
|
@ -1,121 +0,0 @@
|
||||||
---
|
|
||||||
# Bao secret <mount>/data/nextcloud expected to contain:
|
|
||||||
# postgres_password, admin_password
|
|
||||||
_nextcloud: "{{ lookup('community.hashi_vault.hashi_vault', vault_mount + '/data/nextcloud', url=vault_addr) }}"
|
|
||||||
_authentik: "{{ lookup('community.hashi_vault.hashi_vault', vault_mount + '/data/authentik', url=vault_addr) }}"
|
|
||||||
|
|
||||||
# No nextcloud_image pin: the role default (nextcloud:fpm) already ships
|
|
||||||
# the fix for the PHP UserConfig::getValueBool TypeError (#59629).
|
|
||||||
|
|
||||||
# First entry is the canonical public FQDN (used for OVERWRITEHOST and
|
|
||||||
# OIDC redirects). Additional entries cover internal *.int.* names so
|
|
||||||
# collabora's WOPI callbacks hit nextcloud on a name with a valid
|
|
||||||
# internal cert instead of routing through the DMZ.
|
|
||||||
nextcloud_domains:
|
|
||||||
- "cloud.phbe.souveredu.ch"
|
|
||||||
- "cloud.int.phbe.souveredu.ch"
|
|
||||||
nextcloud_postgres_password: "{{ _nextcloud.postgres_password }}"
|
|
||||||
nextcloud_admin_user: admin
|
|
||||||
nextcloud_admin_password: "{{ _nextcloud.admin_password }}"
|
|
||||||
|
|
||||||
nextcloud_enable_notify_push: true
|
|
||||||
# Use the internal FQDN for the notify_push setup check so curl from the
|
|
||||||
# nextcloud container hits the local traefik directly instead of
|
|
||||||
# hairpinning through the DMZ reverseproxy.
|
|
||||||
nextcloud_notify_push_domain: "cloud.int.phbe.souveredu.ch"
|
|
||||||
|
|
||||||
# Collabora integration
|
|
||||||
# wopi_url (server-to-server: nextcloud calls collabora for discovery /
|
|
||||||
# capabilities) goes to the internal FQDN so the call stays in the LAN.
|
|
||||||
# public_wopi_url is what the browser loads the office iframe from — that
|
|
||||||
# stays on the public name reachable through the DMZ.
|
|
||||||
nextcloud_enable_collabora: true
|
|
||||||
nextcloud_collabora_domain: "office.int.phbe.souveredu.ch"
|
|
||||||
nextcloud_collabora_public_domain: "office.phbe.souveredu.ch"
|
|
||||||
|
|
||||||
# Draw.io integration
|
|
||||||
nextcloud_enable_drawio: true
|
|
||||||
nextcloud_drawio_url: "https://draw.phbe.souveredu.ch"
|
|
||||||
|
|
||||||
nextcloud_apps_to_install:
|
|
||||||
- groupfolders
|
|
||||||
- richdocuments
|
|
||||||
- spreed
|
|
||||||
- user_ldap
|
|
||||||
- user_oidc
|
|
||||||
- whiteboard
|
|
||||||
- drawio
|
|
||||||
- files_lock
|
|
||||||
- notify_push
|
|
||||||
|
|
||||||
# S3 primary storage via Garage — server-to-server, so use the internal FQDN.
|
|
||||||
# Resolves through the internal DNS to the storage host and presents a valid
|
|
||||||
# cert from the local traefik on storage.
|
|
||||||
nextcloud_use_s3_storage: true
|
|
||||||
nextcloud_s3_key: "{{ lookup('digitalboard.core.garage_credentials', 'nextcloud', host='storage')['key_id'] }}"
|
|
||||||
nextcloud_s3_secret: "{{ lookup('digitalboard.core.garage_credentials', 'nextcloud', host='storage')['secret_key'] }}"
|
|
||||||
nextcloud_s3_bucket: "nextcloud"
|
|
||||||
nextcloud_s3_host: "s3.int.phbe.souveredu.ch"
|
|
||||||
nextcloud_s3_port: 443
|
|
||||||
nextcloud_s3_ssl: true
|
|
||||||
nextcloud_s3_usepath_style: true
|
|
||||||
|
|
||||||
# OIDC discovery/token/userinfo and the S3 backend both target FQDNs
|
|
||||||
# that resolve to RFC1918 addresses (auth.phbe.* via the reverseproxy,
|
|
||||||
# s3.int.* directly), which Nextcloud's DnsPinMiddleware would otherwise
|
|
||||||
# block as "local server access".
|
|
||||||
nextcloud_allow_local_remote_servers: true
|
|
||||||
|
|
||||||
# Share the LDAP docker network with the authentik LDAP outpost
|
|
||||||
nextcloud_extra_networks:
|
|
||||||
- ldap
|
|
||||||
|
|
||||||
# LDAP backend (Authentik LDAP outpost)
|
|
||||||
nextcloud_ldap_enabled: true
|
|
||||||
nextcloud_ldap_config:
|
|
||||||
ldapHost: "ldap://authentik-outpost-ldap-ldap-1"
|
|
||||||
ldapPort: "3389"
|
|
||||||
ldapAgentName: "cn=akadmin,ou=users,dc=phbe,dc=souveredu,dc=ch"
|
|
||||||
ldapAgentPassword: "{{ _authentik.admin_password }}"
|
|
||||||
ldapBase: "dc=phbe,dc=souveredu,dc=ch"
|
|
||||||
ldapBaseUsers: "ou=users,dc=phbe,dc=souveredu,dc=ch"
|
|
||||||
ldapTLS: "0"
|
|
||||||
turnOffCertCheck: "1"
|
|
||||||
ldapUserFilter: "(&(objectClass=user)(cn=*))"
|
|
||||||
ldapUserFilterObjectclass: "user"
|
|
||||||
ldapLoginFilter: "(&(objectClass=user)(cn=%uid))"
|
|
||||||
ldapLoginFilterUsername: "1"
|
|
||||||
ldapUserDisplayName: "cn"
|
|
||||||
ldapEmailAttribute: "mail"
|
|
||||||
ldapExpertUsernameAttr: "cn"
|
|
||||||
ldapExpertUUIDUserAttr: "uid"
|
|
||||||
ldapExpertUUIDGroupAttr: "uid"
|
|
||||||
ldapBaseGroups: "ou=groups,dc=phbe,dc=souveredu,dc=ch"
|
|
||||||
ldapGroupFilter: "(&(objectClass=group))"
|
|
||||||
ldapGroupFilterObjectclass: "group"
|
|
||||||
ldapGroupDisplayName: "cn"
|
|
||||||
ldapGroupMemberAssocAttr: "member"
|
|
||||||
ldapAdminGroup: "admins"
|
|
||||||
ldapCacheTTL: "600"
|
|
||||||
ldapPagingSize: "500"
|
|
||||||
ldapExperiencedAdmin: "1"
|
|
||||||
ldapConfigurationActive: "1"
|
|
||||||
|
|
||||||
# OIDC providers for login (Authentik)
|
|
||||||
nextcloud_oidc_providers:
|
|
||||||
- identifier: authentik
|
|
||||||
display_name: "Login with Authentik"
|
|
||||||
client_id: nextcloud
|
|
||||||
client_secret: "{{ _authentik.nextcloud_oidc_secret }}"
|
|
||||||
# Discovery via the public FQDN. It resolves (internal DNS view) to
|
|
||||||
# the DMZ reverseproxy, which the backend subnet can now reach, so
|
|
||||||
# the server-to-server call stays in the LAN while the iss claim and
|
|
||||||
# all listed endpoints match the public hostname the browser sees
|
|
||||||
# during login — no host-rewrite or /etc/hosts pin needed.
|
|
||||||
discovery_url: "https://auth.phbe.souveredu.ch/application/o/nextcloud/.well-known/openid-configuration"
|
|
||||||
scope: "openid email profile"
|
|
||||||
unique_uid: true
|
|
||||||
mapping:
|
|
||||||
uid: preferred_username
|
|
||||||
display_name: name
|
|
||||||
email: email
|
|
||||||
|
|
@ -1,50 +0,0 @@
|
||||||
---
|
|
||||||
# Bao secret <mount>/data/opnform expected to contain:
|
|
||||||
# app_key (must start with "base64:"), jwt_secret, front_api_secret,
|
|
||||||
# db_password, admin_password, oidc_client_secret
|
|
||||||
_opnform: "{{ lookup('community.hashi_vault.hashi_vault', vault_mount + '/data/opnform', url=vault_addr) }}"
|
|
||||||
_authentik: "{{ lookup('community.hashi_vault.hashi_vault', vault_mount + '/data/authentik', url=vault_addr) }}"
|
|
||||||
|
|
||||||
opnform_domain: "forms.phbe.souveredu.ch"
|
|
||||||
opnform_extra_domains:
|
|
||||||
- "forms.int.phbe.souveredu.ch"
|
|
||||||
opnform_base_url: "https://forms.phbe.souveredu.ch"
|
|
||||||
|
|
||||||
opnform_app_key: "{{ _opnform.app_key }}"
|
|
||||||
opnform_jwt_secret: "{{ _opnform.jwt_secret }}"
|
|
||||||
opnform_front_api_secret: "{{ _opnform.front_api_secret }}"
|
|
||||||
opnform_db_password: "{{ _opnform.db_password }}"
|
|
||||||
|
|
||||||
# Bootstrap admin via API on first run so the manual setup page is
|
|
||||||
# skipped. The admin credentials are also required to seed the OIDC
|
|
||||||
# IdentityConnection through OpnForm's API (only an authenticated admin
|
|
||||||
# can create connections).
|
|
||||||
opnform_admin_name: "OpnForm Admin"
|
|
||||||
opnform_admin_email: "admin@phbe.souveredu.ch"
|
|
||||||
opnform_admin_password: "{{ _opnform.admin_password }}"
|
|
||||||
|
|
||||||
# OIDC against Authentik. The public auth.phbe.* FQDN resolves (internal
|
|
||||||
# DNS view) to the DMZ reverseproxy, which the backend subnet can reach,
|
|
||||||
# so OpnForm's discovery/token/userinfo calls stay in the LAN while the
|
|
||||||
# iss claim matches the public hostname browsers see during login.
|
|
||||||
opnform_oidc_enabled: true
|
|
||||||
# Issuer must use the public FQDN: OpnForm validates the token's `iss`
|
|
||||||
# claim against this value, and Authentik emits the public hostname there.
|
|
||||||
opnform_oidc_issuer: "https://auth.phbe.souveredu.ch/application/o/opnform/"
|
|
||||||
opnform_oidc_client_id: "opnform"
|
|
||||||
opnform_oidc_client_secret: "{{ _opnform.oidc_client_secret }}"
|
|
||||||
opnform_oidc_client_name: "Authentik"
|
|
||||||
opnform_oidc_slug: "authentik"
|
|
||||||
opnform_oidc_domain: "phbe.souveredu.ch"
|
|
||||||
opnform_oidc_admin_group: "opnform-admins"
|
|
||||||
|
|
||||||
# Disable password login entirely — every user goes through Authentik.
|
|
||||||
# All real users have @phbe.souveredu.ch addresses (matching
|
|
||||||
# opnform_oidc_domain above), so no password fallback is needed.
|
|
||||||
opnform_oidc_force_login: true
|
|
||||||
|
|
||||||
# `/` and `/login` are intercepted and jump straight to Authentik.
|
|
||||||
# Public form deep-links (`/forms/<slug>`, `/admin/...`) keep working.
|
|
||||||
# Break-glass: /login?bypass=1 reaches the email form when the IdP is
|
|
||||||
# down.
|
|
||||||
opnform_oidc_sso_entrypoint: true
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
---
|
|
||||||
# Send: anonymized self-hosted file-share (no login). First entry is the
|
|
||||||
# canonical public FQDN (used as BASE_URL); the *.int.* entry covers the
|
|
||||||
# server-to-server hop from the DMZ reverseproxy with a cert SAN that
|
|
||||||
# matches the backend hostname (same split-horizon pattern as cloud/draw).
|
|
||||||
send_domains:
|
|
||||||
- "send.phbe.souveredu.ch"
|
|
||||||
- "send.int.phbe.souveredu.ch"
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
||||||
---
|
|
||||||
# Services hosted on `application` that the DMZ reverseproxy should
|
|
||||||
# forward public traffic to. The DMZ traefik picks this up via
|
|
||||||
# hostvars[backend].traefik_dmz_exposed_services and renders a router +
|
|
||||||
# service for each entry into /config/services.yml.
|
|
||||||
traefik_dmz_exposed_services:
|
|
||||||
- name: authentik
|
|
||||||
domain: auth.phbe.souveredu.ch
|
|
||||||
backend_host: auth.int.phbe.souveredu.ch
|
|
||||||
port: 443
|
|
||||||
protocol: https
|
|
||||||
- name: nextcloud
|
|
||||||
domain: cloud.phbe.souveredu.ch
|
|
||||||
backend_host: cloud.int.phbe.souveredu.ch
|
|
||||||
port: 443
|
|
||||||
protocol: https
|
|
||||||
- name: collabora
|
|
||||||
domain: office.phbe.souveredu.ch
|
|
||||||
backend_host: office.int.phbe.souveredu.ch
|
|
||||||
port: 443
|
|
||||||
protocol: https
|
|
||||||
- name: drawio
|
|
||||||
domain: draw.phbe.souveredu.ch
|
|
||||||
backend_host: draw.int.phbe.souveredu.ch
|
|
||||||
port: 443
|
|
||||||
protocol: https
|
|
||||||
- name: send
|
|
||||||
domain: send.phbe.souveredu.ch
|
|
||||||
backend_host: send.int.phbe.souveredu.ch
|
|
||||||
port: 443
|
|
||||||
protocol: https
|
|
||||||
- name: opnform
|
|
||||||
domain: forms.phbe.souveredu.ch
|
|
||||||
backend_host: forms.int.phbe.souveredu.ch
|
|
||||||
port: 443
|
|
||||||
protocol: https
|
|
||||||
- name: homarr
|
|
||||||
domain: home.phbe.souveredu.ch
|
|
||||||
backend_host: home.int.phbe.souveredu.ch
|
|
||||||
port: 443
|
|
||||||
protocol: https
|
|
||||||
- name: bookstack
|
|
||||||
domain: wiki.phbe.souveredu.ch
|
|
||||||
backend_host: wiki.int.phbe.souveredu.ch
|
|
||||||
port: 443
|
|
||||||
protocol: https
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
---
|
|
||||||
traefik_mode: dmz
|
|
||||||
|
|
||||||
# The DMZ traefik discovers which services to expose by reading
|
|
||||||
# traefik_dmz_exposed_services from each backend host's host_vars
|
|
||||||
# (application/traefik.yml, storage/traefik.yml). See the role's
|
|
||||||
# tasks/main.yml — set_fact "Build service registry from backend
|
|
||||||
# servers (DMZ mode)".
|
|
||||||
|
|
||||||
# From the DMZ network the public ns1 IP (193.43.183.169) is not
|
|
||||||
# reachable on port 53, but the internal address (172.16.9.169) is.
|
|
||||||
# Override the group-level traefik_acme_dns_nameserver from bao so
|
|
||||||
# lego's RFC2136 updates land at the internal interface. The TSIG
|
|
||||||
# key/secret are the same; only the transport target changes.
|
|
||||||
traefik_acme_dns_nameserver: "172.16.9.169"
|
|
||||||
|
|
||||||
# Lego's propagation check normally polls the NS hostnames listed in
|
|
||||||
# the zone's SOA (ns1.digitalboard.ch.) — which resolves to the
|
|
||||||
# public IP that's unreachable from this DMZ host. Skip that check;
|
|
||||||
# lego still polls via the resolver above before asking LE to
|
|
||||||
# validate.
|
|
||||||
traefik_acme_disable_ans_checks: true
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
---
|
|
||||||
# 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"
|
|
||||||
|
|
@ -1,51 +0,0 @@
|
||||||
---
|
|
||||||
# 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"]
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
---
|
|
||||||
# storage host runs: garage (S3 + WebUI)
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
---
|
|
||||||
# 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
|
|
||||||
|
|
@ -22,7 +22,6 @@ all:
|
||||||
backend_servers:
|
backend_servers:
|
||||||
hosts:
|
hosts:
|
||||||
application:
|
application:
|
||||||
storage:
|
|
||||||
|
|
||||||
garage_servers:
|
garage_servers:
|
||||||
hosts:
|
hosts:
|
||||||
|
|
@ -32,6 +31,10 @@ all:
|
||||||
hosts:
|
hosts:
|
||||||
application:
|
application:
|
||||||
|
|
||||||
|
opencloud_servers:
|
||||||
|
hosts:
|
||||||
|
application:
|
||||||
|
|
||||||
collabora_servers:
|
collabora_servers:
|
||||||
hosts:
|
hosts:
|
||||||
application:
|
application:
|
||||||
|
|
@ -42,32 +45,4 @@ all:
|
||||||
|
|
||||||
authentik_servers:
|
authentik_servers:
|
||||||
hosts:
|
hosts:
|
||||||
application:
|
application:
|
||||||
|
|
||||||
authentik_outpost_ldap_servers:
|
|
||||||
hosts:
|
|
||||||
application:
|
|
||||||
|
|
||||||
# Proxy (ForwardAuth) outpost co-located with garage on storage, so
|
|
||||||
# the garage-webui ForwardAuth subrequest stays on the local docker
|
|
||||||
# network instead of crossing an extra reverseproxy hop (which mangles
|
|
||||||
# X-Forwarded-Host and breaks the embedded outpost's app matching).
|
|
||||||
authentik_outpost_proxy_servers:
|
|
||||||
hosts:
|
|
||||||
storage:
|
|
||||||
|
|
||||||
send_servers:
|
|
||||||
hosts:
|
|
||||||
application:
|
|
||||||
|
|
||||||
opnform_servers:
|
|
||||||
hosts:
|
|
||||||
application:
|
|
||||||
|
|
||||||
homarr_servers:
|
|
||||||
hosts:
|
|
||||||
application:
|
|
||||||
|
|
||||||
bookstack_servers:
|
|
||||||
hosts:
|
|
||||||
application:
|
|
||||||
|
|
@ -70,12 +70,6 @@
|
||||||
roles:
|
roles:
|
||||||
- digitalboard.core.authentik_outpost_ldap
|
- digitalboard.core.authentik_outpost_ldap
|
||||||
|
|
||||||
- name: Deploy authentik proxy outpost
|
|
||||||
hosts: authentik_outpost_proxy_servers
|
|
||||||
become: yes
|
|
||||||
roles:
|
|
||||||
- digitalboard.core.authentik_outpost_proxy
|
|
||||||
|
|
||||||
- name: Deploy nextcloud service
|
- name: Deploy nextcloud service
|
||||||
hosts: nextcloud_servers
|
hosts: nextcloud_servers
|
||||||
become: yes
|
become: yes
|
||||||
|
|
|
||||||
|
|
@ -154,27 +154,12 @@ ensure_key authentik secret_key gen_hex64
|
||||||
ensure_key authentik postgres_password gen_pass
|
ensure_key authentik postgres_password gen_pass
|
||||||
ensure_key authentik admin_password gen_pass
|
ensure_key authentik admin_password gen_pass
|
||||||
ensure_key authentik ldap_outpost_token gen_hex32
|
ensure_key authentik ldap_outpost_token gen_hex32
|
||||||
ensure_key authentik proxy_outpost_token gen_hex32
|
|
||||||
ensure_key authentik nextcloud_oidc_secret gen_hex32
|
ensure_key authentik nextcloud_oidc_secret gen_hex32
|
||||||
ensure_key authentik opnform_oidc_secret gen_hex32
|
ensure_key authentik opnform_oidc_secret gen_hex32
|
||||||
ensure_key authentik homarr_oidc_secret gen_hex32
|
ensure_key authentik homarr_oidc_secret gen_hex32
|
||||||
ensure_key authentik bookstack_oidc_secret gen_hex32
|
ensure_key authentik bookstack_oidc_secret gen_hex32
|
||||||
write_secret authentik
|
write_secret authentik
|
||||||
|
|
||||||
echo "-> nextcloud"
|
|
||||||
read_secret nextcloud
|
|
||||||
ensure_key nextcloud postgres_password gen_long_pass
|
|
||||||
ensure_key nextcloud admin_password gen_pass
|
|
||||||
write_secret nextcloud
|
|
||||||
|
|
||||||
echo "-> garage"
|
|
||||||
read_secret garage
|
|
||||||
ensure_key garage rpc_secret gen_hex32
|
|
||||||
ensure_key garage admin_token gen_hex32
|
|
||||||
ensure_key garage metrics_token gen_hex32
|
|
||||||
ensure_key garage webui_password gen_pass
|
|
||||||
write_secret garage
|
|
||||||
|
|
||||||
echo "-> opnform"
|
echo "-> opnform"
|
||||||
read_secret opnform
|
read_secret opnform
|
||||||
ensure_key opnform app_key gen_app_key
|
ensure_key opnform app_key gen_app_key
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue