feat(matrix): add tuwunel Matrix homeserver deployment manifests

Kubernetes manifests for tuwunel — a Rust Matrix homeserver using RocksDB
for storage. Includes deployment, service, PVC, ConfigMap (tuwunel.toml),
Hydra OAuth2Client for SSO, and Vault secrets for credentials injection.

Key design decisions:
- enableServiceLinks: false to prevent K8s TUWUNEL_* env var conflicts
- strategy: Recreate for RocksDB exclusive lock (no rolling updates)
- Identity provider configured entirely via env vars (client_id/secret
  from hydra-maester Secret, not hardcoded)
- OpenSearch model_id injected via ConfigMap from CLI post-apply hook
- SSO-only auth (login_with_password=false, single_sso=true)
- OpenSearch hybrid neural+BM25 search (768-dim, all-mpnet-base-v2)
This commit is contained in:
2026-03-10 18:52:21 +00:00
parent 91983ddf29
commit d2148335de
9 changed files with 265 additions and 0 deletions

View File

@@ -0,0 +1,22 @@
# Tuwunel OIDC client — registered with Hydra via hydra-maester.
# Hydra Maester creates K8s Secret "oidc-tuwunel" in the matrix namespace
# with CLIENT_ID and CLIENT_SECRET keys.
# redirectUri is patched post-apply by sunbeam CLI (requires client_id
# from the hydra-maester-generated secret).
apiVersion: hydra.ory.sh/v1alpha1
kind: OAuth2Client
metadata:
name: tuwunel
namespace: matrix
spec:
clientName: Matrix
grantTypes:
- authorization_code
- refresh_token
responseTypes:
- code
scope: openid email profile
redirectUris: []
tokenEndpointAuthMethod: client_secret_post
secretName: oidc-tuwunel
skipConsent: true

View File

@@ -0,0 +1,13 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: matrix
resources:
- namespace.yaml
- tuwunel-deployment.yaml
- tuwunel-service.yaml
- tuwunel-config.yaml
- tuwunel-pvc.yaml
- vault-secrets.yaml
- hydra-oauth2client.yaml

View File

@@ -0,0 +1,6 @@
apiVersion: v1
kind: Namespace
metadata:
name: matrix
annotations:
linkerd.io/inject: enabled

View File

@@ -0,0 +1,44 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: tuwunel-config
namespace: matrix
data:
tuwunel.toml: |
[global]
server_name = "sunbeam.pt"
database_path = "/data"
address = "0.0.0.0"
port = 6167
max_request_size = 104857600
allow_registration = false
allow_guest_registration = false
login_with_password = false
single_sso = true
allow_encryption = true
# Search — OpenSearch with hybrid neural search
search_backend = "opensearch"
search_opensearch_url = "http://opensearch.data.svc.cluster.local:9200"
search_opensearch_index = "tuwunel_messages"
search_opensearch_hybrid = true
# model_id is injected via TUWUNEL_SEARCH_OPENSEARCH_MODEL_ID env var
# (set by sunbeam CLI post-apply hook from OpenSearch ML state)
search_opensearch_embedding_dim = 768
search_opensearch_pipeline = "tuwunel_embedding_pipeline"
search_opensearch_batch_size = 100
search_opensearch_flush_interval_ms = 1000
# TURN via LiveKit's built-in TURN server
turn_uris = ["turn:meet.DOMAIN_SUFFIX:3478?transport=udp", "turns:meet.DOMAIN_SUFFIX:5349?transport=tcp"]
turn_secret = ""
# Well-known delegation
[global.well_known]
client = "https://messages.DOMAIN_SUFFIX"
server = "messages.DOMAIN_SUFFIX:443"
livekit_url = "wss://livekit.DOMAIN_SUFFIX"
# OIDC via Ory Hydra — identity_provider is configured entirely
# via env vars because client_id/client_secret are injected from
# the hydra-maester-managed oidc-tuwunel Secret.

View File

