feat(demo-gymburgdorf): replace Collabora with the Euro-Office document server #3

Open
Simon wants to merge 5 commits from feat/eurooffice into main
Owner

Summary

  • demo-gymburgdorf switches its office backend from Collabora to Euro-Office: new host_vars/application/eurooffice.yml, nextcloud_enable_collabora: false, nextcloud_enable_eurooffice: true, and the eurooffice app added to the install list. richdocuments stays listed but disabled, so switching back is a variable flip.
  • DocumentServerUrl uses the public FQDN (the browser loads the editor from it), StorageUrl the internal one (the document server reads and writes the file in the LAN) — the inverse of Collabora's split-horizon.
  • Nextcloud moves to 34.0.3-fpm: the connector app declares >=33.0.0, and the old 33.0.3 pin only existed for a PHP 8.4 TypeError that is fixed upstream.
  • scripts/bao-seed.sh gains the keys the inventories already read: a whole missing nextcloud path (postgres_password, admin_password, eurooffice_jwt) plus authentik/proxy_outpost_token. Both gaps only showed up at deploy time as 'dict object' has no attribute ....
  • collabora_servers is kept as an empty group so the collabora play resolves to zero hosts rather than failing.

Test plan

  • ansible-inventory --list resolves, eurooffice_servers holds application, collabora_servers is empty
  • ansible-playbook --syntax-check passes; play list shows collabora at 0 hosts and eurooffice at 1
  • Bao lookups resolve and both JWT variables read the same key (jwt_match=True)
  • bao-seed.sh --dry-run against the live mount reports no key as missing
  • Deployed against demo-gymburgdorf: document server healthy, Nextcloud on 34.0.3, JWT-signed CommandService answers {"error":0,"version":"9.3.1.37"}
  • Open a .docx/.xlsx in a browser and save it

Notes

requirements.yml temporarily pins the collection to the feat/eurooffice branch, because digitalboard.core PR 13 carries the role this inventory needs. Revert to version: main once that PR lands.

## Summary - `demo-gymburgdorf` switches its office backend from Collabora to Euro-Office: new `host_vars/application/eurooffice.yml`, `nextcloud_enable_collabora: false`, `nextcloud_enable_eurooffice: true`, and the `eurooffice` app added to the install list. `richdocuments` stays listed but disabled, so switching back is a variable flip. - `DocumentServerUrl` uses the public FQDN (the browser loads the editor from it), `StorageUrl` the internal one (the document server reads and writes the file in the LAN) — the inverse of Collabora's split-horizon. - Nextcloud moves to `34.0.3-fpm`: the connector app declares `>=33.0.0`, and the old 33.0.3 pin only existed for a PHP 8.4 TypeError that is fixed upstream. - `scripts/bao-seed.sh` gains the keys the inventories already read: a whole missing `nextcloud` path (`postgres_password`, `admin_password`, `eurooffice_jwt`) plus `authentik/proxy_outpost_token`. Both gaps only showed up at deploy time as `'dict object' has no attribute ...`. - `collabora_servers` is kept as an empty group so the collabora play resolves to zero hosts rather than failing. ## Test plan - [x] `ansible-inventory --list` resolves, `eurooffice_servers` holds `application`, `collabora_servers` is empty - [x] `ansible-playbook --syntax-check` passes; play list shows collabora at 0 hosts and eurooffice at 1 - [x] Bao lookups resolve and both JWT variables read the same key (`jwt_match=True`) - [x] `bao-seed.sh --dry-run` against the live mount reports no key as missing - [x] Deployed against `demo-gymburgdorf`: document server healthy, Nextcloud on 34.0.3, JWT-signed `CommandService` answers `{"error":0,"version":"9.3.1.37"}` - [ ] Open a `.docx`/`.xlsx` in a browser and save it ## Notes `requirements.yml` temporarily pins the collection to the `feat/eurooffice` branch, because digitalboard.core PR 13 carries the role this inventory needs. Revert to `version: main` once that PR lands.
The firewall now permits the backend subnet (172.16.19.0/24) to reach the
DMZ reverseproxy on 443, so server-to-server calls can use the public
FQDN over the reverseproxy instead of the previous workarounds:

- Remove the `*_extra_hosts` pins from nextcloud, opnform, bookstack and
  homarr; their OIDC discovery/issuer now uses the public auth.gymb.* FQDN
  (verified: discovery returns 200 with the public iss over the reverseproxy).
- Switch nextcloud OIDC discovery_url from auth.int.* to auth.gymb.*.
- Drop authentik_host_rewrite_domains and authentik_outpost_domains; point
  the LDAP outpost (both host_vars) at the public auth.gymb.* FQDN.
- Repoint the garage-webui ForwardAuth from the never-functional dedicated
  outpost FQDN to auth.gymb.*. The embedded outpost only serves the auth
  path when Host is a configured authentik_domain and matches the protected
  app via X-Forwarded-Host, so auth.gymb.* stays pinned to the application
  host on storage to bypass the reverseproxy's X-Forwarded-Host stripping.

