UI Access
Tiphys's frontend is served from a ClusterIP Service on port 8080. Three
paths cover every deployment:
- Port-forward — local dev, first-install smoke testing.
- Ingress — standard production path with your existing ingress controller (ALB / nginx / Traefik).
- Ingress + Cognito auth — production with SSO enforcement.
Whichever path you use, somebody has to sign in; see Sign-in for the options.
Sign-in
auth.mode decides who can use Tiphys. The default, builtin, works
the moment the pod is up, over a port-forward or an ingress.
| Mode | Who signs people in | Audit shows | Use when |
|---|---|---|---|
builtin (default) | Tiphys itself: one admin account | admin | Small teams, trials, any install without SSO |
proxy | Your authenticating ingress (oauth2-proxy, ALB + Cognito) | Each person's SSO identity | Production with SSO and per-person accountability |
dev | Nobody; a synthetic user | dev@localhost | Local kind clusters only |
disabled | Nobody | anonymous | Air-gapped networks that enforce identity elsewhere |
Built-in sign-in
On first start Tiphys creates the admin account with a one-time
password and writes it next to its database on the state volume
(/var/lib/clu/initial-admin-password, readable only inside the pod).
Print it with:
kubectl -n tiphys exec tiphys-0 -c backend -- cat /var/lib/clu/initial-admin-password
Reading it takes exec rights in the tiphys namespace, so your
cluster's own access control is what protects it. The first sign-in has
to set a new password (at least 12 characters), which deletes the file.
After that, Account (click your name in the header) changes the
password or signs you out.
-
Forgot the password:
kubectl -n tiphys exec tiphys-0 -c backend -- python -m ops_agent.reset_adminprints a new one-time password and signs everyone out. -
Choose the password yourself (GitOps, or
persistence.mode=configmap, which has no state volume): put it in a Secret and point the chart at it. The password then always comes from the Secret and can't be changed in the UI; rotate the Secret and restart the pod instead.kubectl -n tiphys create secret generic tiphys-admin --from-literal=password='<at least 12 characters>' helm upgrade tiphys oci://ghcr.io/intelligant-ai/charts/tiphys -n tiphys \ --reuse-values --set auth.builtin.existingSecret=tiphys-admin -
How long a sign-in lasts:
auth.builtin.sessionTtlHours(default 168, one week). The session cookie is HttpOnly and SameSite=Strict, and Secure whenever the request arrived over HTTPS (including TLS ended at your ingress). -
Five wrong passwords in a row lock the account for 30 seconds, doubling with each further miss up to 15 minutes.
SSO through your ingress
Set auth.mode=proxy and put Tiphys behind an ingress that signs people
in and forwards X-Forwarded-User / X-Forwarded-Email (examples
below). Every audit entry and approval then names the person. A request
that arrives without those headers, including a plain port-forward, is
refused, and the UI explains why instead of loading.
Port-forward (default)
kubectl port-forward -n tiphys svc/tiphys 8080:8080
Open http://localhost:8080 and sign in (see Sign-in). Works
on every K8s distribution, no additional dependencies. Forward breaks on pod restart — the
./scripts/clu-open.sh helper wraps kubectl port-forward in a
reconnecting loop for demos + dev.
Use for first-install smoke, individual-operator debugging, or any environment where exposing Tiphys via ingress is overkill.
Ingress (production)
Tiphys works with any ingress controller that supports standard
networking.k8s.io/v1 Ingress. Example with ingress-nginx:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: tiphys
namespace: tiphys
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: "1m"
# SSE endpoints need long timeouts for streaming chat.
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
spec:
ingressClassName: nginx
rules:
- host: clu.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: tiphys
port:
number: 8080
tls:
- hosts: [clu.example.com]
secretName: clu-example-tls
For AWS ALB via the AWS Load Balancer Controller:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: tiphys
namespace: tiphys
annotations:
kubernetes.io/ingress.class: alb
alb.ingress.kubernetes.io/scheme: internal # or internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}]'
alb.ingress.kubernetes.io/ssl-redirect: "443"
alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:us-east-1:...
spec:
rules:
- host: clu.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: tiphys
port:
number: 8080
Important — SSE streaming: the /api/query endpoint streams chat
responses via Server-Sent Events. Long-lived connections can hit default
idle timeouts. Set:
- nginx:
proxy-read-timeout: 3600+proxy-send-timeout: 3600 - ALB:
alb.ingress.kubernetes.io/load-balancer-attributes: idle_timeout.timeout_seconds=3600 - Cloudflare / other CDNs: disable caching on
/api/*, set origin timeout ≥ 3600s.
Chats feel fine at 60s timeout for short answers; complex diagnostic flows with many tool calls can exceed that.
Ingress + Cognito auth (recommended for production)
Putting Tiphys behind auth is the standard deployment — production installs shouldn't be reachable without SSO. ALB + Cognito example:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: tiphys
namespace: tiphys
annotations:
kubernetes.io/ingress.class: alb
alb.ingress.kubernetes.io/scheme: internal
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}]'
alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:us-east-1:...
alb.ingress.kubernetes.io/auth-type: cognito
alb.ingress.kubernetes.io/auth-scope: openid
alb.ingress.kubernetes.io/auth-session-timeout: "28800"
alb.ingress.kubernetes.io/auth-idp-cognito: |
{
"UserPoolArn": "arn:aws:cognito-idp:us-east-1:...:userpool/...",
"UserPoolClientId": "...",
"UserPoolDomain": "clu-auth"
}
alb.ingress.kubernetes.io/auth-on-unauthenticated-request: authenticate
spec:
rules:
- host: clu.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: tiphys
port:
number: 8080
For nginx + oauth2-proxy, the standard oauth2-proxy sidecar pattern
works — Tiphys doesn't need auth-aware chart templating.
Either way, set auth.mode=proxy so Tiphys records each person's SSO
identity. If you leave the default builtin, the ingress still works,
but people sign in twice (SSO, then Tiphys's admin) and the audit log
shows admin for everyone.
Multi-cluster considerations
Tiphys is namespace-scoped to tiphys in each cluster where it
runs. Multi-cluster environments install one Tiphys pod per cluster; there's
no cross-cluster federation in v0.0.1. Operators who want one pane of
glass across N clusters use N separate ingress hostnames
(clu-prod.example.com, clu-staging.example.com) — each Tiphys instance
has full visibility into its own cluster + whatever AWS resources its
IRSA role grants access to.
Local-development ingress
For local kind development, the bundled setup script configures
extraPortMappings so port 8080 / 8443 on the host reach the
ingress-nginx controller inside kind. Combined with the test-cluster
setup, the Tiphys UI is reachable at http://clu.localtest.me:8080
without a port-forward (localtest.me always resolves to
127.0.0.1).
What the frontend needs from the backend
The React SPA makes all API calls relative — there's no hardcoded
backend URL. The nginx.conf inside the frontend container reverse-proxies
/api to http://localhost:8081 (the backend container in the same
pod). Any ingress that terminates at the Service port forwards both
/ (SPA) and /api/* (backend) through the same path.
No CORS config needed.