feat: integrate tuwunel with Ory SSO, rename chat to messages subdomain

- Add matrix to hydra-maester enabledNamespaces for OAuth2Client CRD
- Update allowed_return_urls and selfservice URLs: chat→messages
- Add Kratos verification flow, employee/external identity schemas
- Extend session lifespan to 30 days with persistent cookies
- Route messages.* to tuwunel via Pingora with WebSocket support
- Replace login-ui with kratos-admin-ui as unified auth frontend
- Update TLS certificate SANs: chat→messages, add monitoring subdomains
- Add tuwunel + La Suite images to production overlay
- Switch DDoS/scanner detection to compiled-in ensemble models (observe_only)
This commit is contained in:
2026-03-10 18:52:47 +00:00
parent 584e98316b
commit e5741c4df6
10 changed files with 101 additions and 29 deletions

View File

@@ -21,7 +21,7 @@ data:
key_path = "/etc/tls/tls.key"
[telemetry]
otlp_endpoint = "http://tempo.monitoring.svc.cluster.local:4318"
otlp_endpoint = ""
metrics_port = 9090
# Kubernetes resource names for cert/config watchers.
@@ -31,22 +31,20 @@ data:
tls_secret = "pingora-tls"
config_configmap = "pingora-config"
# DDoS detection — KNN-based per-IP behavioral classification.
# DDoS detection — decision tree + MLP ensemble (compiled-in weights).
[ddos]
enabled = true
model_path = "/models/ddos_model.bin"
k = 5
observe_only = true
threshold = 0.6
window_secs = 60
window_capacity = 1000
min_events = 10
# Scanner detection — logistic regression per-request classification.
# Scanner detection — decision tree + MLP ensemble (compiled-in weights).
[scanner]
enabled = true
model_path = "/models/scanner_model.bin"
observe_only = true
threshold = 0.5
poll_interval_secs = 30
bot_cache_ttl_secs = 86400
[[scanner.allowlist]]
@@ -61,6 +59,10 @@ data:
dns_suffixes = ["search.msn.com"]
cidrs = ["40.77.167.0/24", "157.55.39.0/24"]
[[scanner.allowlist]]
ua_prefix = "containerd"
reason = "Container registry client (buildkitd/containerd)"
# Rate limiting — leaky bucket per-identity throttling.
[rate_limit]
enabled = true
@@ -146,7 +148,7 @@ data:
backend = "http://messages-frontend.lasuite.svc.cluster.local:80"
[[routes]]
host_prefix = "chat"
host_prefix = "messages"
backend = "http://tuwunel.matrix.svc.cluster.local:6167"
websocket = true
@@ -181,10 +183,10 @@ data:
backend = "http://gitea-http.devtools.svc.cluster.local:3000"
websocket = true
# auth: login-ui handles browser UI; Hydra handles OAuth2/OIDC; Kratos handles self-service flows.
# auth: unified IAM dashboard; Hydra handles OAuth2/OIDC; Kratos handles self-service flows.
[[routes]]
host_prefix = "auth"
backend = "http://login-ui.ory.svc.cluster.local:3000"
backend = "http://kratos-admin-ui.ory.svc.cluster.local:3000"
[[routes.paths]]
prefix = "/oauth2"
@@ -204,10 +206,6 @@ data:
backend = "http://kratos-public.ory.svc.cluster.local:80"
strip_prefix = true
[[routes]]
host_prefix = "admin"
backend = "http://kratos-admin-ui.ory.svc.cluster.local:3000"
[[routes]]
host_prefix = "integration"
backend = "http://integration.lasuite.svc.cluster.local:80"

View File

@@ -16,9 +16,12 @@ hydra:
error: https://auth.DOMAIN_SUFFIX/error
ttl:
# Short access tokens — API-level auth window is tight.
access_token: 5m
id_token: 5m
# Login session persists 30 days — matches Kratos session lifespan so the
# Hydra session cookie survives browser restarts and prompt=none keeps working.
authentication_session: 720h
# Access/ID tokens renewed via refresh token; 1h keeps the window short.
access_token: 1h
id_token: 1h
# Refresh tokens last 30 days; Kratos session carries silent re-auth.
# Revoking a Kratos session (sunbeam user disable) prevents refresh.
refresh_token: 720h
@@ -42,6 +45,7 @@ secret:
hydra-maester:
enabledNamespaces:
- lasuite
- matrix
deployment:
extraEnv:

