Skip to content

Parameters

The customer sheet carries the twenty-two variables that tell one Tradeval instance from another. This page documents them, it does not redefine them: the reference remains scripts/install.env.example.

Getting your sheet

cp scripts/install.env.example scripts/install.env

The resulting file, scripts/install.env, is never committed: it is excluded by .gitignore. Nor is it sourced. Three of the guide's scripts (preflight.sh, render-config.sh, validate-install.sh) read it through scripts/lib-env.sh, a strict reader that only accepts plain assignments KEY=value: a sheet containing a command substitution or a function call is rejected before being used. The guide's fourth script, check-docs.sh, does not read the sheet: it has neither an --env option nor any need for it.

No secret appears in the sheet. The only secret the scripts consume, CF_API_TOKEN, comes from the operator's environment, not from a line of the sheet.

Domain and TLS

Variable Example Where the value lands Effect if wrong
TV_DOMAIN exemple.tld substituted by render-config.sh in nearly all of the manifests concerned, including its escaped form domaine\.tld in the rewrite rules of core/coredns/ and core/lan-dns/ render-config.sh rejects any value that does not have the shape of a domain; an accepted but wrong value produces hosts and a certificate for the wrong domain
TV_ACME_EMAIL ops@exemple.tld substituted by render-config.sh in the Let's Encrypt ClusterIssuer, under certs/; written by hand as the alert recipient in observability/prometheus-values.yaml an empty value blocks preflight.sh; a wrong but well-formed address is not detected by the guide's scripts, and the certificate expiry notices go to the wrong address
TV_CF_ZONE_ID see scripts/install.env.example consumed by preflight.sh, which queries the Cloudflare API to check that the zone is reachable with CF_API_TOKEN preflight.sh prints KO with the HTTP code returned by Cloudflare; the DNS-01 challenge cannot work
TV_CF_TUNNEL_NAME exemple-prod name given by the operator to the Cloudflare tunnel, created at step 13 of the Step by step, not a value substituted into a manifest core/cloudflare/cloudflared-config.yaml still carries the UUID of the original tunnel, which no substitution touches: until that UUID is replaced by hand after cloudflared tunnel create, the cloudflared pods target the vendor's tunnel and the public exposure does not come up

Cluster

Variable Example Where the value lands Effect if wrong
TV_NODE_COUNT 6 no substitution: the value lands in no manifest, it serves as the expected number for control 1 of validate-install.sh, which counts the Ready nodes of the cluster preflight.sh fails before the installation if the variable is absent, empty, or not a positive integer, and validate-install.sh rejects the sheet on the same criterion; a well-formed but wrong value makes control 1 fail on a healthy cluster, or lets it pass while a node is missing

The reference sizing is six nodes, three control-plane and three workers (Prerequisites). It is an example value, not a constraint of the guide: a customer deploying four or eight nodes writes their number here, and the conformance recipe goes green on their cluster.

Network

The role of six of these eight variables and the addressing to reserve before starting: 02-prerequis.md. This table adds what 02-prerequis.md does not say: where the value lands once the sheet is filled in, and what a wrong value produces. TV_LAN_DNS_IP and TV_VPN_IP, absent from 02-prerequis.md, are documented here in full.

