Helm values¶
Every value of the tenax chart, with its default. Nothing is specific to any organization: set endpoints,
hostnames and credentials for your deployment.
charts/tenax/values.yaml
# Tenax Helm values. Nothing here is specific to any organization: set every endpoint, hostname and
# credential for your deployment (see docs and examples/).
image:
# Required, for example registry.example.com/tenax/tenax
repository: ""
tag: ""
pullPolicy: IfNotPresent
# Names of existing image pull secrets in the release namespace. They are also copied into sandbox namespaces.
pullSecrets: []
# Install / upgrade the CRDs with the release.
installCRDs: true
# Optional cluster name used in metrics and audit records.
clusterName: ""
logLevel: info
controller:
replicas: 2
resources:
requests: { cpu: 50m, memory: 128Mi }
limits: { memory: 512Mi }
extraEnv: []
# Garbage collection interval per store and orphan horizon.
gcInterval: 24h
orphanAge: 24h
resyncInterval: 1m
# Automatic recovery: mirror every backup found in a store into a Backup object when it has none (on start, when
# targets change and every interval). After a cluster is rebuilt, all backups reappear by themselves. Read-only.
autoImport:
enabled: true
interval: 1h
# How often a streamer checks again whether a target's user may replicate, while it may not (ADR 0016).
replicationRecheck: 5m
api:
replicas: 2
resources:
requests: { cpu: 50m, memory: 128Mi }
limits: { memory: 1Gi }
extraEnv: []
service:
type: ClusterIP
port: 80
nodePort: null
# External URL of the console (used in links and the CLI), for example https://tenax.example.com. Default:
# https://<expose.cloudflared.consoleHostname> when the console is published.
externalURL: ""
# Console authentication.
auth:
# none: no authentication (only for local development; every request is anonymous with role "viewer" unless
# auth.devRole is set). cloudflare-access: verify the Cf-Access-Jwt-Assertion JWT.
provider: none
devRole: ""
# With cloudflare-access: the role of requests that come through `kubectl port-forward` (`tenax console`) to the
# API pod's loopback port, which needs no Access login: Kubernetes RBAC (pods/portforward in this namespace)
# already decided who may. Empty: no such port; port-forwards then need an Access token like everyone else.
portForwardRole: restorer-admin
cloudflareAccess:
# Access team domain, for example myteam.cloudflareaccess.com, and the application's audience (AUD) tag. Both
# can stay empty when Tenax publishes the console (expose.cloudflared.consoleHostname): it creates the Access
# application and finds both itself. A team domain set here is used instead of looking it up.
teamDomain: ""
audience: ""
# Override the JWKS URL (default https://<teamDomain>/cdn-cgi/access/certs).
jwksURL: ""
# Load the JWKS from a ConfigMap key "jwks.json" in the release namespace instead (air-gapped tests).
jwksConfigMap: ""
# Role mapping. Each role lists emails and/or Access groups. Roles: viewer, operator, restorer, restorer-admin.
roles:
viewer: []
operator: []
restorer: []
restorer-admin: []
# Optional scoping of roles by org/project label: { "alice@example.com": { orgs: [acme], projects: [] } }
scopes: {}
# Sandbox exposure for external clients.
expose:
# How sandboxes are reached from outside the cluster ("Open external access" in the console, tenax sandbox expose):
# none in-cluster only; people with a kubeconfig run `tenax sandbox connect`, which port-forwards.
# service a Kubernetes Service per sandbox, built from expose.service below; whatever the cluster runs for
# Services gives it an address (cloud load balancer, MetalLB, Tailscale operator, external-dns).
# Clients connect straight to it with any database tool, over TLS.
# cloudflare a Cloudflare Tunnel route behind an Access login; clients run cloudflared.
provider: none
service:
# LoadBalancer or NodePort.
type: LoadBalancer
# A load-balancer implementation, for example "tailscale" (the sandbox joins your tailnet, nothing public).
loadBalancerClass: ""
# Annotations on each sandbox's Service; {id} becomes the sandbox id. For example external-dns:
# external-dns.alpha.kubernetes.io/hostname: "sbx-{id}.db.example.com"
annotations: {}
# Client addresses the load balancer accepts (loadBalancerSourceRanges), for example your office or VPN.
# Sandboxes hold copies of production data: set this whenever the load balancer is public.
sourceRanges: []
# The address clients use when DNS names each sandbox (external-dns): "sbx-{id}.db.example.com". Empty: the load
# balancer's IP or hostname. Required for NodePort: a name that reaches the nodes ("nodes.example.com").
hostnamePattern: ""
# CIDRs the sandbox's NetworkPolicy admits on the database port while it is exposed. Traffic from a load
# balancer often arrives from node addresses, so the default is everything and sourceRanges does the filtering.
allowFrom: []
cloudflare:
# Zone name, for example example.com. With the API token, this is all Tenax needs: it finds the account from
# the zone and finds (or creates) the tunnel named tunnelName.
zone: ""
# Secret with key "token": a Cloudflare API token with Account: Cloudflare Tunnel: Edit, Account: Access: Apps
# and Policies: Edit, Zone: DNS: Edit and Zone: Zone: Read. With a published console, Account: Access:
# Organizations, Identity Providers, and Groups: Read lets Tenax read the team domain (without it, Tenax reads it
# from the console's login redirect, or set auth.cloudflareAccess.teamDomain).
apiTokenSecret: ""
# Hostname pattern for sandbox routes; {id} is replaced by the sandbox id. Keep it one level under the zone:
# Cloudflare's free certificate covers *.zone only.
hostnamePattern: "sbx-{id}.example.com"
# Access policy for sandbox routes: emails ("*@example.com" for a whole domain) and Access group ids.
allowEmails: []
allowGroups: []
# Name of the tunnel Tenax uses (created when missing).
tunnelName: tenax
# Optional: a tunnel you manage yourself (its id), and ids that save a lookup.
tunnelID: ""
accountID: ""
zoneID: ""
# Override the Cloudflare API base URL (tests, proxies). Default https://api.cloudflare.com/client/v4.
apiURL: ""
# cloudflared connector Deployment (console + sandbox routes).
cloudflared:
enabled: false
image: cloudflare/cloudflared:2025.9.1
replicas: 2
# Secret with key "token" holding the tunnel's connector token. Empty: the controller reads the token with the
# API token and keeps it in <fullname>-tunnel-token; the connector pods start once it is there.
tunnelTokenSecret: ""
# Public hostname of the console, for example tenax.example.com (one level under the zone). Tenax publishes it
# like a sandbox route: an Access application with expose.cloudflare.allowEmails/allowGroups, a DNS record and
# a tunnel route to tenax-api. People then use https://<hostname> or `tenax login --server https://<hostname>`
# without cluster access; set auth.provider cloudflare-access so tenax-api checks their Access login.
consoleHostname: ""
sandbox:
defaultTTL: 24h
maxTTL: 168h
# Defaults for every sandbox. A target's spec.sandbox and a restore (console, CLI, Restore CR) override them.
resources:
# CPU request (no CPU limit). Empty: 100m.
cpu: ""
# Memory request and limit. Empty: 256Mi requested, 1Gi limit.
memory: ""
# Data on a PVC of this storage class instead of an emptyDir on the node. Empty: emptyDir.
storageClass: ""
# Ceilings for what a target or a restore may ask for; empty means none. The data size is automatic (twice the
# backup's data, at least 1Gi) unless someone sets it; a restore whose size, set or automatic, is above the ceiling
# fails with the reason rather than filling the disk midway.
limits:
cpu: ""
memory: ""
size: ""
# Namespaces that contain BackupTargets. Tenax gets a Role there to read its target credential secrets.
targetNamespaces: []
# Only secrets whose names start with this prefix may be referenced by targets ("" disables the check).
secretPrefix: "tenax-"
metrics:
serviceMonitor:
enabled: false
interval: 30s
labels: {}
prometheusRule:
enabled: false
labels: {}
# Hours without a successful full backup before BackupOverdue fires, per env label.
overdueHours: { prod: 26, default: 50 }
grafanaDashboard:
enabled: false
# Label the Grafana sidecar watches.
labels: { grafana_dashboard: "1" }
# Example shared policies (prod, dev, critical) in the release namespace. They need a BackupStore name.
examplePolicies:
enabled: false
store: ""
timeZone: UTC
# Compression of backup data. Empty: zstd at level default (on). Example: { level: better }, or
# { algorithm: none } for data that is already compressed (ADR 0013).
compression: {}
podSecurityContext:
runAsNonRoot: true
runAsUser: 65532
seccompProfile: { type: RuntimeDefault }
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities: { drop: [ALL] }
nodeSelector: {}
tolerations: []
affinity: {}