Skip to content

User guide

This page is for a person or workload that already has a deployment supplied by an administrator. It takes one resource from trust to a native client, records the positive proof and the nearest refusal, and leaves a safe next step. The Quickstart is the shortest authority-1 to proxy-1 lab journey. Use the Admin guide to create that deployment.

The supported release is the version printed by the supplied binary. Record the output of gdsgate --version beside the deployment's compatibility decision. The examples below use the split lab topology: Client to Proxy, Proxy to Authority for decisions, Proxy to Connector for data, and Connector to lab-postgres. lab-read is the positive database fixture and lab-denied is visible but denied. The fixture also names authority-1, proxy-1, connector-1, and alice@example.test.

Prerequisites

Reader: an end user or workload owner. The deployment administrator supplies a Linux x86_64 statically linked musl binary, the Proxy address, the transport CA fingerprint, the client configuration location, and the identity-provider instructions. No public download or hosted console is assumed.

Set shell variables on the client host. Values are supplied by the deployment owner, not guessed from this page:

: "${PROXY_ADDR:?set the administrator-supplied Proxy address}"
: "${PROXY_FINGERPRINT:?set the published transport CA fingerprint}"
: "${CLIENT_CONFIG:?set a client configuration path}"
SSH_FRAGMENT="${SSH_FRAGMENT:-./gdsgate-ssh-fragment.conf}"
SSH_CONFIG="${SSH_CONFIG:-$SSH_FRAGMENT}"

The default SSH paths use the generated fragment directly with ssh -F. If the deployment instead includes that fragment from another owner-controlled SSH configuration, set SSH_CONFIG to that configuration before continuing.

Keep the private key, identity cache, and any provider token on this host. Do not paste a token into a command argument or commit a generated file.

0. Connect to the cluster

Actor: the end user on the client host. Prerequisites: the variables above and the fingerprint verified out of band. Action:

gdsgate connect "$PROXY_ADDR" \
  --fingerprint "$PROXY_FINGERPRINT" \
  --output "$CLIENT_CONFIG"

Expected result: the command writes the client settings and transport trust anchor and exits successfully. It does not authenticate the user. A repeat with an existing file is refused unless --force is explicit.

Positive verification:

test -s "$CLIENT_CONFIG"
gdsgate --config "$CLIENT_CONFIG" doctor

Nearest negative test: omit --fingerprint in a non-interactive shell. The command must refuse first contact instead of trusting the answer. If the fingerprint differs, stop, remove only the untrusted output, and ask the owner to publish the correct value. If the Proxy is unavailable, fix the route or endpoint and repeat the same trust check. The --insecure option is for a development process on the same host only; it removes encryption and peer verification and is not a recovery for a network deployment.

Security boundary: connect establishes server trust, not user identity. The fingerprint is the evidence that did not originate in the exchange. Cleanup: retain the trust anchor with its deployment record; remove it only when the owner has rotated the CA and supplied a replacement. Next: sign in.

1. Sign in

Actor: a human using the client host, or a workload owner choosing a workload identity. Human action:

gdsgate --config "$CLIENT_CONFIG" login

Expected result: the default device flow prints a short verification location and a one-time code. Approve the request with the identity provider, then the client stores the resulting identity for this cluster. On a desktop, use gdsgate --config "$CLIENT_CONFIG" login --browser for the Authorization Code with PKCE loopback flow.

Positive verification:

gdsgate --config "$CLIENT_CONFIG" ls

The command returns the resources visible to the signed-in principal. The nearest negative is a token with no permitted group: login can succeed while ls is empty and a connection is denied. That is a policy result, not proof that the Proxy is down. Ask the policy owner to inspect view and connect separately. For a workload, use workload identity and its short-lived certificate instead of placing a human token in a job.

Security boundary: identity-provider claims become the principal and groups; Cedar policy remains the authority for each action. Cleanup: let the token or certificate expire and remove the local cache when retiring this client. Next: list resources.

2. List what you can reach

Actor: the signed-in principal on the client host. Action:

gdsgate --config "$CLIENT_CONFIG" ls

Expected result: one row per catalog resource for which view is allowed, including its kind, environment, labels, and address information. A resource can be connectable but omitted when policy grants connect without view. Use the kind filters when the next native client needs one protocol:

gdsgate --config "$CLIENT_CONFIG" db ls
gdsgate --config "$CLIENT_CONFIG" kube ls
gdsgate --config "$CLIENT_CONFIG" tcp ls
gdsgate --config "$CLIENT_CONFIG" mcp ls

