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¶
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:
- Cloudflare: the domain's zone and a scoped API token (
Zone:DNS:EditandZone:Zone:Read) for the DNS-01 challenge. Symptom if forgotten: the wildcard certificate is never issued, and for as long as it is notReady, no host of the platform is reachable. - 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_HOSTNAMErenamed without those keys being patched accordingly, and every token is rejected with the errorIDX10205. - 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. - 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. - Publishing the images: the registry
${TV_REGISTRY}must carry the eleven application images under their exact names and tags.render-config.shrewrites the host, it pushes nothing. Symptom if forgotten: pods inImagePullBackOff. - Cloudflare tunnel UUID:
core/cloudflare/cloudflared-config.yamlcarries the UUID of the original tunnel, which no substitution touches. Symptom if forgotten: aftercloudflared 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.