The *.int.* names and their cert SANs are kept: the DMZ verifies the
backend cert (acme cert_mode) and connects by name, so they remain
structural to the DMZ->backend hop. The console.s3 DMZ route limitation
is pre-existing and tracked separately.
Finish the garage-webui SSO that the DNS cleanup left broken. Two coupled
fixes, both relying on roles added in digitalboard.core:

- console.s3 now has an internal name. garage_webui_domains lists both the
  public and console.s3.int.* FQDN, and the DMZ garage-webui route sets
  backend_host: console.s3.int.* so the DMZ->storage hop verifies the
  backend cert against a matching SAN instead of failing on a raw IP (500).

- garage-webui ForwardAuth moves off the embedded outpost (cross-host hop
  mangled X-Forwarded-Host -> 404) onto a dedicated proxy outpost deployed
  on storage (authentik_outpost_proxy). The garage Traefik middleware now
  talks to it over the local docker network, and the storage-proxy-outpost
  is registered in authentik with the garage-webui provider. The stale
  auth.gymb pin on storage is dropped; the outpost reaches authentik via
  the reverseproxy (firewall now permits backend -> DMZ).

Requires a new bao secret key: <mount>/data/authentik proxy_outpost_token.
Both outposts reach authentik over auth.gymb.*, which presents a valid
Let's Encrypt cert via the reverseproxy (verified: ssl_verify_result=0
from the storage subnet). Drop the insecure TLS skip:

- proxy outpost: authentik_outpost_proxy_insecure -> "false"
- ldap outpost: pin authentik_outpost_ldap_insecure "false" instead of
  relying on the role default ("true").

Addresses the automated security review finding (TLS verification disabled).
The nextcloud path was missing entirely even though host_vars has always
read postgres_password and admin_password from it, and authentik lacked
proxy_outpost_token which the proxy-outpost token pinning needs. Both
gaps only surfaced at deploy time as "'dict object' has no attribute
...", because the values had been created by hand in the live mount.

Signed-off-by: Simon Bärlocher <simon@whatwedo.ch>
Euro-Office speaks the ONLYOFFICE protocol with a shared JWT instead of
WOPI, so the eurooffice app takes over from richdocuments; richdocuments
stays in the app list but disabled, making the way back a variable flip
rather than a reinstall. Both apps claim the same office mimetypes, so
only one of the two enable flags may be true.

DocumentServerUrl is the public FQDN because the browser loads the editor
from it, while StorageUrl uses the internal name so the document server
reads and writes the file inside the LAN. That inverts Collabora's
split-horizon, where wopi_url was the internal one.

Nextcloud moves to 34.0.3 in the same step: the eurooffice connector
needs >=33, and the 33.0.3 pin only existed for a PHP 8.4 TypeError that
is fixed upstream. collabora_servers is kept as an empty group so the
play resolves to zero hosts instead of failing.

Signed-off-by: Simon Bärlocher <simon@whatwedo.ch>
digitalboard.core PR 13 carries the eurooffice role and the nextcloud
connector, so the inventory above cannot deploy from `main` yet. Revert
this to `version: main` once that PR lands. Also drop `--diff` from the
gymburgdorf deploy target, which made every templated secret show up in
the run output.

Signed-off-by: Simon Bärlocher <simon@whatwedo.ch>
The seed script only generated authentik LDAP, opnform, homarr and
bookstack secrets. Proxy outposts, garage and nextcloud were never
seeded, so a fresh demo mount was missing garage/*, nextcloud/* and
authentik/proxy_outpost_token — the proxy outpost then failed to
authenticate (403) and garage/nextcloud roles aborted on missing vault
keys. Add the three blocks; merge semantics keep existing keys.
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).
Signed-off-by: Simon Bärlocher <simon@whatwedo.ch>

# Conflicts:
#	scripts/bao-seed.sh
Same move as gymburgdorf, now that both sites have full inventories:
richdocuments gives way to the eurooffice connector but stays installed
as the rollback path, DocumentServerUrl takes the public FQDN while
StorageUrl keeps the document server's file access inside the LAN, and
collabora_servers becomes an empty group so its play resolves to zero
hosts.

Both sites also drop the rolling `nextcloud:fpm` default for a 34.0.3
pin: the connector needs >=33, and a shared code volume across fpm
replicas makes an unnoticed major release an unplanned migration.

Signed-off-by: Simon Bärlocher <simon@whatwedo.ch>
This pull request can be merged automatically.
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin feat/eurooffice:feat/eurooffice
git switch feat/eurooffice

Merge

Merge the changes and update on Forgejo.

Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.

git switch main
git merge --no-ff feat/eurooffice
git switch feat/eurooffice
git rebase main
git switch main
git merge --ff-only feat/eurooffice
git switch feat/eurooffice
git rebase main
git switch main
git merge --no-ff feat/eurooffice
git switch main
git merge --squash feat/eurooffice
git switch main
git merge --ff-only feat/eurooffice
git switch main
git merge feat/eurooffice
git push origin main
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
souveredu/reference-ansible!3
No description provided.