Integrations¶
This page covers how gdsgate plugs into the systems around it: identity providers, native clients per protocol, CI pipelines, and the SIEM / observability stack.
OIDC identity provider (Keycloak)¶
gdsgate is an OIDC relying party. Auth verifies each identity token against the provider's published signing keys (RS256 via JWKS) and maps the token's claims to a principal and its groups, which the Cedar policy authorises. The example below uses Keycloak; any standards-compliant OIDC provider works.
Configure gdsgate¶
[oidc]
issuer = "https://keycloak.example.com/realms/gdsgate"
client_id = "gdsgate"
# audience defaults to client_id when unset
Auth fetches <issuer>/.well-known/openid-configuration and the JWKS
at startup and verifies every token's signature, issuer, audience, and
expiry.
Issuer must match exactly
The configured issuer, the issuer Keycloak advertises, and the
token's iss claim must all be byte-identical. Keycloak
derives the issuer from the request host, so reach Keycloak by
one hostname from every node and client.
Configure the Keycloak client¶
Register a client gdsgate in your realm:
- Public client (no secret) with the flows the CLI uses:
- Standard flow (Authorization Code + PKCE) — desktop login
(
gdsgate login --browser); - Direct access grants — headless / CI token retrieval;
- OAuth 2.0 Device Authorization Grant —
gdsgate login(device flow, the default and works over SSH).
- Standard flow (Authorization Code + PKCE) — desktop login
(
- Redirect URIs for the PKCE loopback:
http://127.0.0.1/*,http://localhost/*.
Emit a groups claim¶
gdsgate authorises on the token's groups claim. Add a Group
Membership mapper to the client (or to a shared client scope):
- Mapper type: Group Membership
- Token claim name:
groups - Full group path: off (emit bare names like
admins, not/admins) - Add to ID token: on
A user in the realm group admins then receives "groups": ["admins"]
in the identity token, and the Cedar policy can match
principal in Group::"admins".
Map groups to access with Cedar¶
The token's groups become the principal's Cedar group memberships. Scope each action to a group:
permit(principal, action == Action::"dbConnect", resource)
when { principal in Group::"admins" };
permit(principal, action == Action::"sshConnect", resource)
when { principal in Group::"admins" };
With this policy a user in admins is allowed database and SSH access
while a user in any other group is denied — across every protocol,
from one policy. See Policy for more patterns.
Headless tokens (CI, scripts)¶
The device flow is the human path. For automation, obtain the token
out of band and pass it through GDSGATE_ID_TOKEN. For Keycloak with
direct grants:
GDSGATE_ID_TOKEN=$(curl -s \
-d client_id=gdsgate -d grant_type=password \
-d username=alice -d password=… -d scope=openid \
https://keycloak.example.com/realms/gdsgate/protocol/openid-connect/token \
| jq -r .id_token)
Now every gdsgate <command> and every kubectl / psql invocation
through gdsgate proxies will run as alice.
Native clients per protocol¶
For full client-side workflows see the User guide. Summary of the integration points:
ssh (OpenSSH)¶
A client-config fragment routes ssh through gdsgate via
ProxyCommand. The fragment is emitted by:
The --config path is woven into the generated ProxyCommand so
native ssh (with no gdsgate flags of its own) reaches the right
cluster. -L, -R, PTY, exec, SFTP, agent-forwarding, and live
window-resize all work. Forward channels are gated by
sshForwardLocal / sshForwardRemote in Cedar plus the agent's
allow-lists.
psql / mysql¶
A localhost relay accepts native database clients:
The agent taps the client→server stream and emits a structured query log into the audit chain.
kubectl¶
kubectl integrates through an exec credential plugin plus a
localhost relay. Emit a kubeconfig fragment, point kubectl at the
relay, and on every call kubectl runs gdsgate kube credentials
for a short-lived credential. The gdsgate Kubernetes listener
resolves the identity and impersonates the user on the real API.
redis-cli and other TCP clients¶
Run a localhost TCP relay:
MCP clients¶
MCP servers are reached the same way as TCP, with the agent gating
each tools/call against allowed_tools before it reaches the
backend.
CI pipelines¶
CI jobs reach resources through gdsgate exactly like a user — authorise once with a service-account identity token, then use native tools:
export GDSGATE_ID_TOKEN="$CI_GDSGATE_TOKEN" # a service-account id_token
# Database migration
gdsgate --config /etc/gdsgate/client.toml db proxy prod-db --listen 127.0.0.1:5433 &
DBPID=$!
psql -h 127.0.0.1 -p 5433 -f migrations.sql
kill "$DBPID"
# Or a one-off SSH exec
ssh -o StrictHostKeyChecking=accept-new \
-o UserKnownHostsFile=$CI_PROJECT_DIR/known_hosts \
deploy@web-01.gds 'sudo systemctl reload nginx'
The job's access is policy-controlled, audited, and the identity
appears in the audit log under the service account's sub.
Tips:
- Cache
transport-ca.pemas a CI variable and write it toclient.transport_caat job start. - Pick a short TTL on the service-account identity token so a leaked token does limited damage.
- Keep CI service accounts in dedicated Cedar groups (e.g.
ci-migrations) so the policy can scope their reach explicitly.
Observability and SIEM¶
gdsgate writes two streams:
- Structured logs to
stderr, intracingformat (filterable withRUST_LOG). - Hash-chained audit records to Auth's state store, exportable as canonical JSON, Splunk HEC, or CEF / syslog.
Ship the structured logs to your normal log pipeline (journald, container log driver, Loki) and export the audit log to a SIEM that verifies the chain. See Operations.
Backend kinds — what plugs in¶
A single Cedar policy speaks for every protocol the agent serves.
kind |
What the agent does | Cedar action | Native client |
|---|---|---|---|
ssh (model A) |
Terminates and records the SSH session | sshConnect, plus sshForward* and mintOnwardSshCert for model B |
ssh, sftp, scp |
ssh (model B) |
Forwards the session to a downstream sshd with an OpenSSH cert from Auth |
same | ssh |
postgres |
Forwards the wire to addr, taps the query log |
dbConnect |
psql, pgbench, any libpq client |
mysql |
Forwards the wire to addr, taps the query log |
dbConnect |
mysql, mariadb, any MySQL client |
kubernetes |
Reverse-proxies the API with identity impersonation | k8sAccess |
kubectl, helm, kustomize |
tcp |
Raw byte forward | tcpConnect |
redis-cli, curl, anything plaintext |
mcp |
JSON-RPC forward with tools/call allow-list |
tcpConnect (transport) + mcpCallTool (per call) |
any MCP client |
See Configuration → [agent] for every
field per kind.