Skip to content

Authority 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 [authority]. Each row gives the serde type and source default or unset meaning; keep keys and certificates in protected files. Check parsing and authority cross-field rules with gdsgate doctor --config <PATH> --json, then follow the multi-node control plane guide.

[authority]

Used by: Authority.

What Authority's registration listener ([endpoints].authority_enroll) presents, and whether Authority opens an emergency socket on its own host. Authority's control plane needs nothing here: it runs mutual TLS off the transport CA the cluster is built on, and both ends of it are nodes of this cluster. Registration is the one Authority surface whose peer is not one yet.

Key Type Default Purpose
enroll_cert_file string unset PEM certificate chain the registration listener presents. Unset, the listener speaks cleartext h2c.
enroll_key_file string unset PEM private key for enroll_cert_file. Naming one half of the pair and not the other is refused at start-up. Accepts the secret-reference notation; a helper or variable named here is re-run on each certificate rotation, not only at start-up.
emergency_socket string unset Path of the emergency administrative socket. Unset, there is no socket.
ca_kms_key string (optional) unset Which [[kms_keys]] entry wraps the CA signing seeds.
[authority]
enroll_cert_file = "/etc/gdsgate/enroll-fullchain.pem"
enroll_key_file  = "/etc/gdsgate/enroll-key.pem"

Cleartext is what this listener has always spoken and what an internal network is entitled to keep: the one-time provision token is the proof either way, and on a segment nobody else is on there is nothing to hide it from. Name a certificate where that segment is the internet. Everything crossing this listener is a credential in flight, a node's provision token and a workload's platform token on IssueWorkloadIdentity / RenewWorkloadIdentity, which sit on the same port, so an exposed deployment without one hands each of them to whoever is in the path.

gdsgate obtains no certificate, as it obtains none for [proxy].public_cert_file: an ACME client or a corporate issuer writes the two files and replaces them on renewal, and the listener re-reads them while it runs. See Renewing a listener certificate. The same pair can serve both listeners where one name fronts them.

Registration listener has no transitional mode

The listener is either cleartext h2c or TLS. It cannot be both, and nothing negotiates between them. The moment enroll_cert_file takes effect, every node's [enroll].endpoint has to change from http:// to https:// in the same rollout: a node still configured with http:// gets a connection that goes nowhere, and a node configured with https:// before the certificate exists gets the same.

This affects a hand-configured node hardest, because nothing on it tracks the change. What it costs depends on when it is noticed: a node that already holds an identity keeps working off it and renews over the control plane, which is a different listener and unaffected, so the failure surfaces only on a first registration, or on a node that has lost its state directory. Plan it as one change over the fleet, not as a per-node migration.

Turning it back off has the same shape in reverse.

The emergency administrative socket

[authority]
emergency_socket = "/run/gdsgate/auth-emergency.sock"

Unset is the default and means the socket does not exist. A cluster that never has to be repaired from its own host grows no surface by upgrading.

It is there for one situation: the policy refuses everybody, so neither a person through the gateway nor the administrative certificate decides anything, and the cluster cannot be repaired from where it is normally administered. The socket answers on the Authority host, and reaching it means having a shell there, which is deliberately harder than the everyday path.

The filesystem is the whole admission. Authority creates the socket 0600 and refuses to start if it comes up reachable by another account. The directory holding it is created 0700 when absent and read, not rewritten, when present, so pointing the key at a directory of your own does not change that directory; a directory other accounts can write to is refused instead, because anybody who can write there could unlink the socket and answer in its place, which no permission on the socket itself would prevent. Point the key at a directory the service account owns; the shipped systemd unit has a commented RuntimeDirectory=gdsgate / RuntimeDirectoryMode=0700 pair to uncomment beside this key, which gives exactly the path above and takes the directory away again when the service stops. Connections are accepted from the socket's owner and from root, and from nobody else.

It does not skip the policy. A call arriving here carries no identity, no token and no address, and offering any of them is refused, not ignored. It is decided by Cedar over User::"gdsgate-break-glass", the principal every accepted policy must keep able to edit the policy. That is what makes a lockout curable through it, and it is also why nothing else comes with it: outside editPolicy the socket reaches only what a rule names, which in the shipped baseline is nothing.

It carries PullPolicy, PushPolicy, the catalog calls and the registry listings, and refuses every other method by name. Audit rows from it name gdsgate-break-glass as the actor and carry admin_channel=emergency-socket in their detail, so an emergency is legible as one when the chain is read.

gdsgate doctor reports it, present, owner-only, and the directory around it, so a mode widened after the fact is found before it matters. The walkthrough is in Lock-out and recovery.

gdsgate doctor reports which of the two registration modes is in force (config.authority.enroll_listener), on the node side which of them that node is configured for (config.enroll.trust), and, where the join relay is bound, what registration crossing it travels as (config.proxy.join_relay). It reports the join on the client-facing listener in both states, with the call budget and both lane ceilings in force (config.proxy.public_join).

Wrapping the CA signing seeds

[authority]
ca_kms_key = "ca"

Unset is the default, and every CA generation goes on being stored the way it always has been: 32 bytes in the database's ca_private_key.seed column, readable by whoever can read the table. Naming a key here wraps every seed written from then on: the column holds ciphertext instead, opened once when a generation is loaded, at start-up and when a rotation publishes a new one, and never on the path that signs a certificate.

The value is a name, not a secret reference. ca_private_key has no column to carry one, so the key is named once, here, out of [[kms_keys]], and every row records the fingerprint of the key it was wrapped under; starting under a differently named key is a refusal naming both, not an unwrap that produces nothing readable. Rows already in the clear go on being read. gdsgate authority keys wrap-ca-seeds converts them, and a table that is only partway converted is a table a cluster keeps running on.