Variable Example Where the value lands Effect if wrong
TV_CP_ENDPOINT 10.0.0.100 Talos machine configuration, generated by talosctl; out of reach of render-config.sh talosctl does not reach the control-plane, the cluster bootstrap fails
TV_VIP 10.0.0.200 substituted by render-config.sh, after TV_VIP_RANGE; pinned on the Traefik Service by spec.loadBalancerIP, and also configures kube-vip on the Talos side preflight.sh fails before the installation if the value falls outside TV_VIP_RANGE; otherwise, validate-install.sh compares the EXTERNAL-IP of the Traefik service against this variable afterwards and fails if they differ
TV_VIP_RANGE 10.0.0.200-10.0.0.209 kube-vip configuration on the Talos side; substituted by render-config.sh in core/kube-vip/kubevip-range.yaml, before TV_VIP, the range having to be replaced first, failing which the VIP substitution cuts it into two halves. This ConfigMap is read by no component that this repository installs: the range is to be reserved and documented, it is not distributed (step 5 of the Step by step) no direct effect, since nothing reads this range; preflight.sh does however use it to reject a TV_VIP, TV_LAN_DNS_IP or TV_VPN_IP that falls outside it
TV_TRAEFIK_CLUSTERIP 10.111.0.21 substituted by render-config.sh in core/cloudflare/cloudflared-config.yaml and core/traefik/traefik.yaml validate-install.sh queries CoreDNS for a public host and fails if the resolution does not point to this ClusterIP
TV_LAN_DNS_IP 10.0.0.201 address of the split-horizon DNS (core/lan-dns/), pinned on its Service by the annotation kube-vip.io/loadbalancerIPs and advertised by kube-vip; substituted by render-config.sh; must fall within TV_VIP_RANGE, like TV_VIP; the customer's DHCP must push it to the LAN workstations preflight.sh fails if the address falls outside TV_VIP_RANGE; otherwise kube-vip advertises the address written in the manifest, whatever it is, and the LAN workstations query an address other than the one that answers
TV_VPN_IP 10.0.0.202 address of the in-cluster WireGuard concentrator, pinned by spec.loadBalancerIP in core/vpn/wireguard-incluster.yaml; substituted by render-config.sh; must fall within TV_VIP_RANGE, like TV_VIP. This manifest is not applied by the procedure, see step 13 of the Step by step preflight.sh fails if the address falls outside TV_VIP_RANGE; no effect afterwards, since the manifest that carries it is not applied
TV_POD_SUBNET 10.244.0.0/16 Talos machine configuration, generated by talosctl, and substituted by render-config.sh in core/vpn/peer-officer.template.conf, where the tunnel advertises the range to the agents possible addressing conflict with the customer's existing network, which no control of the guide detects; and if the value in the sheet differs from the one actually set in Talos, the tunnel comes up, the agents connect and reach nothing behind it, with no error
TV_SVC_SUBNET 10.96.0.0/12 Talos machine configuration, generated by talosctl, and substituted by render-config.sh in core/vpn/peer-officer.template.conf, like the pod range same effect as for TV_POD_SUBNET: undetected addressing collision, or silent VPN routing if the sheet and Talos diverge

The TV_TRAEFIK_CLUSTERIP example is the only one in this table that does not copy the value of scripts/install.env.example. That is not a discrepancy: the example sheet carries the real ClusterIP of the reference instance, and no page of this guide copies an instance value. Both fall within 10.96.0.0/12, and neither is to be taken as it is: what goes into the sheet is the ClusterIP reserved on the customer's cluster.

core/coredns/coredns-configmap.yaml carries no hard-coded IP address: its header says explicitly that CoreDNS keeps resolving the Traefik service, not a copied-over ClusterIP. preflight.sh checks that TV_VIP, TV_LAN_DNS_IP and TV_VPN_IP all three fall within TV_VIP_RANGE.

Identity

Variable Example Where the value lands Effect if wrong
TV_KC_REALM tradeservices out of reach of render-config.sh: the realm is created in Keycloak, and the same value is found again in the Vault keys that carry the OIDC issuer (page 06) OIDC issuer inconsistent between Keycloak and the services: every token rejected, see below

Images

Variable Example Where the value lands Effect if wrong
TV_REGISTRY registry.exemple.tld substituted by render-config.sh: the host is rewritten on the eleven application images; third-party images keep their original registry eleven pods in ImagePullBackOff

No variable parameterises the image tag: the ten application images carry an immutable per-build tag, and the Keycloak image carries prod pinned by its digest, which another registry does not reproduce. A single variable would build references that exist in no registry.

The customer's registry must carry these eleven images under their exact names and tags. render-config.sh rewrites the host, it pushes nothing.

Storage

Variable Example Where the value lands Effect if wrong
TV_STORAGE_CLASS longhorn no manifest names a StorageClass; TV_STORAGE_CLASS is a control of preflight.sh preflight.sh distinguishes two failures: no default StorageClass on the cluster, and the PVCs will stay Pending; or a default StorageClass exists but its name differs from TV_STORAGE_CLASS

External data

Each of these six variables already carries, in scripts/install.env.example, a comment giving its format, the exact place where it lands and the symptom of a wrong value. This table does not copy them over: it points back to the sheet.

Variable Example Where the value lands Effect if wrong
TV_PG_HOST pg.exemple.tld:5432 Vault, at step 11 of the Step by step, from where ESO injects it into the pods see the variable's comment in scripts/install.env.example
TV_KAFKA_BOOTSTRAP kafka.exemple.tld:9092 Vault, at step 11 of the step by step see the variable's comment in scripts/install.env.example
TV_REDIS_HOST redis.exemple.tld:6379 Vault, at step 11 of the step by step see the variable's comment in scripts/install.env.example
TV_ES_HOST es.exemple.tld:9200 Vault, at step 11 of the step by step see the variable's comment in scripts/install.env.example
TV_MINIO_ENDPOINT minio.exemple.tld:9000 Vault, at step 11 of the step by step, and secrets/vault-backup.yaml through render-config.sh see the variable's comment in scripts/install.env.example
TV_SMTP_HOST smtp.exemple.tld:587 Vault, at step 11 of the step by step, and observability/prometheus-values.yaml through render-config.sh (login and sender edited by hand) see the variable's comment in scripts/install.env.example