View File

@@ -25,12 +25,18 @@ spec:
value: "http://kratos-public.ory.svc.cluster.local:80"
- name: KRATOS_ADMIN_URL
value: "http://kratos-admin.ory.svc.cluster.local:80"
- name: HYDRA_ADMIN_URL
value: "http://hydra-admin.ory.svc.cluster.local:4445"
- name: PUBLIC_URL
value: "https://admin.DOMAIN_SUFFIX"
value: "https://auth.DOMAIN_SUFFIX"
- name: CUNNINGHAM_THEME
value: "dsfr-light"
- name: PORT
value: "3000"
- name: TRUSTED_CLIENT_IDS
value: ""
- name: SEAWEEDFS_S3_URL
value: "http://seaweedfs-filer.storage.svc.cluster.local:8333"
- name: ADMIN_IDENTITY_IDS
valueFrom:
secretKeyRef:
@@ -46,9 +52,19 @@ spec:
secretKeyRef:
name: kratos-admin-ui-secrets
key: csrf-cookie-secret
- name: SEAWEEDFS_ACCESS_KEY
valueFrom:
secretKeyRef:
name: kratos-admin-ui-secrets
key: s3-access-key
- name: SEAWEEDFS_SECRET_KEY
valueFrom:
secretKeyRef:
name: kratos-admin-ui-secrets
key: s3-secret-key
resources:
limits:
memory: 256Mi
memory: 384Mi
requests:
memory: 64Mi
cpu: 25m

View File

@@ -17,7 +17,7 @@ data:
- https://meet.DOMAIN_SUFFIX/
- https://drive.DOMAIN_SUFFIX/
- https://mail.DOMAIN_SUFFIX/
- https://chat.DOMAIN_SUFFIX/
- https://messages.DOMAIN_SUFFIX/
- https://people.DOMAIN_SUFFIX/
- https://src.DOMAIN_SUFFIX/
- https://admin.DOMAIN_SUFFIX/

View File