Positive verification in the split lab is a visible lab-read row and a visible lab-denied row. The nearest negative is an empty list after login: check the identity, endpoint, and view policy before changing a connector. Catalog resolution happens before policy evaluation, so a misspelled resource is not a policy denial. Cleanup: no files are changed. Next: choose an explicit relay below, or start the Resident client.

Choose the access shape before continuing:

Need Use
One task, a script, or the clearest failure boundary the explicit SSH, database, Kubernetes, TCP, MCP, model, or web command below
Repeated native-client use under one user account Resident basic or direct, after reviewing its generated state
An application that cannot be pointed at a loopback relay Resident transparent, only with host-owner approval and a non-overlapping address pool
A shared host, server, container, or non-interactive service an explicit command or reviewed workload/service identity; do not leave a human Resident identity behind

Start with one explicit command. Adopt Resident only after the native request, denial, cleanup, and ownership boundary are understood.

3. SSH

Actor: a user on the client host. Supported topology: a catalogued ssh resource served by connector-1 or an equivalent Connector. Command host: the client host. Generate a dedicated native-client fragment:

gdsgate --config "$CLIENT_CONFIG" ssh-config '*.gds' > "$SSH_FRAGMENT"

The default SSH_CONFIG above points directly at this generated fragment. To use an existing SSH configuration instead, include the fragment before its matching host entries and set SSH_CONFIG to that configuration. The generated fragment carries a ProxyCommand, the chosen client config, and the gdsgate host-key boundary. Do not append a second generated fragment.

Expected result: the native command opens a session and the Authority audit contains a connect decision and a session close when it ends:

ssh -F "$SSH_CONFIG" user@RESOURCE_NAME

Positive verification is the remote prompt or command result plus the session row visible to an authorized audit reader. The nearest negative is a Cedar denial on SshHost::"RESOURCE_NAME"; no downstream SSH connection is made. If the denial is curable, run the named gdsgate step-up RESOURCE_NAME or gdsgate request-access RESOURCE_NAME --reason 'ticket-1234', then retry. If it is not curable, ask the policy owner. A changed host key is a separate native host-key failure and must be checked against the owner, not bypassed with a broad trust setting.

Interactive shell

Input is the normal SSH command. Expected result: an interactive PTY, resize, and interrupt work while the session remains open. Proof is the session ID and close row. A refusal before the prompt is either the connect policy or native host-key verification. Recover by checking each layer separately. Cleanup is exit; the connector closes the session and emits its final audit event.

Running a command

ssh -F "$SSH_CONFIG" user@RESOURCE_NAME -- command arg

The exact command is sent to the selected host. Positive proof is its exit status and the recorded session. A command that is denied inside a policy-aware downstream path must not be described as an SSH connect denial. Re-run only after correcting the command or its policy. Cleanup is automatic on process exit.

-L: local port forward

Prerequisite: policy must grant sshForwardLocal and the resource's forward allow-list must contain the requested destination. Action:

ssh -F "$SSH_CONFIG" -L 127.0.0.1:LOCAL_PORT:DEST_HOST:DEST_PORT user@RESOURCE_NAME

Expected result: the local listener opens only after the session decision and the requested destination is permitted. Positive proof is the listener and its audit event. The nearest negative is a policy or allow-list denial before any forward bytes reach the Connector. Remove the listener by ending SSH; do not leave a background process with an inherited grant.

-A: agent forwarding

Prerequisite: the backend must set allow_agent_forward = true and policy must grant sshForwardAgent. Both are off by default, and neither connect nor sshForwardLocal implies them. Action:

ssh -F "$SSH_CONFIG" -A user@RESOURCE_NAME

Expected result: the session's programs see SSH_AUTH_SOCK and sign with the client's keys through it. Positive proof is that variable inside the session and the sshForwardAgent audit event. The nearest negative is a refusal, where the Connector creates no socket and the variable is absent from the session's environment. Weigh it before granting: while the session lives, anything that reaches the socket authenticates as you wherever your keys are trusted. That is the shell, what it starts, and root on the Connector host.

-R: remote port forward

The actor and prerequisites are the same, with sshForwardRemote and the remote bind allow-list. Use an explicit loopback bind when the remote service must not be exposed to that host's network:

ssh -F "$SSH_CONFIG" -R 127.0.0.1:REMOTE_PORT:DEST_HOST:DEST_PORT user@RESOURCE_NAME