@@ -0,0 +1,91 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: tuwunel
namespace: matrix
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app: tuwunel
template:
metadata:
labels:
app: tuwunel
spec:
enableServiceLinks: false
containers:
- name: tuwunel
image: tuwunel
ports:
- name: http
containerPort: 6167
protocol: TCP
env:
- name: TUWUNEL_CONFIG
value: /etc/tuwunel/tuwunel.toml
- name: TUWUNEL_TURN_SECRET
valueFrom:
secretKeyRef:
name: tuwunel-secrets
key: TUWUNEL_TURN_SECRET
- name: TUWUNEL_REGISTRATION_TOKEN
valueFrom:
secretKeyRef:
name: tuwunel-secrets
key: TUWUNEL_REGISTRATION_TOKEN
- name: TUWUNEL_SEARCH_OPENSEARCH_MODEL_ID
valueFrom:
configMapKeyRef:
name: opensearch-ml-config
key: model_id
optional: true
- name: TUWUNEL_IDENTITY_PROVIDER__0__BRAND
value: "Sunbeam"
- name: TUWUNEL_IDENTITY_PROVIDER__0__ISSUER_URL
value: "https://auth.DOMAIN_SUFFIX/"
- name: TUWUNEL_IDENTITY_PROVIDER__0__DEFAULT
value: "true"
- name: TUWUNEL_IDENTITY_PROVIDER__0__CLIENT_ID
valueFrom:
secretKeyRef:
name: oidc-tuwunel
key: CLIENT_ID
- name: TUWUNEL_IDENTITY_PROVIDER__0__CLIENT_SECRET
valueFrom:
secretKeyRef:
name: oidc-tuwunel
key: CLIENT_SECRET
volumeMounts:
- name: tuwunel-data
mountPath: /data
- name: tuwunel-config
mountPath: /etc/tuwunel/tuwunel.toml
subPath: tuwunel.toml
livenessProbe:
httpGet:
path: /_matrix/client/versions
port: 6167
initialDelaySeconds: 15
periodSeconds: 30
readinessProbe:
httpGet:
path: /_matrix/client/versions
port: 6167
initialDelaySeconds: 5
periodSeconds: 10
resources:
limits:
memory: 1Gi
requests:
memory: 512Mi
cpu: 250m
volumes:
- name: tuwunel-data
persistentVolumeClaim:
claimName: tuwunel-data
- name: tuwunel-config
configMap:
name: tuwunel-config

View File

@@ -0,0 +1,10 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: tuwunel-data
namespace: matrix
spec:
accessModes: [ReadWriteOnce]
resources:
requests:
storage: 20Gi

View File

@@ -0,0 +1,13 @@
apiVersion: v1
kind: Service
metadata:
name: tuwunel
namespace: matrix
spec:
selector:
app: tuwunel
ports:
- name: http
port: 6167
targetPort: 6167
protocol: TCP

View File

@@ -0,0 +1,39 @@
---
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultAuth
metadata:
name: vso-auth
namespace: matrix
spec:
method: kubernetes
mount: kubernetes
kubernetes:
role: vso
serviceAccount: default
---
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultStaticSecret
metadata:
name: tuwunel-secrets
namespace: matrix
spec:
vaultAuthRef: vso-auth
mount: secret
type: kv-v2
path: tuwunel
refreshAfter: 60s
destination:
name: tuwunel-secrets
create: true
overwrite: true
transformation:
excludeRaw: true
templates:
TUWUNEL_OIDC_CLIENT_ID:
text: "{{ index .Secrets \"oidc-client-id\" }}"
TUWUNEL_OIDC_CLIENT_SECRET:
text: "{{ index .Secrets \"oidc-client-secret\" }}"
TUWUNEL_TURN_SECRET:
text: "{{ index .Secrets \"turn-secret\" }}"
TUWUNEL_REGISTRATION_TOKEN:
text: "{{ index .Secrets \"registration-token\" }}"

View File

@@ -0,0 +1,27 @@
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: tuwunel
namespace: matrix
spec:
template:
spec:
containers:
- name: tuwunel
resources:
requests:
memory: 512Mi
cpu: 500m
limits:
memory: 2Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: tuwunel-data
namespace: matrix
spec:
resources:
requests:
storage: 50Gi