@@ -16,7 +16,7 @@ kratos:
- https://meet.DOMAIN_SUFFIX/
- https://drive.DOMAIN_SUFFIX/
- https://mail.DOMAIN_SUFFIX/
- https://chat.DOMAIN_SUFFIX/
- https://messages.DOMAIN_SUFFIX/
- https://people.DOMAIN_SUFFIX/
- https://src.DOMAIN_SUFFIX/
- https://find.DOMAIN_SUFFIX/
@@ -32,14 +32,19 @@ kratos:
recovery:
enabled: true
ui_url: https://auth.DOMAIN_SUFFIX/recovery
verification:
enabled: true
ui_url: https://auth.DOMAIN_SUFFIX/verification
settings:
ui_url: https://auth.DOMAIN_SUFFIX/settings
identity:
default_schema_id: default
default_schema_id: employee
schemas:
- id: default
url: base64://ewogICIkaWQiOiAiaHR0cHM6Ly9zY2hlbWFzLnN1bmJlYW0uc3R1ZGlvL2lkZW50aXR5Lmpzb24iLAogICIkc2NoZW1hIjogImh0dHA6Ly9qc29uLXNjaGVtYS5vcmcvZHJhZnQtMDcvc2NoZW1hIyIsCiAgInR5cGUiOiAib2JqZWN0IiwKICAidGl0bGUiOiAiUGVyc29uIiwKICAicHJvcGVydGllcyI6IHsKICAgICJ0cmFpdHMiOiB7CiAgICAgICJ0eXBlIjogIm9iamVjdCIsCiAgICAgICJwcm9wZXJ0aWVzIjogewogICAgICAgICJlbWFpbCI6IHsKICAgICAgICAgICJ0eXBlIjogInN0cmluZyIsCiAgICAgICAgICAiZm9ybWF0IjogImVtYWlsIiwKICAgICAgICAgICJ0aXRsZSI6ICJFbWFpbCIsCiAgICAgICAgICAib3J5LnNoL2tyYXRvcyI6IHsKICAgICAgICAgICAgImNyZWRlbnRpYWxzIjogewogICAgICAgICAgICAgICJwYXNzd29yZCI6IHsKICAgICAgICAgICAgICAgICJpZGVudGlmaWVyIjogdHJ1ZQogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfSwKICAgICAgICAgICAgInJlY292ZXJ5IjogewogICAgICAgICAgICAgICJ2aWEiOiAiZW1haWwiCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgICJ2ZXJpZmljYXRpb24iOiB7CiAgICAgICAgICAgICAgInZpYSI6ICJlbWFpbCIKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgIm5hbWUiOiB7CiAgICAgICAgICAidHlwZSI6ICJvYmplY3QiLAogICAgICAgICAgInByb3BlcnRpZXMiOiB7CiAgICAgICAgICAgICJmaXJzdCI6IHsgInR5cGUiOiAic3RyaW5nIiwgInRpdGxlIjogIkZpcnN0IG5hbWUiIH0sCiAgICAgICAgICAgICJsYXN0IjogeyAidHlwZSI6ICJzdHJpbmciLCAidGl0bGUiOiAiTGFzdCBuYW1lIiB9CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICB9LAogICAgICAicmVxdWlyZWQiOiBbImVtYWlsIl0KICAgIH0KICB9Cn0K
- id: employee
url: base64://ewogICIkaWQiOiAiaHR0cHM6Ly9zY2hlbWFzLnN1bmJlYW0uc3R1ZGlvL2VtcGxveWVlLmpzb24iLAogICIkc2NoZW1hIjogImh0dHA6Ly9qc29uLXNjaGVtYS5vcmcvZHJhZnQtMDcvc2NoZW1hIyIsCiAgInR5cGUiOiAib2JqZWN0IiwKICAidGl0bGUiOiAiRW1wbG95ZWUiLAogICJwcm9wZXJ0aWVzIjogewogICAgInRyYWl0cyI6IHsKICAgICAgInR5cGUiOiAib2JqZWN0IiwKICAgICAgInByb3BlcnRpZXMiOiB7CiAgICAgICAgImVtYWlsIjogewogICAgICAgICAgInR5cGUiOiAic3RyaW5nIiwKICAgICAgICAgICJmb3JtYXQiOiAiZW1haWwiLAogICAgICAgICAgInRpdGxlIjogIkVtYWlsIiwKICAgICAgICAgICJvcnkuc2gva3JhdG9zIjogewogICAgICAgICAgICAiY3JlZGVudGlhbHMiOiB7ICJwYXNzd29yZCI6IHsgImlkZW50aWZpZXIiOiB0cnVlIH0gfSwKICAgICAgICAgICAgInJlY292ZXJ5IjogeyAidmlhIjogImVtYWlsIiB9LAogICAgICAgICAgICAidmVyaWZpY2F0aW9uIjogeyAidmlhIjogImVtYWlsIiB9CiAgICAgICAgICB9CiAgICAgICAgfSwKICAgICAgICAiZ2l2ZW5fbmFtZSI6IHsgInR5cGUiOiAic3RyaW5nIiwgInRpdGxlIjogIkZpcnN0IG5hbWUiIH0sCiAgICAgICAgImZhbWlseV9uYW1lIjogeyAidHlwZSI6ICJzdHJpbmciLCAidGl0bGUiOiAiTGFzdCBuYW1lIiB9LAogICAgICAgICJtaWRkbGVfbmFtZSI6IHsgInR5cGUiOiAic3RyaW5nIiwgInRpdGxlIjogIk1pZGRsZSBuYW1lIiB9LAogICAgICAgICJuaWNrbmFtZSI6IHsgInR5cGUiOiAic3RyaW5nIiwgInRpdGxlIjogIk5pY2tuYW1lIiB9LAogICAgICAgICJwaWN0dXJlIjogeyAidHlwZSI6ICJzdHJpbmciLCAiZm9ybWF0IjogInVyaSIsICJ0aXRsZSI6ICJQcm9maWxlIHBpY3R1cmUiIH0sCiAgICAgICAgInBob25lX251bWJlciI6IHsgInR5cGUiOiAic3RyaW5nIiwgInRpdGxlIjogIlBob25lIG51bWJlciIgfSwKICAgICAgICAiam9iX3RpdGxlIjogeyAidHlwZSI6ICJzdHJpbmciLCAidGl0bGUiOiAiSm9iIHRpdGxlIiB9LAogICAgICAgICJkZXBhcnRtZW50IjogeyAidHlwZSI6ICJzdHJpbmciLCAidGl0bGUiOiAiRGVwYXJ0bWVudCIgfSwKICAgICAgICAib2ZmaWNlX2xvY2F0aW9uIjogeyAidHlwZSI6ICJzdHJpbmciLCAidGl0bGUiOiAiT2ZmaWNlIGxvY2F0aW9uIiB9LAogICAgICAgICJlbXBsb3llZV9pZCI6IHsgInR5cGUiOiAic3RyaW5nIiwgInRpdGxlIjogIkVtcGxveWVlIElEIiB9LAogICAgICAgICJoaXJlX2RhdGUiOiB7ICJ0eXBlIjogInN0cmluZyIsICJmb3JtYXQiOiAiZGF0ZSIsICJ0aXRsZSI6ICJIaXJlIGRhdGUiIH0sCiAgICAgICAgIm1hbmFnZXIiOiB7ICJ0eXBlIjogInN0cmluZyIsICJ0aXRsZSI6ICJNYW5hZ2VyIiB9CiAgICAgIH0sCiAgICAgICJyZXF1aXJlZCI6IFsiZW1haWwiXQogICAgfQogIH0KfQo=
- id: external
url: base64://ewogICIkaWQiOiAiaHR0cHM6Ly9zY2hlbWFzLnN1bmJlYW0uc3R1ZGlvL2V4dGVybmFsLmpzb24iLAogICIkc2NoZW1hIjogImh0dHA6Ly9qc29uLXNjaGVtYS5vcmcvZHJhZnQtMDcvc2NoZW1hIyIsCiAgInR5cGUiOiAib2JqZWN0IiwKICAidGl0bGUiOiAiRXh0ZXJuYWwgVXNlciIsCiAgInByb3BlcnRpZXMiOiB7CiAgICAidHJhaXRzIjogewogICAgICAidHlwZSI6ICJvYmplY3QiLAogICAgICAicHJvcGVydGllcyI6IHsKICAgICAgICAiZW1haWwiOiB7CiAgICAgICAgICAidHlwZSI6ICJzdHJpbmciLAogICAgICAgICAgImZvcm1hdCI6ICJlbWFpbCIsCiAgICAgICAgICAidGl0bGUiOiAiRW1haWwiLAogICAgICAgICAgIm9yeS5zaC9rcmF0b3MiOiB7CiAgICAgICAgICAgICJjcmVkZW50aWFscyI6IHsgInBhc3N3b3JkIjogeyAiaWRlbnRpZmllciI6IHRydWUgfSB9LAogICAgICAgICAgICAicmVjb3ZlcnkiOiB7ICJ2aWEiOiAiZW1haWwiIH0sCiAgICAgICAgICAgICJ2ZXJpZmljYXRpb24iOiB7ICJ2aWEiOiAiZW1haWwiIH0KICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgICJnaXZlbl9uYW1lIjogeyAidHlwZSI6ICJzdHJpbmciLCAidGl0bGUiOiAiRmlyc3QgbmFtZSIgfSwKICAgICAgICAiZmFtaWx5X25hbWUiOiB7ICJ0eXBlIjogInN0cmluZyIsICJ0aXRsZSI6ICJMYXN0IG5hbWUiIH0sCiAgICAgICAgIm5pY2tuYW1lIjogeyAidHlwZSI6ICJzdHJpbmciLCAidGl0bGUiOiAiTmlja25hbWUiIH0sCiAgICAgICAgInBpY3R1cmUiOiB7ICJ0eXBlIjogInN0cmluZyIsICJmb3JtYXQiOiAidXJpIiwgInRpdGxlIjogIlByb2ZpbGUgcGljdHVyZSIgfQogICAgICB9LAogICAgICAicmVxdWlyZWQiOiBbImVtYWlsIl0KICAgIH0KICB9Cn0K
courier:
smtp:
@@ -56,6 +61,8 @@ kratos:
# receive it. Without this Kratos scopes the cookie to auth.* only, causing
# redirect loops on admin.*.
domain: DOMAIN_SUFFIX
persistent: true
lifespan: 720h
serve:
public:

