Skip to content

Enrollment configuration

The flat configuration hub remains the compatibility route. This page is the canonical source-checked field reference for its family, including nested tables and list rows.

Paths in the tables are relative to [enroll]. Each row gives the serde type and source default or unset meaning; tokens are supplied through protected files or the supported environment overlay. Check parsing and enrollment cross-field rules with gdsgate doctor --config <PATH> --json, then follow the registration lifecycle guide.

[enroll]

Used by: Proxy, Connector.

Set on a standalone Proxy or Connector so it obtains its transport identity and runs internal mutual TLS. When endpoint is set and a token is supplied, in the file or through GDSGATE_ENROLL_TOKEN, the node registers on first start; on subsequent starts it reuses the persisted identity in state_dir.

For a connector, gdsgate join writes this section: it registers first and leaves the identity in state_dir, so the file it produces carries no token and the service never needs one.

Key Type Default Purpose
endpoint optional string unset, enrollment off Authority registration URL. A tunnelled connector derives the address from endpoints.proxy_join when this is unset.
token optional string unset One-time registration token. Prefer GDSGATE_ENROLL_TOKEN so the secret is not stored in the file, or write the field itself as a secret reference (${file:...}, ${env:...}, ${exec:...}). A bare value is the token itself, not a path.
state_dir optional string unset, per-role directory under ~/.gdsgate/state Directory for the persisted transport identity and SSH model A host key.
renew_endpoint optional string unset, derived from the Authority or tunnel relay Authority mTLS endpoint for token-less renewal. It must use https://.
background_renewal bool true Whether the running process keeps its transport leaf current.
node_name optional string unset Registry label sent on join. It is not defaulted to the host name and must satisfy the documented charset and length check.
transport_ca optional string unset, platform trust store PEM anchor for an HTTPS registration listener. It is refused on a cleartext endpoint.
[enroll]
endpoint       = "http://auth:50050"
renew_endpoint = "https://auth:50051"
state_dir      = "/var/lib/gdsgate/proxy"
# token is supplied at boot via GDSGATE_ENROLL_TOKEN

Registration token is single-use

Authority consumes the registration token once. After registration the node runs off its persisted identity, which it renews over mTLS, with no new token. Do not bake long-lived tokens into the file; supply them out of band on boot.

renew_endpoint requires the https:// scheme

Renewal is a mutual-TLS call: the node presents the leaf it already holds and Authority authenticates it by that certificate. Whether TLS runs at all is decided by the scheme of the URL and by nothing else, and a configured certificate on an http:// target is dropped before the dial, without an error anywhere.

A node pointed at http:// therefore registers, serves, and renews nothing. The first symptom is the leaf expiring hours or days later, at which point the one-time join token that could have rescued it is long spent and an operator has to issue a new one for every node in the batch.

It is therefore refused at start-up, not merely warned about, and gdsgate doctor reports it (config.enroll.renew_scheme) before the start-up is attempted. The same rule applies to [admin].endpoint and to the renewal address a cluster advertises: a scheme renewal cannot run over is a fault in the cluster's configuration, and the node refuses it quoting what arrived rather than repairing it.

Automatic identity renewal

A transport leaf is valid for 24 hours, or for whatever [transport].cert_ttl_secs says on the Authority that issued it. A Proxy or Connector renews it on its own, without a restart and without a token:

  • an hour before the leaf expires, the node calls Authority over mutual TLS (renew_endpoint) presenting the leaf it already has, and receives a new one for a fresh 24 hours;
  • the new material is written to state_dir and takes effect for every new connection from that moment. Connections already open are not touched, since TLS material is used at handshake time;
  • the listeners follow too, so a peer reconnecting to the node is shown the new certificate without the port being rebound;
  • every attempt is bounded: 10 s for the connect and the handshakes, 20 s for the call itself. An Authority that has died fails an attempt at once; an Authority that stops answering (frozen, overloaded, behind a firewall that swallows packets) accepts the connection and says nothing, and without a ceiling that one call would absorb the whole window;
  • a failed renewal is logged at warn and retried with a growing delay (30 s up to 10 min), so around nine attempts fit inside the hour of headroom even when every one of them runs out its budget. The node keeps working on the leaf it has, so an Authority outage shorter than that hour passes unnoticed.

Every figure above is the one a 24-hour leaf produces. None of them is a constant: the hour of headroom, the sleep between looks, the per-attempt budget and the backoff are all shares of the leaf actually in hand, so a shorter cert_ttl_secs contracts all of them together. See [transport].

The renewal is token-less only: it never falls back to a registration token, because the join token is single-use and long spent by then.

background_renewal = false turns this off. Without it, the node stops accepting new connections a day after it started, and only a restart brings it back. It exists for a deployment that refreshes state_dir by some other means, and as a way to switch the behaviour off without rolling back a binary. gdsgate doctor reports a warning while it is off.

Watch it through gdsgate_transport_identity_expires_in_seconds and gdsgate_transport_identity_renewals_total; see Operations → Metrics.