Expected result and evidence are the remote listener plus the audited forward. The nearest negative is a denied remote bind. Recovery is a narrower bind or a policy request. Cleanup is ending SSH and confirming the remote listener is gone.

SFTP

Use the same generated fragment:

sftp -F "$SSH_CONFIG" user@RESOURCE_NAME

The actor owns the files and the command host is the client. Positive proof is the transfer result and the session close. The nearest negative is an SSH connect denial or a downstream file permission error. Keep the two errors distinct, and close the SFTP session when the transfer finishes.

Agent forwarding (-A)

Agent forwarding extends the native SSH trust boundary to the remote host. Use it only when policy and the resource owner explicitly permit it:

ssh -F "$SSH_CONFIG" -A user@RESOURCE_NAME

The security consequence is that a process on the remote host can ask the forwarded agent to sign while the session is open. The nearest negative is the forward policy refusing the channel. Prefer a short-lived, purpose-specific credential, then close the session and remove any agent socket reference.

Next: database relay, or use the Resident client when native names and generated files are needed for several resources.

4. Databases (PostgreSQL / MySQL)

Actor: a database user on the client host. Supported kinds are postgres, mysql, and the Connector backend cockroach when the catalog advertises its PostgreSQL wire resource as postgres. The command host is the client. Start a loopback relay and point the native client at the printed local port:

gdsgate --config "$CLIENT_CONFIG" db proxy lab-read --listen 127.0.0.1:5433 &
DB_PID=$!
trap 'kill "$DB_PID" 2>/dev/null || true' EXIT
psql -h 127.0.0.1 -p 5433 -c 'select count(*) from lab_table;'

Expected result in the split lab is count 3. The Proxy makes the connect decision; the Connector may make a per-statement dbQuery decision when the backend is configured for it. Positive evidence is the query result and the corresponding session/query audit rows. The nearest negative is:

gdsgate --config "$CLIENT_CONFIG" --no-remediate \
  db proxy lab-denied --listen 127.0.0.1:5434

Expected result: a policy denial naming Database::"lab-denied", with no backend connection. A direct connection to the fixture backend must fail at the network boundary, not be used as an alternative authorization test. Recovery: ask for the typed connect or dbQuery grant, or run the named step-up and retry. Cleanup: stop the relay and remove its trap; do not preserve a database password in a shell history or generated config.

Next: Kubernetes or policy database patterns.

5. Kubernetes

Actor: a cluster operator on the client host. Supported version: use the Kubernetes client version pinned by the deployment owner and record it with gdsgate --version; the generated exec credential and per-request path are version-sensitive. A Connector backend of kind kubernetes is required.

Create the local proxy and kubeconfig for the selected catalog resource. Keep the generated credential short-lived and local:

KUBECONFIG="${KUBECONFIG:-./gdsgate-kubeconfig.yaml}"
gdsgate --config "$CLIENT_CONFIG" kube login KUBE_RESOURCE > "$KUBECONFIG"
gdsgate --config "$CLIENT_CONFIG" kube proxy KUBE_RESOURCE --listen 127.0.0.1:6443 &
KUBE_PID=$!
trap 'kill "$KUBE_PID" 2>/dev/null || true' EXIT
kubectl --kubeconfig "$KUBECONFIG" get --raw=/version

Expected result: the exec plugin obtains a short-lived credential and the request reaches the intended API through the local listener. Every API request is evaluated as kubeRequest, narrowed by verb, resource kind, namespace, name, subresource, and the policy marker. Positive evidence is the response, the request decision, and the session close/audit row where a session is held.

The nearest negative is a request with an unapproved verb or namespace. It returns 403 before the backend request. Port-forward is refused unless the backend sets allow_port_forward; when enabled it is an opaque audited byte channel and not a replayable typed request. exec and attach have their own upgrade and recording limits. Recovery is a narrower request or a policy step-up, not a broad cluster grant. Cleanup: stop the proxy, delete temporary kubeconfig files, and let generated credentials expire. Next: TCP and web.

6. TCP, Redis, web

Actor: a user on the client host. A tcp backend is an opaque byte relay, not an assertion that gdsgate can inspect its protocol. Start it on loopback:

gdsgate --config "$CLIENT_CONFIG" tcp proxy RESOURCE_NAME --listen 127.0.0.1:6390 &
TCP_PID=$!
trap 'kill "$TCP_PID" 2>/dev/null || true' EXIT
redis-cli -p 6390 ping