View File

@@ -9,7 +9,6 @@ kind: Kustomization
resources:
- namespace.yaml
- login-ui-deployment.yaml
- kratos-admin-deployment.yaml
# Hydra chart CRDs are not rendered by helm template; apply manually.
- hydra-oauth2client-crd.yaml

View File

@@ -58,12 +58,15 @@ spec:
- meet.DOMAIN_SUFFIX
- drive.DOMAIN_SUFFIX
- mail.DOMAIN_SUFFIX
- chat.DOMAIN_SUFFIX
- messages.DOMAIN_SUFFIX
- people.DOMAIN_SUFFIX
- src.DOMAIN_SUFFIX
- auth.DOMAIN_SUFFIX
- s3.DOMAIN_SUFFIX
- grafana.DOMAIN_SUFFIX
- metrics.DOMAIN_SUFFIX
- systemmetrics.DOMAIN_SUFFIX
- systemlogs.DOMAIN_SUFFIX
- systemtracing.DOMAIN_SUFFIX
- admin.DOMAIN_SUFFIX
- integration.DOMAIN_SUFFIX
- livekit.DOMAIN_SUFFIX

View File

@@ -7,6 +7,7 @@ kind: Kustomization
# sunbeam apply --env production --domain yourdomain.com
resources:
- ../../base/build
- ../../base/longhorn
- ../../base/cert-manager
- ../../base/ingress
@@ -18,6 +19,7 @@ resources:
- ../../base/devtools
- ../../base/vso
- ../../base/monitoring
- ../../base/matrix
# cert-manager ClusterIssuer + Certificate (requires cert-manager to be installed)
- cert-manager.yaml
# CNPG daily backup schedule
@@ -37,6 +39,36 @@ images:
newName: src.DOMAIN_SUFFIX/studio/meet-frontend
newTag: latest
# people-frontend — built from source with estudio theme baked in.
- name: lasuite/people-frontend
newName: src.DOMAIN_SUFFIX/studio/people-frontend
newTag: latest
# Messages — built from source and pushed to Gitea registry.
- name: messages-backend
newName: src.DOMAIN_SUFFIX/studio/messages-backend
newTag: latest
- name: messages-frontend
newName: src.DOMAIN_SUFFIX/studio/messages-frontend
newTag: latest
- name: messages-mta-in
newName: src.DOMAIN_SUFFIX/studio/messages-mta-in
newTag: latest
- name: messages-mta-out
newName: src.DOMAIN_SUFFIX/studio/messages-mta-out
newTag: latest
- name: messages-mpa
newName: src.DOMAIN_SUFFIX/studio/messages-mpa
newTag: latest
- name: messages-socks-proxy
newName: src.DOMAIN_SUFFIX/studio/messages-socks-proxy
newTag: latest
# Tuwunel Matrix homeserver — built and pushed by `sunbeam build tuwunel`
- name: tuwunel
newName: src.DOMAIN_SUFFIX/studio/tuwunel
newTag: latest
patches:
# Pingora host ports — bind :80/:443 to the host network
- path: patch-pingora-hostport.yaml
@@ -53,5 +85,18 @@ patches:
# OpenSearch: expand PVC to 50 Gi
- path: patch-opensearch-storage.yaml
# Tuwunel: production resource limits and PVC sizing
- path: patch-tuwunel.yaml
# SeaweedFS volume: expand PVC to 600 Gi
- path: patch-seaweedfs-volume-size.yaml
# MTA-in: bind port 25 to the host for inbound email delivery
- patch: |
- op: add
path: /spec/template/spec/containers/0/ports/0/hostPort
value: 25
target:
kind: Deployment
name: messages-mta-in
namespace: lasuite

View File

@@ -197,7 +197,7 @@ echo " Auth: https://auth.${DOMAIN}/"
echo " Docs: https://docs.${DOMAIN}/"
echo " Meet: https://meet.${DOMAIN}/"
echo " Drive: https://drive.${DOMAIN}/"
echo " Chat: https://chat.${DOMAIN}/"
echo " Messages: https://messages.${DOMAIN}/"
echo " Mail: https://mail.${DOMAIN}/"
echo " People: https://people.${DOMAIN}/"
echo " Gitea: https://src.${DOMAIN}/"

View File

@@ -18,7 +18,7 @@ echo " Docs: https://docs.${BASE}"
echo " Meet: https://meet.${BASE}"
echo " Drive: https://drive.${BASE}"
echo " Mail: https://mail.${BASE}"
echo " Chat: https://chat.${BASE}"
echo " Messages: https://messages.${BASE}"
echo " People: https://people.${BASE}"
echo " Source: https://src.${BASE}"
echo " Auth: https://auth.${BASE}"