Declare the hostnames a data plane serves
From 0.7.0 a data plane declares the hostnames it serves in its own chart, under global.gateway.hostnames, and reports them to the management plane on every configuration poll. The Admin Console lists them read-only. No console page or API call writes a declared hostname: adding or retiring one is a values change followed by tare upgrade or helm upgrade.
Persona: Platform operator with access to the data plane's Helm values or tare identity file, the DNS zone, and the load balancer in front of the cluster.
Estimated time: 10 minutes for the values change, plus DNS propagation and certificate issuance.
Outcomes
By the end of this guide:
- The data plane's serve-helm values list every hostname callers use to reach it, with the name callers should use first.
- Each declared hostname resolves to the data plane's load balancer, presents a certificate that covers it, and routes to the data plane.
- The Admin Console lists the hostnames on the data plane's page, and
tare doctorconfirms the certificate covers each one.
Prerequisites
- A self-hosted data plane on 0.7.0 or later. A data plane before 0.7.0 cannot declare hostnames and keeps the address stored for it through the admin API.
- Control of the DNS zone for each hostname, and of the certificate the load balancer presents.
- For a data plane that already serves traffic on a stored address, read Move a data plane to declared hostnames first. A partial list refuses later edits to gateway URLs that are missing from it.
Step 1: list the hostnames
Add the list to the data plane's serve-helm values:
global:
gateway:
hostnames:
- eu.acme.example.com # first: the address the console prints
- dp.acme.example.com:8443 # a port, for callers that do not use 443
tare takes the same list as a repeatable flag:
# Declare two names at install time.
tare install /path/to/data-plane-credentials.json \
--gateway-hostname=eu.acme.example.com \
--gateway-hostname=dp.acme.example.com:8443
# Upgrade and keep the installed list. tare upgrade reads it from the release.
tare upgrade /path/to/data-plane-credentials.json
# Upgrade and replace the list.
tare upgrade /path/to/data-plane-credentials.json --gateway-hostname=eu.acme.example.com
There are 5 rules for the entries:
- An entry is a hostname, optionally with a port. The management plane stores the port apart from the name and joins them again when it prints an address. A scheme such as
https://is accepted and dropped. - The first entry is the address the console prints wherever it shows a single address, such as the Base URL panel and the Playground. List the name callers should use first.
- Two data planes in one organization may declare the same name, which is how a pair behind a global server load balancer serves one hostname. The console lists both data planes under that name. Two organizations cannot claim one hostname, and two gateways on one data plane still cannot share one.
- Leaving the key out declares nothing. The data plane keeps the address stored for it through
SetDataplaneURLand answers its readiness probe there. serve-helm leaves the key out by default, so upgrading to 0.7.0 with untouched values changes nothing about where the data plane serves. - An empty list is a declaration. It says the data plane serves no hostname: the management plane retires every name it recorded for the data plane, and the readiness probe stops answering. Write
hostnames: [], or runtare upgradewith--gateway-hostname=""alone, only to drain a data plane.
helm upgrade can drop the listRunning helm upgrade without the values file that carries the hostnames drops the key, and the data plane falls back to its stored address. Keep the list in the values file applied on every upgrade. tare upgrade carries the installed list forward and does not have this problem.
Step 2: apply and confirm the declaration
-
Run
tare upgradeorhelm upgradewith the new values. -
Read what the chart rendered. The chart writes the list into the
tars-gateway-declarationConfigMap:kubectl -n tars-system get configmap tars-gateway-declaration -o jsonpath='{.data.gateway-hostnames}'["eu.acme.example.com","dp.acme.example.com:8443"]An empty list renders
[]. A chart with the key left out renders nogateway-hostnamesfield at all, which the management plane reads as "declares nothing" rather than as an empty list. -
In the Admin Console, open Directory → Data Planes and select the data plane. The hostnames appear on its page once the data plane polls for configuration. A row tagged set through the management plane is a stored address, which means the chart still declares nothing.
Step 3: make each name serve
Declaring a name tells the management plane that the data plane serves it. The chart creates no DNS record, certificate, or load balancer route. There are 3 things each declared name needs before a caller reaches it:
- A DNS record that points the name at the data plane's load balancer.
- A certificate on the load balancer, or on the cluster's own listener, that covers the name.
- A route at the load balancer that sends requests for the name to the data plane. Without it the TLS handshake succeeds and the request answers
404.
GKE with the gateway-serve-helm chart
The gateway-serve-helm chart does not read global.gateway.hostnames. Pass the same names to it as gatewayHostnames, so its HTTPRoute matches each one beside serveUrl:
# gateway-serve-helm values (gateway.yaml)
customer: acme
serveUrl: proxy.acme.example.com
certificateMap:
name: acme-serve-certmap
gatewayHostnames:
- eu.acme.example.com
- dp.acme.example.com
The chart drops a port, a scheme, and a path from each entry, because a Gateway API hostname carries no port. Confirm the route after the upgrade:
kubectl -n tars-gateway get httproute proxy-route -o jsonpath='{.spec.hostnames}'
The chart names the certificate map and never creates its entries. tare gateway install creates one map entry, for the serve host only. Create a certificate and a map entry for every further name:
HOST=eu.acme.example.com
SLUG=$(echo "$HOST" | tr . -)
MAP=acme-serve-certmap
gcloud certificate-manager dns-authorizations create "$SLUG-dns-auth" --domain="$HOST"
# Publish the CNAME this prints in the zone that holds $HOST.
gcloud certificate-manager dns-authorizations describe "$SLUG-dns-auth" --format='value(dnsResourceRecord)'
gcloud certificate-manager certificates create "$SLUG" \
--domains="$HOST" --dns-authorizations="$SLUG-dns-auth"
gcloud certificate-manager maps entries create "$SLUG-entry" \
--map="$MAP" --certificates="$SLUG" --hostname="$HOST"
The certificate stays PROVISIONING until the DNS authorization record is published. Point the name's A record at the Gateway's address once the certificate is ACTIVE.
AWS, Azure, and other load balancers
No chart provisions the edge on AWS or Azure. The DNS record, the certificate (an ACM certificate on an ALB or NLB, or a Key Vault certificate on an Application Gateway), and the listener or Ingress rule for each name are the operator's own. Where the Ingress or listener uses host-based rules, add a rule for each declared name. See Gateway installation on EKS and Gateway installation on AKS.
Step 4: check the certificate the data plane reads
A data plane on 0.7.0 or later reads the certificate serving each declared name and reports it beside the name: the subject alternative names, the issuer, the fingerprint, the validity window, the address the handshake reached, and where the reading was taken from. By default it dials each declared name over HTTPS, honouring HTTPS_PROXY and NO_PROXY, so it reads what a load balancer in front of the cluster presents as well as a certificate on the cluster's own listener.
global.gateway.certificateProbe changes where the data plane dials. There are 3 shapes:
-
A private load balancer the cluster reaches but cannot resolve by name. Name its address, and optionally a port, an SNI, and a CA bundle that decides whether the chain reads as trusted:
global:gateway:certificateProbe:address: dp-internal.eu-west-1.elb.amazonaws.comport: 8443sni: eu.acme.example.com # defaults to each declared name -
A GKE global external load balancer. Name the forwarding rule's address and leave
sniout, so each declared name is sent in turn and the certificate map answers with the certificate it holds for that name:global:gateway:certificateProbe:address: 34.120.0.1 -
An endpoint nothing inside the trust boundary can reach, such as a DMZ appliance or a CDN whose origin is unroutable. Turn the dial off:
global:gateway:certificateProbe:enabled: falseEvery address then reads as not observed and says the chart disabled the probe. The data plane stays healthy.
certificateProbe says where to look. Nothing in it changes what the certificate says, so an expired certificate never reads as healthy.
Run the same reading from the command line:
tare doctor /path/to/data-plane-credentials.json --only gateway
tare doctor reads the listener certificate where a listener carries one, and otherwise dials each declared address the same way the data plane does, honouring certificateProbe. It reports:
| Reading | Severity |
|---|---|
| The certificate does not cover a declared name | WARN, naming the hostname |
| The certificate has expired, or is not valid yet | ERROR, with the time validity starts or ended. A not-yet-valid certificate points at the cluster clock or the issuing CA |
| The certificate expires soon | Reported with the time left |
| The address could not be reached | INFO, with the openssl s_client command to read it by hand. The data plane stays healthy |
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
A declared name appears in the console but requests to it answer 404 | The load balancer has no route for the name. TLS completes, then nothing matches | Add the name to the load balancer's routes. On GKE, add it to gatewayHostnames on gateway-serve-helm |
The GKE certificate for a new name stays PROVISIONING | The DNS authorization record is not published | Publish the record that gcloud certificate-manager dns-authorizations describe prints, then wait for ACTIVE |
CreateProjectGateway, UpdateProjectGateway, or SetProjectGatewayURL fails with FailedPrecondition naming global.gateway.hostnames, including a console edit that resends an unchanged URL | The data plane declares hostnames, and the URL's hostname is not one of them | Add the hostname to the list and upgrade the chart. See Move a data plane to declared hostnames |
/healthz/membership answers 404 on one declared name while others answer 200 | The name is missing from the rendered ConfigMap, or the request's Host carries a non-standard port | Read tars-gateway-declaration as in Step 2. The probe answers on port 443 only |
| The console lists the old stored address again after an upgrade | helm upgrade ran without the values file, so the key was dropped | Re-run the upgrade with the values file, or use tare upgrade, which carries the list forward |
tare doctor warns that the certificate does not cover a name | The certificate's subject alternative names lack the declared name | Reissue the certificate with the name, or remove the name from the list |
Where to go next
Move a data plane to declared hostnames
Replace a stored data plane URL and gateway URLs with one declared list.
Serve a project from two data planes
Declare one hostname on two data planes and fail over between them with DNS.
Serve a project from a data plane
Label the data plane with the projects it serves.
Reading tare doctor output
Severities, categories, and common findings.