What a change affects¶
A change an operator makes after the first start. The table names it, what
else moves with it, and whether a role restarts. Each row links to its
section below for the files, the symptom if a dependent change is missed, and
a check. Procedures live at each section's reference link, including
operations/change.md.
| Change | Also change | Restart | Section |
|---|---|---|---|
| The name or address clients and connectors dial | DNS record, certificate SAN, client configs | Authority, Proxy | link |
| IP-only to a DNS name | certificate mode, workstation and connector trust | Authority, Proxy | link |
| Public certificate renewal, same CA | none | none | link |
| Public certificate: new CA, or Let's Encrypt to own CA | client and connector trust | none | link |
| Registration certificate renewal, same name | none | none | link |
| Registration certificate: name changes | transport_sni, [enroll].endpoint scheme |
Proxy, connectors | link |
dev to pilot |
store, certificates or identity | the role | link |
pilot to production |
OIDC issuer/client id, integrity keyrings | the role | link |
| Connector route classification | firewall | Authority, Proxy | link |
public_join / join relay toggle |
firewall, joined connectors' renewal address | Authority, Proxy | link |
Join relay to public_join, connectors already joined |
each connector rejoins | Authority, Proxy, connectors | link |
| A listener port | firewall, DNS, joined connectors' endpoints | the role that binds it | link |
| A bind address | firewall, [admin].endpoint |
Authority | link |
| Splitting onto two hosts | firewall, registration certificate | both roles | link |
| Joining back onto one host | firewall | both roles | link |
| SQLite to PostgreSQL | none | Authority | link |
| PostgreSQL address or password | network route, firewall | Authority | link |
| OIDC issuer or client id | provider discovery document, client re-login | Authority, Proxy | link |
| OIDC group mapping | provider client or mapper, complete public profile on nodes/clients | Authority, Proxy when gdsgate mapping changes; fresh client login | link |
| Adding a redirect URI | provider client configuration | none | link |
Naming or rotating control_keyring/audit_keyring |
every HA replica's keyring files | Authority, prepare step only | link |
| User SSH CA rotation | none | none | link |
| Onward SSH CA rotation | downstream sshd trust file |
none on gdsgate's side | link |
| HostTls / SPIFFE / JWT-signing CA rotation | propagation window for renewal or cache TTL | none | link |
| Audit export path | log shipper's watched path | Authority | link |
Recording storage mode or state_dir |
policy grant for central casts |
the connector | link |
| Adding an Authority replica | firewall, authority_failover on the Proxy |
every Authority, the Proxy | link |
| Product version upgrade | none | each role, in order | link |
| Evaluation build licence file | none | Authority | link |
Gateway name and address¶
The name or address clients and connectors dial¶
- Files and keys:
[endpoints].proxy_public/_internal/_ws(Authority: told to nodes; Proxy: bound) - Also change: DNS record;
[proxy].public_cert_fileSAN;[enroll].transport_sniwhere the Proxy dials Authority by another address; every client's~/.gdsgate/config.toml(gdsgate connect <name>again); an already-joined connector keeps its old advertised addresses inconnector.tomluntil it rejoins - Restart: Authority and Proxy (
[endpoints]read at start) - Symptom if missed: clients and new connectors dial the old name; an already-joined connector's tunnel and renewal calls keep going to the old address until it rejoins
- Check:
- Reference:
[endpoints]
IP-only to a DNS name¶
- Files and keys: certificate mode: own-CA/IP-address pair to Let's
Encrypt or own-CA name pair (Certificates);
[proxy].public_cert_file;[authority].enroll_cert_file; drop[enroll].transport_ca/--enroll-caonce the new certificate is publicly or system trusted - Also change:
--domainvalue in every futuresetup prepare/join; workstations trust the new pair without--fingerprint; connectors joined at the IP drop--enroll-caon their next join - Restart: Authority and Proxy for the new certificate files; connectors
need no restart for the reload, but a fresh
--enroll-ca-free join stops them carrying the old anchor - Symptom if missed: old workstations still pinned by
--fingerprintkeep working; a new one pointed at the address fails without--fingerprint - Check:
- Reference: Certificates: modes
Certificates¶
Public certificate renewal, same CA¶
- Files and keys:
[proxy].public_cert_file/public_key_file(also[authority].enroll_cert_file/enroll_key_filewhen one pair serves both listeners) - Also change: nothing
- Restart: none; certificate refresh within 1s;
kill -HUP <gdsgate-pid>orsc control ... paramchangeforces it now - Symptom if missed: none if the pair parses and the key matches; a bad pair leaves the old one in force
- Check: log line
listener certificate reloaded cert=<path> generation=<n>; a new TLS handshake presents the new pair - Reference: Renewing a listener certificate; Certificates: renewal
Public certificate: new CA, or Let's Encrypt to own CA¶
- Files and keys: same files; clients that pinned the old CA via
SSL_CERT_FILE/system store - Also change: every client and connector trust source: system store
update, or a fresh
--enroll-ca/--fingerprint - Restart: none; hot reload of the files; client-side trust update is manual, per host
- Symptom if missed:
gdsgate connectreportspublished no transport CA anchor, and the certificate authorities this host trusts do not vouch for it either - Check: on the new pair before installing it
- Reference: Certificates: own CA
Registration certificate renewal, same name¶
- Files and keys:
[authority].enroll_cert_file/enroll_key_file - Also change: nothing
- Restart: none; same hot reload as the public pair
- Symptom if missed: none
- Check: same log line,
cert=<enroll_cert_file path> - Reference: Renewing a listener certificate
Registration certificate: name changes¶
- Files and keys: same files;
[enroll].transport_snion every Proxy/connector that dials Authority by another address or an internal name;--enroll-caon nodes trusting a private CA - Also change: going from cleartext to TLS on this listener changes
every node's
[enroll].endpointfromhttp://tohttps://in the same rollout - Restart: every Proxy and connector whose
[enroll]block changes; the listener itself only hot-reloads the pair - Symptom if missed: no transitional mode: a node with the wrong scheme
cannot connect at all;
certificate refused (NotValidForName...) - Check:
- Reference:
[authority], no transitional mode
Security profile¶
dev to pilot¶
- Files and keys:
[security].profile;gdsgate authority profile set --profile pilot --changed-by <name>for Authority, orgdsgate setup change --set <role>:security.profile=pilotfor any role - Also change: Authority:
store_urlto PostgreSQL,[authority].enroll_cert_file/enroll_key_file; Proxy:[proxy].public_cert_filepair or an enrolled identity,[enroll].endpointschemehttps:// - Restart: the role (
[security].profileread at start;set-profilewrites the file but does not restart) - Symptom if missed: the service refuses to start and lists every failed check at once
- Check:
exit
0clean,1error,2warning-only - Reference: Profile matrix;
gdsgate config check
pilot to production¶
- Files and keys: same, plus
[oidc].issuer/client_id;[security.integrity].control_keyring/audit_keyring, two distinct files - Also change: keyring file ownership/mode (
0640groupgdsgate, or owner-only); every replica holding the same keyrings before promoting a key - Restart: the role; a keyring add/rotate needs an Authority restart of every replica (ring read at start)
- Symptom if missed:
`[oidc].issuer` and `[oidc].client_id` are unset;`[security.integrity].control_keyring` names no keyring; a keyring on the wrong permissions refuses at start - Check:
- Reference: Profile matrix;
[security.integrity]
Connector route¶
Route classification¶
- Files and keys:
[connector].authority_transportin Authority's file (direct/tunneled/fronted);setup preparewrites it from the flags below - Also change: firewall for the ports the new route needs
- Restart: Authority and Proxy; an already-joined connector needs
gdsgate join --if-missing --route fronted(ordirect/tunneled), no token: the route rewrites the advert this node renews at - Symptom if missed: a connector still on the old route's advert renews at the wrong address and fails once its certificate cannot renew there
- Check:
output line
--route fronted: Authority ..., renewal ...names the new address - Reference: Connector routes;
gdsgate join
public_join, the join relay, --no-public-join¶
- Files and keys: Proxy and Authority:
[proxy].public_join,[endpoints].proxy_join;setup prepareflags: none (public_join),--join-relay,--no-public-join - Also change: firewall (
50061vs50064vs50050/50051); every already-joined connector's[enroll].renew_endpoint - Restart: Authority and Proxy
- Symptom if missed: an already-joined connector keeps dialing the retired relay or port for renewal; once its transport certificate cannot renew there, it drops off the cluster with no warning before that point
- Check:
gdsgate config check <proxy-file> --role proxy(proxy.public_joinwarns if the listener has no name-bearing certificate);renew_endpointin the connector's own file - Reference:
public_join;proxy_join;gdsgate join
Join relay to public_join, connectors already joined¶
- Files and keys: Authority:
[proxy].public_join = true,[endpoints].proxy_joinremoved; Proxy:[proxy].public_join = true,[endpoints].proxy_joinkept until the last connector has moved - Also change: each connector, no token:
plus the arguments it joined with; it renews at
50061and writes that asrenew_endpoint. Then removeproxy_joinfrom the Proxy's file and close50064 - Restart: Authority, then the Proxy, before the connectors run
join; each connector right after its run; the Proxy again after removingproxy_join - Symptom if missed:
joinstops withAuthority's file still sets [endpoints].proxy_joinwhile Authority advertises the relay; a connector not restarted after its run logsrenewal denied: unknown identity; a connector not moved when50064closes cannot renew; an expired identity needs--forceand a fresh token - Check:
renew_endpointin each connector's file; on the Proxy underRUST_LOG=gdsgate_proxy=debug, eachrelaying joinline names the IP of a node still on50064.list-nodesand the Proxy's metrics do not show the renewal address - Reference: Moving the registration
address;
proxy_join
Listener ports and bind addresses¶
A listener port¶
- Files and keys:
[endpoints].*on the role that binds it, and on Authority's file when split (Authority does not bind the Proxy's addresses, but advertises them) - Also change: firewall; DNS/clients dialing a fixed port;
already-joined connectors'
[endpoints].proxy_internal/proxy_wsand[enroll].renew_endpoint, static inconnector.toml - Restart: the role that binds the port, and Authority if its
[endpoints]names it for advertising - Symptom if missed: a connector whose one changed port has a live twin
(
proxy_wswhen onlyproxy_internalmoved) fails over to it on its own; with no live twin, its tunnel and renewal both fail silently until manually rejoined - Check:
- Reference:
[endpoints]; What Authority tells a joining node
A bind address¶
- Files and keys:
--authority-bind/[endpoints].authority/authority_enroll - Also change: firewall rule scoped to the new address;
[admin].endpointif it names the old one - Restart: Authority
- Symptom if missed: administrative CLI hangs dialing the old address; a joining node told a wildcard address reports it received none
- Check:
- Reference: Separate hosts: traffic
Splitting or joining Authority and Proxy¶
Splitting onto two hosts¶
- Files and keys: Authority:
--authority-bind <reachable-address>(not loopback, not a wildcard with--no-public-join); Authority's file also carries the Proxy's[endpoints],[proxy].public_join,[connector].authority_transport, since Authority does not bind them but must advertise them - Also change: firewall on the Authority host, allowing the Proxy's address on the registration and control-plane ports; the registration listener now needs a certificate off the loopback
- Restart: both roles
- Symptom if missed: the Proxy times out reaching Authority; a joining node receives only its identity, no addresses, when Authority's file lacks the Proxy's advertised settings
- Check:
- Reference: Separate hosts; Split deployments must declare the Proxy's addresses
Joining back onto one host¶
- Files and keys: reverse of the above;
--authority-bindback to loopback - Also change: firewall rule removed
- Restart: both roles
- Symptom if missed: none specific;
gdsgate all(single process) is refused underpilot/production, so the two roles stay separate processes on the one host - Check:
- Reference:
all-in-one
The store¶
SQLite to PostgreSQL¶
- Files and keys:
store_url,store_password_file - Also change: nothing else in
[endpoints]/[proxy] - Restart: Authority
- Symptom if missed: no safe path: there is no export/import between
backends; the new
store_urlstarts an empty store (policy, catalogue, registry, audit chain all begin again) - Check:
(
store-postgres) - Reference: Top level; Profile matrix
PostgreSQL address or password, same data¶
- Files and keys:
store_urlhost/port,store_password_file - Also change: network route/firewall to the new address
- Restart: Authority
- Symptom if missed: connection refused at start; run
authority store migrate --checkagainst the new address before cutover - Check:
- Reference: Top level; Store schema
Identity provider¶
Issuer or client id¶
- Files and keys: the complete
[oidc]profile in every Authority and Proxy config, then the selected saved client configs - Also change: the trusted discovery issuer, registered client and
authorized node issuer/client bindings must agree. Refresh client configs
through verified
connect, then sign in again. Retain protected node metadata; do not delete it to bypass a conflict. - Restart: Authority and Proxy
- Symptom if missed:
gdsgate loginfails at the provider, or Authority refuses the token: issuer mismatch - Check:
- Reference: profile lifecycle and
[oidc]
Groups claim name¶
- Files and keys:
[oidc.claims.groups]selects the identity-token claimpath, explicitformat, optionaldelimiterandrequiredbehavior - Also change: the provider's identity-token mapper and exact group names in the reviewed access policy. Distribute the same OIDC mapping to every Authority, Proxy and saved client config.
- Restart: Authority and Proxy when their OIDC config changes; client reload and a fresh login. A provider-only mapper change needs a fresh token, without changing gdsgate files.
- Symptom if missed: an optional missing claim yields no memberships; required/malformed claims fail mapping; group-scoped policies deny
- Check: fresh
gdsgate login, its group summary, then an allowed and a denied operation against the intended cluster. Keep bearer tokens private. - Reference: claims-to-policy example and sanitisation
Adding a redirect URI¶
- Files and keys: provider-side client configuration only
- Also change:
gdsgate login --browser: loopbackhttp://127.0.0.1:<port>/callback; the clientless browser entry:https://gdsgate.<webapps_zone>/callback - Restart: none on gdsgate's side
- Symptom if missed: the provider answers
invalid redirect_uri - Check:
or open
https://gdsgate.<webapps_zone> - Reference:
gdsgate login; The clientless browser entry
Keyrings and CA rotation¶
Naming or rotating control_keyring/audit_keyring¶
- Files and keys:
[security.integrity].control_keyring/audit_keyring;gdsgate authority keys rotate <ring> --prepare|--activate|--retire - Also change: every HA replica needs the same keyring files before
--activate - Restart:
--prepareneeds a restart of every Authority (ring read at start);--activate/--retireapply live - Symptom if missed:
productionrefuses two rings naming the same file;--activaterefused when a replica has not published the prepared key - Check:
- Reference: Rotating a keyring;
keys rotate
User SSH CA rotation¶
- Files and keys:
gdsgate authority ca rotate user-ssh, or[ca_rotation]on a schedule - Also change: nothing client-side; certificates reissue on the next connect
- Restart: none; live, paced double-signing rotation
- Symptom if missed: a session opened during too-short
propagation_secsis refused by a verifier still on the old bundle - Check:
gdsgate authority keys status; a session-level connect during the window - Reference:
[ca_rotation]; CA rotation
Onward SSH CA rotation¶
- Files and keys:
gdsgate authority ca rotate onward-ssh - Also change: every downstream
sshd'sTrustedUserCAKeys - Restart: none on gdsgate's side; the downstream
sshdneeds its trust file updated and reloaded - Symptom if missed: the downstream host refuses the new certificate:
Certificate invalid: unknown CA - Check: through the connector
- Reference:
rotate-onward-ca
HostTls / SPIFFE / JWT-signing CA rotation¶
- Files and keys:
gdsgate authority ca rotate host-tls/rotate-spiffe-ca/rotate-jwt-ca - Also change:
[ca_rotation].propagation_secsmust cover a full mTLS renewal cycle (HostTls/SPIFFE) or the application's JWKS cache TTL (JWT) - Restart: none; nodes and applications pick up the new bundle on their next renewal or cache refresh
- Symptom if missed: a verifier that has not refreshed refuses the new certificate inside the propagation window
- Check: metric
gdsgate_transport_identity_renewals_total;GET /.well-known/gdsgate/jwks.jsoncache headers - Reference:
rotate-host-tls-ca;rotate-jwt-ca
Audit export and recording storage¶
Audit export path¶
- Files and keys:
[audit].export_path - Also change: the log shipper's watched path; under systemd, the new
path must sit under the unit's
ReadWritePaths=/state directory - Restart: Authority (path opened at start)
- Symptom if missed:
`[audit].export_path` is unsetwarning at start; oraudit export file: the service cannot write it - Check:
- Reference:
[audit]
Recording storage: disk to central, or [enroll].state_dir¶
- Files and keys:
[recording].mode,[recording].sweep_interval_secs - Also change: a policy grant to read
AuditLog::"recordings"for browsingcentralcasts; astate_dirmove leaves existing on-disk casts behind with no automatic carry-over - Restart: the connector
- Symptom if missed: casts pile up undelivered;
gdsgate doctorreports them pending or left behind - Check:
- Reference:
[recording]
High availability¶
Adding an Authority replica¶
- Files and keys: new instance: same
store_url,[ha].enabled = true; Proxy:[endpoints].authority_failoverlisting the new address - Also change: firewall opening the new Authority's
50050/50051to the Proxy and to its peers; a shared PostgreSQL store (HA does not work on SQLite) - Restart: every Authority instance and the Proxy
- Symptom if missed: without
authority_failoveron the Proxy, failover is invisible to it and it keeps dialing one instance only; mismatched keyrings across replicas refuse at start underproduction - Check:
- Reference:
[ha];authority_failover
Version and licensing¶
Product version upgrade¶
- Files and keys: binary replacement;
store_auto_migrateexplicitly set for a planned migration - Also change: order: upgrade every Proxy before Authority, and Authority before connectors when the SSH gate is on
- Restart: each role in order
- Symptom if missed:
auth refused connector registrationreasonregistration carries no resource kinds(wrong order);gate_not_offeredon unupgraded connectors after activation - Check:
- Reference: Upgrade guide
Evaluation build licence file¶
- Files and keys: none in TOML:
--file <path>ongdsgate license show/verify, orGDSGATE_LICENSE_FILEin the process environment - Also change: nothing else; the document is read once, at Authority start
- Restart: Authority: the licence loads once into memory at start, not re-read while running
- Symptom if missed: Authority keeps enforcing the previous document's expiry until restarted, even after the file is replaced
- Check:
metric
gdsgate_license_expires_unix - Reference: Metrics and health