feat(ess_pro): deploy Element Server Suite Pro via K3s + Helm

Adds k3s and ess_pro roles to replace the planned Nextcloud Talk
stack. Integrates with existing Keycloak (OIDC), Garage (S3 media)
and OpenBao (secrets). Hostnames under digitalboard.ch.
This commit is contained in:
Tobias Wüst 2026-05-27 23:46:37 +02:00
parent c11f019aae
commit 01fd12d75c
18 changed files with 1098 additions and 0 deletions

View file

@ -0,0 +1,92 @@
# SPDX-License-Identifier: MIT-0
---
# inventory/group_vars/ess_servers.yml
# Public configuration for the ESS Pro deployment. All secrets are pulled
# from OpenBao at runtime — same pattern as bookstack/opnform/homarr.
# ---- Matrix identity ----------------------------------------------------
ess_pro_server_name: "digitalboard.ch"
# Hostnames default to:
# matrix.digitalboard.ch (Synapse)
# mas.digitalboard.ch (Matrix Authentication Service)
# chat.digitalboard.ch (Element Web)
# admin.digitalboard.ch (Element Admin Panel)
# rtc.digitalboard.ch (Matrix RTC / LiveKit)
# `auth.digitalboard.ch` is intentionally avoided — Keycloak already owns it.
# ---- DMZ Traefik terminates TLS -----------------------------------------
ess_pro_tls_terminate_externally: true
# ---- External Postgres --------------------------------------------------
# Disable for first PoC iteration (uses chart-internal Postgres).
ess_pro_postgres_external: false
# ess_pro_postgres_host: "postgres.svc.digitalboard.ch"
# ---- Delegated auth via the Digitalboard Keycloak -----------------------
ess_pro_oidc_enabled: true
ess_pro_oidc_issuer: "https://auth.digitalboard.ch/realms/Digitalboard"
ess_pro_oidc_client_id: "ess-mas"
ess_pro_oidc_provider_name: "Digitalboard"
# ---- Garage S3 media store ----------------------------------------------
ess_pro_s3_media_enabled: true
ess_pro_s3_endpoint: "https://s3.digitalboard.ch"
ess_pro_s3_bucket: "ess-media"
# ---- Matrix RTC / LiveKit -----------------------------------------------
# Public-facing IP of the DMZ NAT so LiveKit publishes the right ICE
# candidates. Use the same address that the DMZ Traefik lives behind.
ess_pro_rtc_external_ip: "203.0.113.42" # placeholder — set for your env
# =============================================================================
# Secrets — sourced from OpenBao via community.hashi_vault, same as the
# other digitalboard.core roles.
#
# OpenBao paths (KV v2, mount `kv`):
#
# digitalboard/ess-pro
# ├── username (Element customer.element.io username)
# ├── token (Element customer.element.io token)
# ├── client_secret (Keycloak ess-mas OIDC client secret)
# ├── s3_access_key (Garage access key for ess-media bucket)
# ├── s3_secret_key (Garage secret key)
# ├── synapse_db_password (only if postgres_external: true)
# └── mas_db_password (only if postgres_external: true)
#
# Bootstrap once with:
# bao kv put kv/digitalboard/ess-pro \
# username='ess-customer-xxx' \
# token='paste-from-customer-portal' \
# client_secret='from-keycloak' \
# s3_access_key='...' s3_secret_key='...'
# =============================================================================
ess_pro_registry_username: "{{ lookup('community.hashi_vault.vault_kv2_get',
'digitalboard/ess-pro',
mount_point='kv').data.data.username }}"
ess_pro_registry_token: "{{ lookup('community.hashi_vault.vault_kv2_get',
'digitalboard/ess-pro',
mount_point='kv').data.data.token }}"
ess_pro_oidc_client_secret: "{{ lookup('community.hashi_vault.vault_kv2_get',
'digitalboard/ess-pro',
mount_point='kv').data.data.client_secret }}"
ess_pro_s3_access_key: "{{ lookup('community.hashi_vault.vault_kv2_get',
'digitalboard/ess-pro',
mount_point='kv').data.data.s3_access_key }}"
ess_pro_s3_secret_key: "{{ lookup('community.hashi_vault.vault_kv2_get',
'digitalboard/ess-pro',
mount_point='kv').data.data.s3_secret_key }}"
# Uncomment when ess_pro_postgres_external is true:
# ess_pro_postgres_synapse_password: "{{ lookup('community.hashi_vault.vault_kv2_get',
# 'digitalboard/ess-pro',
# mount_point='kv').data.data.synapse_db_password }}"
#
# ess_pro_postgres_mas_password: "{{ lookup('community.hashi_vault.vault_kv2_get',
# 'digitalboard/ess-pro',
# mount_point='kv').data.data.mas_db_password }}"

View file

@ -0,0 +1,26 @@
#!/usr/bin/env bash
# Bootstrap the OpenBao secret needed by the ess-pro Ansible role.
# Single KV v2 entry at kv/digitalboard/ess-pro with all keys flat
# (same layout as digitalboard/bookstack, digitalboard/opnform, etc.).
#
# Requires: `bao` CLI in PATH, `BAO_ADDR` exported, authenticated.
set -euo pipefail
MOUNT="${MOUNT:-kv}"
PATH_="${PATH_:-digitalboard/ess-pro}"
read -p "Element registry username (from customer.element.io): " REG_USER
read -s -p "Element registry token: " REG_TOKEN; echo
read -s -p "Keycloak ess-mas client secret: " OIDC_SECRET; echo
read -p "Garage S3 access key: " S3_AK
read -s -p "Garage S3 secret key: " S3_SK; echo
bao kv put "${MOUNT}/${PATH_}" \
username="${REG_USER}" \
token="${REG_TOKEN}" \
client_secret="${OIDC_SECRET}" \
s3_access_key="${S3_AK}" \
s3_secret_key="${S3_SK}"
echo "Done. Verify with: bao kv get ${MOUNT}/${PATH_}"

View file

@ -0,0 +1,14 @@
# SPDX-License-Identifier: MIT-0
---
# Example play, mirroring the convention used by the other digitalboard.core
# roles (digitalboard.core.bookstack, digitalboard.core.opnform, ...).
#
# Place the ess-pro role into your digitalboard.core collection alongside
# the others, then reference it as `digitalboard.core.ess_pro`.
- name: Deploy Element Server Suite Pro
hosts: ess_servers
become: true
roles:
- digitalboard.core.k3s
- digitalboard.core.ess_pro