feat(demo): add full inventories for mbazürich and phbern
Both demo sites had only a hosts.yml, so every role ran on its defaults (authentik.local.test etc.) and nothing was reachable under the real FQDN. Add the complete group_vars + host_vars analogous to gymburgdorf, with the mbaz.souveredu.ch / phbe.souveredu.ch domain bases, matching Bao mounts, DMZ split-horizon (public + *.int.*), authentik OIDC/LDAP/proxy outposts, nextcloud with S3+LDAP+OIDC, collabora, drawio, garage, send, opnform, homarr and bookstack. authentik_domains lists the *.int.* name too so Traefik requests a cert the DMZ can verify; the storage proxy outpost carries a config block (required by the outpost blueprint serializer).
This commit is contained in:
parent
a8c8ac3e1e
commit
d45e358efc
44 changed files with 1458 additions and 10 deletions
167
inventories/demo-phbern/host_vars/application/authentik.yml
Normal file
167
inventories/demo-phbern/host_vars/application/authentik.yml
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
---
|
||||
# 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
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
---
|
||||
# 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"
|
||||
36
inventories/demo-phbern/host_vars/application/bookstack.yml
Normal file
36
inventories/demo-phbern/host_vars/application/bookstack.yml
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
---
|
||||
# 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
|
||||
16
inventories/demo-phbern/host_vars/application/collabora.yml
Normal file
16
inventories/demo-phbern/host_vars/application/collabora.yml
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
---
|
||||
# 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"
|
||||
20
inventories/demo-phbern/host_vars/application/drawio.yml
Normal file
20
inventories/demo-phbern/host_vars/application/drawio.yml
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
---
|
||||
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"
|
||||
78
inventories/demo-phbern/host_vars/application/homarr.yml
Normal file
78
inventories/demo-phbern/host_vars/application/homarr.yml
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
---
|
||||
# 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
|
||||
3
inventories/demo-phbern/host_vars/application/main.yml
Normal file
3
inventories/demo-phbern/host_vars/application/main.yml
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
# application host runs: authentik, authentik-ldap-outpost,
|
||||
# nextcloud, collabora, drawio, send, opnform, homarr, bookstack
|
||||
121
inventories/demo-phbern/host_vars/application/nextcloud.yml
Normal file
121
inventories/demo-phbern/host_vars/application/nextcloud.yml
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
---
|
||||
# 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
|
||||
50
inventories/demo-phbern/host_vars/application/opnform.yml
Normal file
50
inventories/demo-phbern/host_vars/application/opnform.yml
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
---
|
||||
# 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
|
||||
8
inventories/demo-phbern/host_vars/application/send.yml
Normal file
8
inventories/demo-phbern/host_vars/application/send.yml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
# 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"
|
||||
46
inventories/demo-phbern/host_vars/application/traefik.yml
Normal file
46
inventories/demo-phbern/host_vars/application/traefik.yml
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
---
|
||||
# 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
|
||||
Loading…
Add table
Add a link
Reference in a new issue