diff --git a/base/matrix/hydra-oauth2client.yaml b/base/matrix/hydra-oauth2client.yaml new file mode 100644 index 0000000..399c611 --- /dev/null +++ b/base/matrix/hydra-oauth2client.yaml @@ -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 diff --git a/base/matrix/kustomization.yaml b/base/matrix/kustomization.yaml new file mode 100644 index 0000000..4520dda --- /dev/null +++ b/base/matrix/kustomization.yaml @@ -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 diff --git a/base/matrix/namespace.yaml b/base/matrix/namespace.yaml new file mode 100644 index 0000000..dae7e68 --- /dev/null +++ b/base/matrix/namespace.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: matrix + annotations: + linkerd.io/inject: enabled diff --git a/base/matrix/tuwunel-config.yaml b/base/matrix/tuwunel-config.yaml new file mode 100644 index 0000000..5d52ed8 --- /dev/null +++ b/base/matrix/tuwunel-config.yaml @@ -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. diff --git a/base/matrix/tuwunel-deployment.yaml b/base/matrix/tuwunel-deployment.yaml new file mode 100644 index 0000000..44a7423 --- /dev/null +++ b/base/matrix/tuwunel-deployment.yaml @@ -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 diff --git a/base/matrix/tuwunel-pvc.yaml b/base/matrix/tuwunel-pvc.yaml new file mode 100644 index 0000000..3d50736 --- /dev/null +++ b/base/matrix/tuwunel-pvc.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: tuwunel-data + namespace: matrix +spec: + accessModes: [ReadWriteOnce] + resources: + requests: + storage: 20Gi diff --git a/base/matrix/tuwunel-service.yaml b/base/matrix/tuwunel-service.yaml new file mode 100644 index 0000000..af0cfa1 --- /dev/null +++ b/base/matrix/tuwunel-service.yaml @@ -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 diff --git a/base/matrix/vault-secrets.yaml b/base/matrix/vault-secrets.yaml new file mode 100644 index 0000000..736be25 --- /dev/null +++ b/base/matrix/vault-secrets.yaml @@ -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\" }}" diff --git a/overlays/production/patch-tuwunel.yaml b/overlays/production/patch-tuwunel.yaml new file mode 100644 index 0000000..0c20887 --- /dev/null +++ b/overlays/production/patch-tuwunel.yaml @@ -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