Authority manages the resource catalog, resource attributes and the boundaries within which enrolled Connectors may publish. Connectors enumerate databases and Kubernetes objects through discovery sources.
A catalog entry identifies a resource for listing, authorization and routing.
Its presence does not mean a Connector is currently serving it; inspect the
serving column separately. See catalog lifecycle
and publishing resources.
[catalog]
Used by: Authority. Fields below are relative to [catalog] or the named nested
table. Validate a file with gdsgate config check <PATH> --role authority.
| Key | Type | Default | Purpose |
|---|---|---|---|
publication |
manual or auto |
manual |
Initial enrollment policy for new Connector identities. Used once when the shared policy is absent; an existing policy wins on restart. New configurations explicitly select auto. Existing nodes retain their assignments. |
lease_sweep_secs |
u64 | 60 |
How often Authority removes catalog rows whose publication leases expired. Each scope sets its lease length with lease_secs. |
Configuration and API ownership
At startup each Authority upserts the resources and scopes declared in its file. Rows absent from that file remain in the shared store. Removing a declaration from the file therefore does not delete the catalog entry. Conversely, a row that remains declared in any Authority file is restored from that declaration when that instance starts.
For an API-managed catalog, keep catalog.resources and catalog.auto_scopes
empty on every Authority. Manage rows with authority resources and boundaries
with authority scopes. The other [catalog] settings can remain in the file.
For file-managed declarations, keep every Authority's intended declarations
consistent and persist API changes in those files too.
[[catalog.resources]]: declared resources
| Key | Type | Default | Purpose |
|---|---|---|---|
id |
string | unset, required | Resource id. Matches what the connector registers and what clients request. |
kind |
string | unset, required | One of ssh, postgres, mysql, kubernetes, tcp, mcp, llm, web, web-egress, rdp. Selects the Cedar entity type (SshHost, Database, KubernetesCluster, TcpService, McpServer, LlmService, WebApp, WebEgress, RdpHost). The catalog has no cockroach resource kind. |
project |
string | "default" |
Owning project (Cedar parent: <entity> in Project::"<project>"). Use it to partition by team or tenant. |
min_approvers |
usize | unset | Resource-level JIT approval threshold, the narrowest level of the approvals cascade. |
hostname |
string | the resource id, when it is a legal name | Name clients can use for the resource. Relative DNS name: case-insensitive labels of at most 63 letters, digits or -, without empty labels or edge hyphens; at most 189 bytes in total. An id with _ or . has no name until hostname is set. |
aliases |
array of string | [] |
More names for the resource, same rules as hostname. |
port |
u16 | ssh 22, postgres 5432, mysql 3306, kubernetes 6443, web 80, rdp 3389 |
Port clients connect on. Required for tcp, mcp, llm and web-egress. Not related to the connector-side [[connector.backends]] addr, which is never published. |
native_name |
string | unset | web only. The application's own domain (app.example.com, at least two labels). A resident client answers to it locally only when its user lists it in [client].intercept_names. It is the name the connector sends in Host ([[connector.backends]] url). hostname is a relative DNS name inside the client zone, such as demo-ssh.connector-a (resolved as demo-ssh.connector-a.gds). See Resident client → An application's own name. |
pin_tool_descriptors |
bool | false |
mcp only. The first descriptor seen for a tool becomes its baseline; a tools/call on a tool whose descriptor changed is refused until the change is approved. See Pinning tool descriptors. On another kind, start-up is refused. |
A [[connector.backends]] entry with kind = "cockroach" (CockroachDB, port
26257) is published as kind = "postgres" with port = 26257. The catalog
has no cockroach kind.
Names are unique across the catalog, native_name included. A duplicate name,
declared or taken from an id, is refused at start-up, as is a tcp, mcp,
llm or web-egress resource without a port.
[[catalog.import_rules]]: label and environment rules
Rules apply in order to each declared resource whose id matches the glob. The
environment defaults to dev; the last matching rule sets it. Labels merge
across matches; a later rule wins per key.
| Key | Type | Default | Purpose |
|---|---|---|---|
match |
string | unset, required | Glob over resource id. Only * is special and it matches any run, including empty. |
environment |
optional string | unset, resolved environment dev |
Environment to set on a match. |
labels |
table of string to string | {} |
Labels merged on a match and exposed to Cedar as resource tags. |
Reserved labels
These labels also change gdsgate behavior. Like other labels, they merge across
rules and are visible to Cedar through resource.getTag(...).
| Key | Value | Effect |
|---|---|---|
pin_src_ip |
"true" |
Access certificates for this resource are bound to the client's TCP peer address at issue time. The connector rejects a session from another address. Any other value or no label: not pinned. |
Optional tenant visibility
For the complete setup and operational walkthrough, see Capsule tenant visibility. This section is the Authority settings reference.
catalog.visibility_rules is empty by default. With no rules, catalog listing
continues to use Cedar view alone and does not read membership facts. Enabling
collection on a Connector does not enable filtering on Authority.
To protect one Kubernetes source, configure both its collection block and a rule naming the enrolled Connector UUID and exact source ID:
[[catalog.visibility_rules]]
connector_id = "12345678-1234-1234-1234-123456789abc"
source_id = "prod-kube"
provider = "capsule"
user_claim = "sub"
include_additional_role_bindings = false
max_staleness_secs = 90
on_error = "hide"| Key | Type | Default | Purpose |
|---|---|---|---|
connector_id |
string | required | Enrolled Connector UUID; the display name cannot replace it. |
source_id |
string | required | Exact local Kubernetes discovery-source ID on that node. |
provider |
string | "capsule" |
Supported tenant API adapter. |
user_claim |
string | "sub" |
Verified identity subject; arbitrary claim paths are unsupported. |
user_prefix |
string | "" |
Prefix applied to subject comparison only. |
group_prefix |
string | "" |
Prefix applied to verified group comparison only. |
include_additional_role_bindings |
bool | false |
Count explicit additional binding subjects as members. |
max_staleness_secs |
u64 | 90 |
Maximum original fact age; allow more than the 20-second publication budget plus collection time. |
on_error |
string | "hide" |
Missing, unavailable, invalid or expired facts hide the protected source. |
manual_bindings |
array of table | [] |
Explicit resource associations described below. |
A member must also pass Cedar view. Missing membership hides discovery without
changing connect, query or Kubernetes-operation policies. Knowing a resource
ID can still allow a connection when its existing policy permits it. Source
associations in status contain only visible targets. Administrative catalog
inspection retains its existing authorization.
For a manually declared resource, add an explicit association to the selected service or pod under that rule:
[[catalog.visibility_rules.manual_bindings]]
resource_id = "orders-db"
object_id = "service/orders-dev/database"Both fields are required strings. The source must observe the object and verify its namespace UID against the tenant association. The binding is an operator assertion about the manual resource; gdsgate does not infer it from an address or resource label. A bound parent also restricts its database children.
Authority stores signed facts in the shared database and reads them on each listing. Every serving Authority needs the same rules and integrity keys. Restart Authority to change its rules. Reading, restarting or increasing the configured lifetime does not extend a stored observation's fixed expiry. See Connector collection settings.
Publication modes
Publication follows the enrolled Connector's assignment. The initial
catalog.publication value initializes the shared default only once.
gdsgate authority publication set changes the default for future enrollments;
existing Connectors keep their assigned mode and namespace.
gdsgate authority nodes list
gdsgate authority scopes list --wide| Assignment | Resource publication |
|---|---|
| Automatic | Authority assigns a namespace and scope to the enrolled node. The Connector publishes its permitted static backends and discovered targets within that assignment. |
| Manual | The administrator declares catalog resources and explicit serving assignments. A publication scope can additionally permit that node to publish discovered targets. |
For an automatic Connector, retain its assigned prefix and node when changing
scope limits with authority scopes set. For a manual Connector, a discovery
source's scope must match the prefix of a boundary assigned to its Registry UUID.
Scopes restrict publication; resource visibility and session access are still controlled by policy. Associating a discovery source with an accessible backend adds no inherited permission to that backend or its children.
[[catalog.auto_scopes]]: publication boundaries
Each scope permits one enrolled node to write catalog rows inside its prefix,
subject to kinds, attributes, limits and a renewable lease. This supports
short-lived resources, including discovered databases and Kubernetes targets.
Use the Registry UUID from authority nodes list for node.
| Key | Type | Default | Purpose |
|---|---|---|---|
id_prefix |
string | unset, required | Prefix every resource id inside the scope starts with. A scope whose prefix covers a declared resource, or overlaps another scope's prefix, is refused at startup and by authority scopes set. |
node |
string | unset, required | Enrolled node id (gdsgate authority nodes list) of the connector allowed to publish here. Authority matches the publishing peer's verified key fingerprint against this node. |
kinds |
array of string | unset, required | Resource kinds a target may be published as: ssh, postgres, mysql, kubernetes, tcp, mcp, llm, web, web-egress, rdp. A snapshot carrying any other kind is refused. |
project |
string | "default" |
Project written on every row in this scope. |
environment |
string | unset, required | Environment written on every row in this scope. Not taken from the source. |
labels |
table of string to string | {} |
Labels written on every row in this scope, overriding source labels with the same key. |
accept_label_keys |
array of string | [] |
Label keys accepted from the source. Keys outside this list are dropped. pin_src_ip is always dropped. On rows from an agent host, agent is set by Authority to the work that declares the face, whatever this list holds; a face no declaration names gets no agent. labels overrides both. |
max_live |
usize | unset, required | Maximum rows the scope holds at once, counting rows from earlier snapshots whose leases have not run out. A snapshot that would leave the scope over it is refused in full. See choosing max_live. |
lease_secs |
u64 | unset, required | How long a row stays after the snapshot that carried it. |
fallback |
parent | deny |
parent |
What an absent row means. parent: the parent resource's rules apply; a database is authorized through its host, and a target created between two probe passes is reachable. deny: a target with no row is not served. |
ssh_host_key |
annotation | tofu |
annotation |
Where an ssh target's host-key fingerprint comes from. annotation: the source states it, and a target that does not is not served. tofu: the first key seen is accepted for the lease. |
onward_auth |
array of local | certificate | client_key |
[] |
Onward modes an ssh target here may name. Required when kinds holds ssh, and refused when it does not. A snapshot naming any other mode is refused in full. |
enabled |
bool | true |
Whether the scope accepts publishes. Setting it to false deletes every row the scope holds. |
A scope with ssh in kinds must specify onward_auth. A scope prefix cannot
overlap a manually declared resource or another scope. Invalid declarations
are refused at startup and by authority scopes set.
authority scopes set replaces a scope declaration: supply every intended kind,
onward mode, label and limit. Disabling a scope removes its published rows.
Keep file-managed declarations synchronized with API changes as described above.
Choosing max_live
A row missing from a new snapshot remains until its lease expires. A source that replaces all its targets on each pass can leave up to this many rows:
targets_per_pass × (1 + lease_secs / interval_secs)For 300 targets, a 300-second probe interval and a 900-second lease, allow
1200 rows. A lower ceiling can refuse the full snapshot until earlier leases
expire. Narrow discovery filters, reduce the lease or raise max_live.
A catalog row can remain for up to catalog.lease_sweep_secs after its lease
expires. Listings show the remaining lease and mark an unswept row expired.
A returning resource must be admitted again before it becomes available.
Connector discovery
Configure probe credentials, filters, intervals and backend connection settings on the Connector. The discovery-source guide covers PostgreSQL and Kubernetes source-only discovery and optional parent connections. The Connector reference lists the fields.
PostgreSQL list_databases sources publish separately accessible database
resources. Kubernetes list_kube_targets sources publish the selected services,
pods or nodes. A source itself has no connect address. An associated server or
API is a separate resource with its own access decision.
For publication failures, check the Connector's refusal reason and
authority scopes list --wide: the node, prefix, enabled state, allowed kinds
and live-row ceiling must agree. Successful publication does not establish
permission to connect; check resource policy and backend permissions separately.
A full catalog example
[catalog]
publication = "manual"
lease_sweep_secs = 60
[[catalog.resources]]
id = "orders-db"
kind = "postgres"
project = "payments"
min_approvers = 2
[[catalog.import_rules]]
match = "orders-*"
environment = "prod"
labels = { service = "orders" }
[[catalog.auto_scopes]]
id_prefix = "database."
node = "11111111-1111-4111-8111-111111111111"
kinds = ["postgres"]
project = "payments"
environment = "prod"
labels = { service = "orders" }
max_live = 100
lease_secs = 300The declared resource and publication scope have separate IDs. The Connector
uses scope = "database." for a manual database source; configure the probe
and its session role using the discovery-source guide.
Migrating from [discovery]
[catalog] is the canonical name from 0.11.0-rc.8. The former top-level
[discovery] section remains supported with a deprecation warning. Rename that
section and its nested tables, keeping their values unchanged:
| Previous spelling | Current spelling |
|---|---|
[discovery] |
[catalog] |
[[discovery.resources]] |
[[catalog.resources]] |
[[discovery.import_rules]] |
[[catalog.import_rules]] |
[[discovery.auto_scopes]] |
[[catalog.auto_scopes]] |
A document containing both top-level names is refused, including when either
section is empty. Keep a single [catalog] section. Update the binary before
renaming an existing file; rc.7 uses the previous spelling.
Connector discovery_sources and its nested discovery probe tables retain
their names. Resource IDs, serving assignments, authorization rules and catalog
lifecycle are unchanged by the section rename.