Security configuration¶
Paths in the tables are relative to [security], [security.integrity],
[mfa] or [ca_rotation]. Keep keys and credentials in protected files. Check
parsing and cross-field rules with gdsgate doctor --config <PATH> --json. See
also the CA rotation guide.
[security]¶
Used by: every role.
| Key | Type | Default | Purpose |
|---|---|---|---|
profile |
string (optional) | unset | The deployment profile this cluster is held to at start-up: dev, pilot, or production. |
| Profile | At start-up |
|---|---|
| unset | No checks, no warnings. gdsgate doctor reports that no profile is set. |
dev |
No checks. One line says the deployment is a development one. |
pilot |
Refuses the faults in the table below. |
production |
Refuses the faults below and the additional production checks. |
Every check per profile, with the key or flag that satisfies it: Profile matrix.
pilot and production refuse these faults; the error lists all faults found:
| Role | Refused |
|---|---|
| Authority | store_url does not name a PostgreSQL store. [authority].enroll_cert_file names no certificate for the registration listener. |
| Proxy | No [proxy].public_cert_file pair and no enrolled identity, so the client-facing listener would run without TLS. The connector-facing listeners would run without mutual TLS. A configured [enroll].endpoint is not https://. |
| Connector | The node has no enrolled identity. A configured [enroll].endpoint is not https://. |
Any role, started as gdsgate all |
Authority, Proxy and Connector would run in one process with the certificate authority in memory. |
With [audit].export_path unset, both profiles warn and start.
production also refuses:
| Role | Refused |
|---|---|
| Authority | [oidc].issuer or [oidc].client_id is unset (Authority would accept tokens from the built-in development issuer). |
| Authority, Proxy with the clientless browser entry | [oidc].allow_insecure_http = true (allowed only outside production, for a lab or dev provider). |
| Authority | The two [security.integrity] keyrings are not both set, or are the same file. |
| Authority | A keyring, or a [audit].*_key_path file that exists on disk, is readable by anyone other than the service. See [security.integrity]. |
After opening the store, production Authority checks the store's rows before
serving:
| Check | Result |
|---|---|
| A key fingerprint held by some Authority replicas and not others, with rows already sealed under it | refused |
| The same, with no rows sealed under it (a rolling keyring rotation in progress) | warning |
The newest sealed row of a table names a key that neither keyring holds and that was not declared lost with keys accept-loss |
refused; usually the wrong keyring file, or a database restored without its keyring |
See
Administration → gdsgate authority keys status
and
keys accept-loss.
[security.integrity]¶
Used by: Authority only.
The two keyrings that seal the cluster's rows. Each field accepts a
secret reference, including the
${kms.<name>+...} wrapper. A bare value is a file
path.
| Key | Type | Default | Purpose |
|---|---|---|---|
control_keyring |
string (optional) | unset | Keyring approvals, revocations, delegations, and inventory receipts are sealed under. |
audit_keyring |
string (optional) | unset | Keyring the audit chain's anchors are sealed under. |
[security.integrity]
control_keyring = "/var/lib/gdsgate/authority/control.keys"
audit_keyring = "/var/lib/gdsgate/authority/audit.keys"
Use two different files. The same file for both, directly or through another
path, is refused under production; pilot warns.
Both fields are optional. Unset, Authority uses the five [audit].*_key_path
files (see Operations → [audit]).
Who may read a keyring or a seal key. Only the service. The keyring reader
checks this whenever it opens a keyring, under every profile. production also
checks both keyrings and every existing [audit].*_key_path file before
serving.
| Platform | Accepted | Refused |
|---|---|---|
| Linux | Owner root or the service account; mode 0640 with group gdsgate. The shipped units run with DynamicUser=yes and SupplementaryGroups=gdsgate; gdsgate setup leaves /etc/gdsgate/*.keys as 0640 with group gdsgate. |
Any other owner; readable by others (for example 0644); a group the service is not in. |
| Windows | Access entries only for the file owner, SYSTEM, and NT SERVICE\gdsgate-authority, -proxy or -connector. gdsgate service install writes these entries onto the configuration's files. |
Any other access entry; a file with no access list. |
gdsgate authority keys migrate-legacy imports the keys of the five
[audit].*_key_path files into the two keyrings as verify-only records with
their existing fingerprints. Existing rows keep verifying. New rows are sealed
with the five key files until a keyring has an active key, so keep the five
parameters in the configuration. With a keyring set, gdsgate doctor lists the
files not yet imported. See
Administration → gdsgate authority keys migrate-legacy.
[mfa]¶
Used by: Authority.
Gateway step-up MFA factors. TOTP (gdsgate mfa enroll / verify) needs no
configuration. WebAuthn (passkeys) needs [mfa.webauthn]; without it WebAuthn
is off and webauthn_satisfied in Cedar is always false.
| Key | Type | Default | Purpose |
|---|---|---|---|
webauthn.rp_id |
string | unset | WebAuthn relying-party id: the domain a passkey is bound to. Each origin's host must be rp_id or its subdomain. |
webauthn.origins |
list | [] |
Browser origins (scheme://host[:port]) for the ceremony. Must be https://, except with allow_localhost. |
webauthn.allow_localhost |
bool | false |
Development only. Allow http://localhost origins. Passkeys are then bound to the workstation. |
webauthn.allow_any_port |
bool | false |
Development only. Accept any port on the origin host; the loopback ceremony uses a new port each run. Requires allow_localhost. |
webauthn.rp_origin |
string | unset | Legacy single-origin alias, added to origins. |
In production the ceremony runs on the gateway's browser origin
([proxy].public_origin/web_addr):
gdsgate mfa register-passkey and step up with
gdsgate step-up <resource>; both open the gateway's confirmation page. See
Policy → Two MFA channels.
Development: localhost loopback
Without a gateway web origin the CLI runs the ceremony on a loopback page
(http://localhost:<port>), and the passkey is bound to localhost. This
is refused at start-up unless enabled:
Migrating off localhost
A passkey registered for localhost does not work on a gateway-domain
origin. To move to production: set [proxy].public_origin and web_addr,
remove allow_localhost and allow_any_port, and have each user run
gdsgate mfa register-passkey again. Old localhost passkeys stop working;
nothing needs to be revoked.
[ca_rotation]¶
Used by: Authority.
Scheduled rotation of the User SSH CA; off by default. Manual rotations of the
Onward SSH, HostTls, SPIFFE and JWT-signing CAs use the same timing settings.
The manual commands gdsgate authority rotate-ca, rotate-onward-ca,
rotate-host-tls-ca, rotate-spiffe-ca and rotate-jwt-ca work regardless of
enabled. Only the User SSH CA rotates on a schedule.
The end of each wait is stored with the rotation phase. A restarted Authority
or a new HA leader takes the next step at that stored time or later, whatever
its own propagation_secs and retire_secs are; see
HA.
For HostTls, set propagation_secs to cover a full
mTLS renewal cycle. For JWT-signing, cover how long
web lane applications cache the key set; see
Telling the application who came.
| Key | Type | Default | Purpose |
|---|---|---|---|
enabled |
bool | false |
Master switch for the scheduled rotation. |
interval_secs |
u64 | 2592000 (30 days) |
Cadence. 0 disables the schedule. |
proactive_secs |
u64 | 604800 (7 days) |
Also rotate when the active generation has less than this much validity left. 0 disables the safety net. |
propagation_secs |
u64 | 300 (5 min) |
After publishing the candidate, wait this long for verifiers (Proxy, connectors) to refresh their trust bundle before promoting it to the signer. |
retire_secs |
u64 | 3600 (1 h) |
After promotion, wait this long before retiring the old CA. Set it at or above the issued-certificate TTL. |
check_secs |
u64 | 3600 |
How often the controller checks whether a rotation is due. |