Configuration

Discovery sources and optional parent connections

Put live discovery under [[connector.discovery_sources]]. A source enumerates targets and publishes them inside its Authority-owned scope. It is a grouping origin, not a resource, and supplies no parent connection. Each discovered target is independently authorized and served over its own protocol.

0.11.x

Put live discovery under [[connector.discovery_sources]]. A source enumerates targets and publishes them inside its Authority-owned scope. It is a grouping origin, not a resource, and supplies no parent connection. Each discovered target is independently authorized and served over its own protocol.

To offer a connection to the server or cluster API as well, declare a backend with discovery_source = "<source-id>". The endpoint is inherited from that source. Missing sources, mismatched kinds, conflicting endpoints, multiple backends associated with one source, and a backend combining this reference with its own discovery block are refused at startup and by config check.

Kubernetes

toml
[[connector.discovery_sources]]
id = "cluster"
kind = "kubernetes"
api_url = "https://kubernetes.default.svc:6443"
ca_path = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
token_path = "/var/run/secrets/kubernetes.io/serviceaccount/token"

[connector.discovery_sources.discovery]
mode = "list_kube_targets"
scope = "kube-"
label_selector = "gdsgate.io/expose=true"
sources = ["service"]
interval_secs = 30

# Optional: separately expose the cluster API.
[[connector.backends]]
resource = "cluster-api"
kind = "kubernetes"
discovery_source = "cluster"
token_path = "/run/secrets/cluster-api-token"

The discovery token needs list access to the selected object kinds and no impersonation permission. API sessions may use a separate token with the required impersonation rights. If no session token is declared, the backend inherits the source token; it still needs the usual API-session permissions. Token refresh and revocation checks are unchanged.

Optional tenant membership collection

For reader RBAC, a complete paired configuration, identity examples and verification, see the Capsule integration guide.

Collection is disabled by default. Kubernetes discovery does not require tenant API permissions unless this block is enabled on its source:

toml
[connector.discovery_sources.tenant_visibility]
enabled = true
provider = "capsule"
api_version = "v1beta2"
refresh_interval_secs = 30
tenant_allowlist = ["orders", "payments"]
Key Type Default Purpose
enabled bool false Collect source membership facts independently of target publication.
provider string "capsule" Supported tenant API adapter.
api_version string "v1beta2" Supported tenant schema; other versions are refused.
refresh_interval_secs u64 30 Membership refresh interval, 1–3600 seconds; target discovery keeps its own interval.
tenant_allowlist array of string [] Exact tenant names to collect; empty means all.

The discovery credential additionally needs list on tenant objects in API group capsule.clastix.io and core namespaces. Collection uses resolved tenant owners and reciprocal namespace UID associations. The selected service/pod collections still follow the source's selector and object kinds. No secret read, write, impersonation or separate owner-object permission is required.

A read failure or five-second collection timeout publishes unavailable facts. Target discovery and healthy route renewal continue independently. If Authority cannot receive that update, the previous observation retains only its existing finite deadline. Authority filtering is enabled separately through catalog.visibility_rules.

Manual resources use the same collection path. An enabled source without a probe scope collects facts only and publishes no catalog entries or routes; bind the existing resource to its object in the Authority rule. Automatic publication continues to supply its assigned scope. PostgreSQL sources cannot enable tenant collection.

PostgreSQL

toml
[[connector.discovery_sources]]
id = "databases"
kind = "postgres"
addr = "127.0.0.1:5432"
auth_mode = "session_role"
service_account = "postgres://gdsgate_broker@127.0.0.1:5432/app_orders?sslmode=require"
service_account_password_file = "/run/secrets/database-session-password"
db_roles = [{ name = "readonly", db_user = "database_reader", read_only = true }]

[connector.discovery_sources.discovery]
mode = "list_databases"
scope = "databases."
connection = "postgres://database_probe@127.0.0.1:5432/postgres?sslmode=verify-full"
password_file = "/run/secrets/database-probe-password"
tls_ca_file = "/etc/gdsgate/database-ca.pem"
allowlist = ["app_*"]
interval_secs = 30

# Optional: also expose the session account's default database.
[[connector.backends]]
resource = "database-server"
kind = "postgres"
discovery_source = "databases"

The probe and session accounts are separate. The probe reads the database catalog; the session account must be a member of the configured roles and should have no other grants. Native clients supply no database username or password: the Connector authenticates the gdsgate session and applies the policy-authorized role. Source-only PostgreSQL requires session_role, because the Connector binds each authorized child to its exact database.

From v0.11.0-rc.10, discovery applies its own TLS settings before sending startup credentials. Rc.9 does not enforce the probe's DSN TLS requirements; upgrade before relying on them. The probe's DSN accepts sslmode=disable, prefer (default), require or verify-full. require refuses a server that does not offer TLS. verify-full also checks its certificate chain and the host from the source's addr; the DSN host does not override that address. tls_ca_file supplies a PEM trust bundle and accepts the usual file or secret reference. Without it, verification uses system roots. The session account's service_account_tls_ca_file does not configure the discovery account.

Duplicate modes and unsupported TLS options, including verify-ca, sslrootcert, sslcert and channel_binding, are configuration errors. Use tls_ca_file for the probe's CA. A certificate or mandatory TLS failure fails that probe and keeps its previous inventory until its freshness period expires. These settings also apply to legacy [connector.backends.discovery] blocks.

Manual sources publish IDs as the scope prefix plus the discovered database name. Keep the existing prefix when migrating, for example databases.. Automatic sources use their assigned node-qualified namespace. The exact database name travels as public target metadata; IDs are not parsed to guess it. A linked PostgreSQL backend uses session_role and inherits session settings it does not override, including the default database. Discovered children keep the source's session profiles.

Per-user status and JSON

The Resident groups targets by source. Without a visible backend it shows a source header with no address or connect command. With a visible backend it groups targets under that resource, retaining its own address, access decision and connect command. A visible backend denied by policy has no connect command; its accessible children keep theirs. Association grants no inherited access.

JSON keeps a flat resources array and adds discovery_sources. Resource rows carry discovery_source_id; source records carry id, name, kind and backend_resource_id. Authority qualifies the source ID with its enrolled node ID, so identically named sources on different Connectors do not merge. The name is the local source name from configuration.

Only sources represented by visible targets are listed. An invisible backend is absent from resources and its source reference is null. Upstream addresses and credentials never appear in these records. parent_id continues to mean real resource ancestry; source grouping does not change routing or policy ancestry. A source header exists only in text and is never an artificial JSON resource.

Compatibility and migration

[connector.backends.discovery] is deprecated and remains functional. It keeps its protocol and authentication behavior, including legacy passthrough and inventory-only probes. Startup and config check warn; they do not disable it.

For PostgreSQL, move the probe to a named source, configure the source's session account and role profiles, preserve the publication scope prefix, and replace the backend's probe with discovery_source = "<id>". Keep the backend to retain the parent connection, or remove it for discovery-only access. Remove or hide an old manually declared parent through the catalog separately if it should no longer be listed; changing Connector configuration does not delete catalog rows.

For Kubernetes, move the target probe and its read token to a source, and link the API backend only when API access is intended. Namespace inventory probes remain supported by the legacy backend configuration; namespaces are not individually connectable resources. Existing MCP tool probes also remain supported. Do not configure both discovery forms on the same backend.

New provenance and grouping require updated Authority, Connector and Resident binaries. Older wire peers ignore the added fields, retaining flat listings. Existing configurations remain readable; the optional storage migration adds public provenance without changing existing routes or grants.

See Connector fields, publication scopes, and Resident database clients.

Search this documentation edition.