# Ops console + Temporal UI — SSO access design (ACTIVITY-WP-0025) ## Audience Founders / platform operators who already have Authelia accounts under `coulomb.social` SSO (LLDAP → Authelia → KeyCape MFA path). ## Hostnames (locked) | Host | Backend | Purpose | | --- | --- | --- | | `activity.coulomb.social` | `actcore-api:8010` | Ops console `/ops/ui`, JSON `/ops/*`, existing API | | `temporal.coulomb.social` | `actcore-temporal-ui:8080` | Temporal Web UI (clean short name) | Both resolve to the railiance01 Traefik LB (`92.205.62.239`) — same pattern as `forgejo.coulomb.social`. **DNS A records + Let's Encrypt certs are live** (verified 2026-07-22); Certificate objects `actcore-ops-tls` / `actcore-temporal-ui-tls` are Ready. ## Auth edge (fleet pattern) | Component | Location | | --- | --- | | Ingress controller | Traefik (`ingressClassName: traefik`) | | TLS | cert-manager `ClusterIssuer/letsencrypt-prod` | | Login portal | Authelia `https://auth.coulomb.social` | | IAM / MFA | KeyCape `https://kc.coulomb.social` (post-password) | | Forward auth | Traefik Middleware `forwardAuth` → Authelia `/api/verify` | **Not** oauth2-proxy — the live railiance01 stack already runs Authelia in namespace `sso`. Reuse it. ### Middleware `Middleware/authelia-forwardauth` in `activity-core` calls: ```text http://authelia.sso.svc.cluster.local:9091/api/verify?rd=https://auth.coulomb.social/ ``` Response headers trusted into the app: - `Remote-User` - `Remote-Groups` - `Remote-Name` - `Remote-Email` ### Access control policy Authelia global `default_policy: one_factor` currently applies. MVP accepts any authenticated Authelia user. Follow-up (T06): LLDAP group `activity-core-operators` + Authelia domain rules (net-kingdom config change). ## Mutation identity Priority for ops mutations (`POST /ops/...`): 1. SSO principal from Authelia headers (preferred) 2. Shared `ACTIVITY_CORE_OPERATOR_TOKEN` (break-glass) 3. Else 401/403 fail-closed ## DNS (operator) Expected records (live as of 2026-07-22): ```text activity.coulomb.social A 92.205.62.239 temporal.coulomb.social A 92.205.62.239 ``` **Important:** do **not** leave a stale **AAAA** (IPv6) record for either host pointing at parking (e.g. IONOS `2001:8d8:100f:f000::200` / `217.160.0.253`). Cluster resolvers prefer AAAA; cert-manager HTTP-01 self-check then hits the wrong host. Either remove AAAA or set it to the railiance01 public IPv6. ## Break-glass Port-forward remains documented in `docs/runbook.md` if Ingress/SSO is down. ## Manifests - `k8s/railiance/30-authelia-middleware.yaml` - `k8s/railiance/31-ingress-ops-sso.yaml` - `k8s/railiance/32-ingress-temporal-sso.yaml` Apply after DNS: ```bash export KUBECONFIG=~/.kube/config-hosteurope kubectl apply -f k8s/railiance/30-authelia-middleware.yaml kubectl apply -f k8s/railiance/31-ingress-ops-sso.yaml kubectl apply -f k8s/railiance/32-ingress-temporal-sso.yaml # set public Temporal URL on API after cert Ready: kubectl -n activity-core set env deploy/actcore-api \ ACTIVITY_CORE_TEMPORAL_UI_URL=https://temporal.coulomb.social kubectl -n activity-core set env deploy/actcore-temporal-ui \ TEMPORAL_CORS_ORIGINS=https://temporal.coulomb.social ```