preflight.sh checks that each of the six endpoints answers, including when run with --skip-cluster: that flag only skips the two sections that require a cluster, and those six endpoints are external to it. The very first run, before the cluster even exists, therefore already exercises them.

Keycloak's database does not appear in this table, nor in the sheet: it is nonetheless mandatory, and no manifest in the repository creates it. See Prerequisites.

What is not entered

Three values are computed from TV_DOMAIN and TV_KC_REALM. They do not appear in the sheet, and a sheet that carried them anyway would be an opportunity for inconsistency rather than a guarantee:

Derived value Formula
OIDC issuer https://auth.${TV_DOMAIN}/realms/${TV_KC_REALM}
KC_HOSTNAME auth.${TV_DOMAIN}
Ingress hosts <service>.${TV_DOMAIN}

A derived value entered by hand can diverge from the formula without any control of the guide noticing it at the time it is entered: scripts/install.env has no field for it, so nothing reads it back. scripts/validate-install.sh does not take that risk either: it recomputes the issuer itself from TV_DOMAIN and TV_KC_REALM rather than reading an entered value.

What parameterisation cannot do

scripts/render-config.sh ends with a block of eight entries stating what no text substitution does. Six are operations, all of them necessary, none of them covered by the customer sheet; the script's last two entries are observations about the repository, not actions to take. The six operations:

  1. Cloudflare: the domain's zone and a scoped API token (Zone:DNS:Edit and Zone:Zone:Read) for the DNS-01 challenge. Symptom if forgotten: the wildcard certificate is never issued, and for as long as it is not Ready, no host of the platform is reachable.
  2. Vault: the keys that carry the OIDC issuer and the API URLs of the .NET services (AUTH_KEYCLOAK_ISSUER, NEXTAUTH_URL, NEXTAUTH_URL_INTERNAL, the OIDC authority of the five .NET services, the *_API_BASE_URL, CONTENT_SERVICE_URL, ALLOWED_ORIGINS). Symptom if forgotten: KC_HOSTNAME renamed without those keys being patched accordingly, and every token is rejected with the error IDX10205.
  3. Keycloak realm: creating the realm ${TV_KC_REALM}, its Valid Redirect URIs and its Web Origins. Symptom if forgotten: login refused or post-login redirection failing, while the expected realm simply does not exist yet under that name.
  4. Frontend images: the NEXT_PUBLIC_* variables are frozen at build time, not at container start. Symptom if forgotten: the portals keep calling the old domain after the deployment, a redeployment alone is not enough, the images have to be rebuilt.
  5. Publishing the images: the registry ${TV_REGISTRY} must carry the eleven application images under their exact names and tags. render-config.sh rewrites the host, it pushes nothing. Symptom if forgotten: pods in ImagePullBackOff.
  6. Cloudflare tunnel UUID: core/cloudflare/cloudflared-config.yaml carries the UUID of the original tunnel, which no substitution touches. Symptom if forgotten: after cloudflared tunnel create, for as long as that UUID is not replaced by hand, the cloudflared pods target the vendor's tunnel and the public exposure does not come up.

A seventh value escapes the sheet without the script naming it: the name of kube-vip's network interface. core/kube-vip/kube-vip-ds.yaml sets vip_interface to ens34, the NIC name of the reference instance's VMs. No variable parameterises it, no substitution touches it, and a name that matches nothing leaves the kube-vip pods Running without ever publishing an address. Finding and fix at step 5 of the Step by step.

The realm and the external data endpoints do not live in the manifests

This script therefore cannot change them. They are set in Keycloak and in Vault, detailed on page 07-configuration.md.

Applying the sheet

scripts/render-config.sh --env scripts/install.env            # preview
scripts/render-config.sh --env scripts/install.env --apply    # apply
git diff --stat

Expected: 42 files modified, once the twelve families of values have been substituted (domain, VIP, range, Traefik ClusterIP, registry, LAN DNS, VPN, ACME address, pod subnet, service subnet, MinIO, SMTP relay). The script announces their number itself, Substitutions actives (12), before listing the files: that line is what counts if the repository evolves. An empty git diff --stat means the sheet still carries the repository's original values, not the customer's.