Expected result: the native client receives its normal response and the audit records the connect and byte counts. The nearest negative is a connect denial, which must occur before a downstream dial. Recovery is a typed policy grant or a corrected resource ID. Cleanup is stopping the relay.

The web kind is a named upstream application and the web-egress kind is a separate policy-controlled forward/CONNECT lane. Do not substitute one for the other. Next: MCP.

7. MCP servers

Actor: an MCP client owner on the client host. Start the proxy:

gdsgate --config "$CLIENT_CONFIG" mcp proxy MCP_RESOURCE --listen 127.0.0.1:8765 &
MCP_PID=$!
trap 'kill "$MCP_PID" 2>/dev/null || true' EXIT
gdsgate mcp bridge 127.0.0.1:8765

Expected result: tools/list contains only the tools visible to the principal, and an allowed tools/call, resources/read, or prompts/get reaches the server. Static allowed_tools remains available; Cedar per-tool enforcement is enabled only when the backend sets enforce_tool_policy. Positive evidence is the JSON-RPC result and mcpCallTool, mcpReadResource, or mcpGetPrompt audit row. The nearest negative is a denied tool, resource, or prompt. It must return a JSON-RPC error before the backend is called. Recovery is a narrower policy change, an allowed tool name, or a step-up. Cleanup: stop the proxy and remove client-specific endpoint files.

Security boundary: listing visibility and invocation are separate decisions; seeing a server does not grant every tool. Next: model services.

8. Model services

Actor: a model client or delegated agent owner. A catalogued llm resource is not a session relay: the Connector reads the model name from each HTTP request body and evaluates llmCall for each call. The gateway-held credential, if the backend uses substitution, never enters the client or sandbox.

Positive action is an allowed model call through the configured gateway. Proof is the response, model/token counters, and the llmCall audit row. The nearest negative is an unlisted model or a revoked delegation; the call is refused before it leaves the Connector. Recovery is a policy grant to the exact model, or a new short-lived delegation. Cleanup is revocation or expiry. See AI agents for the containment decision table and model policy for typed rules.

9. Web applications

Actor: a browser or HTTP client on the client host. For a named web resource, start the local proxy and use the printed address:

gdsgate --config "$CLIENT_CONFIG" web proxy WEB_RESOURCE --listen 127.0.0.1:0

Expected result: the proxy prints a loopback address and an allowed route returns the application response. A route denial is an HTTP 403 from the gateway; an application 403 proves only that the upstream application denied the request. Positive evidence is the response and the httpRequest audit row. The nearest negative is an unauthorized path or method. Recovery is a typed route policy change or step-up. Cleanup is stopping the proxy and closing the browser session.

Reaching the outside through a web-egress resource

web-egress is not a named application. The client sends a policy-controlled forward request; a DNS answer is dialled only where the address is a host on the public internet, so private, loopback, link-local, and metadata targets are refused before the egress connection, and so is any other range set aside for a purpose. A range the network genuinely routes is named in routed_ranges. Positive proof is an allowed external response and an egress audit row. The nearest negative is a private or metadata address and must fail closed. Recovery is a permitted destination approved by the network owner. Cleanup is stopping the relay; never copy a provider credential into the request body.

Reaching an application from a browser with nothing installed

This is an administrator-provided hosted route, if the deployment exposes one. The user must receive its exact origin and trust instructions out of band. Do not invent a public console name or URL. Expected result is the same route decision and audit row as the local proxy. A missing or expired browser identity is the nearest negative; use the provider login and retry. Cleanup is sign-out and expiry according to the deployment owner.

Reaching an application by its own name

The Resident client can intercept a catalogued native_name only when the user also opts into that whole name in [client].intercept_names. Both facts are required. Positive proof is the browser's original name and a matching route audit row. The nearest negative is a name not in the local opt-in or catalog, which must resolve normally rather than being hijacked. Recover by checking the two lists, then stop the Resident client to remove interception. See Resident client.

10. Just-in-time access

Actor: a user who has a reason but no standing action. Prerequisite: the denied target action offers an approval remedy and the deployment has an approver path. Creating the request is not a separate Cedar action; approval is gated by approveRequest. Request on the client host:

gdsgate --config "$CLIENT_CONFIG" request-access RESOURCE_NAME \
  --action connect --reason 'ticket or task identifier' --ttl 900
gdsgate --config "$CLIENT_CONFIG" requests

