Skip to content

Install on Kubernetes (Helm)

The controller is a single HTTPS service. Everything — the REST API, the web console, and the SSH / Kubernetes / database / RDP proxies — travels over that one port as WebSocket traffic, so the ingress only has to forward HTTPS with WebSocket support. The official Helm chart wraps all of this and is secure by default.

  • Kubernetes 1.25+.
  • An external PostgreSQL 16+ database (managed service or operator — the chart does not run one).
  • An ingress controller: ingress-nginx, Traefik v3, or a Gateway API implementation (with the v1alpha3 BackendTLSPolicy CRD).
  • cert-manager (recommended) to issue the public TLS certificate.
  • Paid plans only: your per-organization license token from the Tessera portal. Community needs no license — omit the TESSERA_LICENSE key from the secret below.

The controller image is pulled from Tessera’s public registry, so no image pull secret is needed.

The chart never creates secrets — you provide them. Create the main secret and a stable SSH host key.

Terminal window
kubectl create namespace tessera
# Encryption/JWT keys, database URL, and your license
kubectl create secret generic tessera-controller-secrets -n tessera \
--from-literal=TESSERA_ENC_KEY="$(openssl rand -hex 32)" \
--from-literal=TESSERA_JWT_SECRET="$(openssl rand -hex 32)" \
--from-literal=TESSERA_DATABASE_URL="postgres://tessera:PASSWORD@pg-host:5432/tessera?sslmode=require" \
--from-literal=TESSERA_LICENSE="<license token>"
# Stable SSH proxy host key — generate ONCE and keep it
ssh-keygen -t ed25519 -N '' -f ssh_host_ed25519_key
kubectl create secret generic tessera-hostkey -n tessera \
--from-file=ssh_host_ed25519_key

The SSH host key must stay the same across upgrades — clients pin it (trust-on-first-use). Generate it once and keep the secret.

The controller always serves HTTPS. The recommended setup terminates the public certificate at the ingress (from cert-manager) and re-encrypts to the controller — traffic is never plaintext inside the cluster.

By default the controller uses a self-signed backend certificate and the ingress skips backend verification. For fully verified re-encrypt (and required for Gateway API), issue a stable backend certificate and pass it as backendTLS.existingSecret (tls.crt / tls.key / ca.crt).

Pull the chart from the registry (OCI) and install with a values file for your ingress. CI stamps the published chart version to the release at package time, and the chart defaults to the matching controller image (tagged v<version>) for that release.

Terminal window
helm install tessera \
oci://registry.tessera.company/charts/tessera-controller \
--version 1.0.0 \
-n tessera -f values.yaml

A minimal values.yaml for ingress-nginx:

secret:
existingSecret: tessera-controller-secrets
hostKey:
existingSecret: tessera-hostkey
config:
publicUrl: https://controller.example.com
ingress:
type: nginx # nginx | traefik | gateway
host: controller.example.com
className: nginx
tls:
secretName: tessera-edge-tls # cert-manager-managed
certManager:
clusterIssuer: letsencrypt-prod
networkPolicy:
enabled: true
ingressControllerNamespace: ingress-nginx
ingressControllerPodLabels:
app.kubernetes.io/name: ingress-nginx
postgres:
cidr: 10.0.0.5/32
egress:
targetCIDRs:
- 10.0.0.0/16 # networks of the servers you connect to (never 0.0.0.0/0)

For Traefik, set ingress.type: traefik (renders an IngressRoute + ServersTransport); for Gateway API, set ingress.type: gateway and point ingress.gateway.name at your Gateway (renders an HTTPRoute + BackendTLSPolicy, which requires backendTLS). The chart ships example overlays (values-nginx.yaml, values-traefik.yaml, values-gateway.yaml).

Terminal window
kubectl -n tessera rollout status deploy/tessera-tessera-controller
helm test tessera -n tessera # curls /healthz through the service

Then open https://controller.example.com. On a fresh database the controller bootstraps a default administrator — sign in as admin / admin and change the password immediately. Then follow the initial setup walkthrough.

The chart is hardened out of the box — it passes the Kubernetes restricted Pod Security Standard:

  • Runs non-root (uid 65532), read-only root filesystem, all Linux capabilities dropped, seccomp: RuntimeDefault, no privilege escalation.
  • No ServiceAccount token is mounted and the ServiceAccount has zero RBAC — a compromised pod cannot reach the Kubernetes API.
  • A deny-by-default NetworkPolicy is on: only the ingress controller can reach the port, and egress is an allowlist (DNS, PostgreSQL, your target networks, and 443 for OIDC/portal).
  • The Service is ClusterIP — reachable only through the ingress — and traffic is TLS end to end.

The published chart is cosign-signed with the same key as the image; verify it with cosign verify --key <tessera pubkey> registry.tessera.company/charts/tessera-controller:<version>.

Terminal window
helm upgrade tessera \
oci://registry.tessera.company/charts/tessera-controller \
--version <new-version> -n tessera -f values.yaml

Because it is a single replica with a Recreate rollout, the pod restarts and active sessions drop — schedule upgrades in a maintenance window (see Backups & upgrades). The database schema migrates automatically on startup.

See Configuration for the full list of settings and Licensing & activation for how the license is applied.