Expected result: a queued request with an ID. An approver runs gdsgate approve REQUEST_ID through an authorized route. Positive proof is the approval audit event and the subsequent connect. The nearest negative is a request denied by policy or an expired TTL. Recovery is a new, narrower request; an old request must not be reused. Cleanup is expiry and session termination. See policy JIT patterns.

11. Multi-factor (MFA) and step-up

Login freshness and a one-time gateway step-up are different channels. The identity provider establishes the login claim; gdsgate step-up RESOURCE_NAME establishes a grant bound to one action and resource:

gdsgate --config "$CLIENT_CONFIG" step-up RESOURCE_NAME --action connect

Use --code only when the deployment enrolled a local TOTP factor. The default passkey flow opens the browser. Expected result: the next matching request is allowed once. Positive evidence is the successful request and its step-up audit row. The nearest negative is a second identical request, which is denied because the grant was spent. Recovery is a fresh step-up with the same narrow scope. Cleanup is expiry; there is no reusable credential to archive. Next: sessions.

12. Managing your sessions

Actor: a principal authorized to view or terminate sessions. On the client host:

gdsgate --config "$CLIENT_CONFIG" session list
gdsgate --config "$CLIENT_CONFIG" session kill SESSION_ID

Expected result: session list shows only sessions policy permits you to see; session kill ends the selected one and records the action. Positive evidence is the close event and the downstream connection ending. The nearest negative is a session outside your killSession scope, which is denied without touching it. Recovery is to choose an ID from the current list, not a stale log. Cleanup is automatic when the session exits. For audit verification, use What the audit log captures.

13. Delegating access to an agent

Use the AI agents page for the threat model, model channel, and sandbox boundary. The human actor creates the narrow grant on the client host:

gdsgate --config "$CLIENT_CONFIG" delegate \
  --can mcp:search@tools-dev \
  --can llm:call@models-dev \
  --ttl 900 --sandbox strict --model gateway \
  --agent-profile PROFILE_NAME \
  --exec ./agent-wrapper -- --single-search-and-single-model-call

Run gdsgate delegate --list-agent-profiles to discover the profiles this installation ships and the source and review date for each one. The profile name must be verified in the local configuration and its external documentation review record. Expected result: the child receives only the agent-bound capability while it runs; the grant is revoked when it exits. Positive evidence is delegation.create, sandbox.claim, the allowed tool and model rows, and a denial after revocation. The nearest negative is an unlisted tool or model, or a direct model channel under a sandbox, which must be refused before launch. Cleanup is automatic for --exec; a --bind-key grant requires an explicit revoke and removal of its mode-0600 directory.

What the audit log captures

The Authority audit chain separates authentication, policy decisions, session activity, delegation, and administrative events. A positive row names the principal, resource kind, action, outcome, and session or request identifier where the lane supplies one. A refusal row names the nearest boundary and must not be treated as evidence that a backend was contacted. Authorized operators verify the chain off-band from a separate workstation whose configuration opens the audit store directly and names the anchor key:

gdsgate --config "$AUDIT_VERIFY_CONFIG" authority verify-audit

Expected result is a chain and anchor verification summary. The audit is not a secret store: tokens, private keys, passwords, and prompt bodies are not a substitute for a credential vault. See Operations for the exhaustive event and export reference owned by the operations documentation.

Troubleshooting

Check layers in this order: binary version, client trust, identity, catalog visibility, policy action, local relay, then backend. Keep the nearest failure message and its request ID when asking an administrator for help.

Symptom Evidence to collect Safe recovery
First contact refuses published fingerprint and offered fingerprint stop and ask the deployment owner to reconcile them
Login succeeds but ls is empty principal subject, groups, and endpoint ask for view on the intended typed resource
connect is denied resource kind, action, request ID use the named step-up/JIT path or ask for policy review
Local relay opens but native client fails relay output and native client error check local port, generated config, and host-key/TLS trust separately
Kubernetes request is 403 verb, kind, namespace, name, subresource request one typed kubeRequest, not cluster-wide access
MCP tool is absent tools/list output and tool name check allowed_tools, enforce_tool_policy, and viewTools
Agent loses access after exit delegation ID and close event expected for --exec; revoke and clean a bind-key bundle if one remains

Never work around a denial by dialing a backend directly. If the source or deployment does not identify a supported version or endpoint, record that ambiguity and ask the owner; do not fill it with a public URL or credential.