Skip to main content

Overview

The kguardian Broker exposes a REST API for querying collected telemetry data. The CLI uses this API internally, but you can also integrate directly with it for custom workflows.

Base URL

For external access, use port-forwarding:

Authentication

The broker supports scoped bearer tokens. Auth is off by default. When it is on, every endpoint except /health and /metrics needs an Authorization: Bearer <token> header, and the token must carry the scope the endpoint requires. A missing or unknown token gets 401. A valid token without the required scope gets 403. supplychain is kept separate from ingest so that a compromised pod holding the controller’s token can’t post a forged clean scan result. The frontend’s read token stays on the server. The browser calls /api on the frontend, and the frontend’s proxy removes any Authorization header the browser sent and adds the read token. The proxy forwards only GET, HEAD and the seccomp export POST. It answers every other method with 405, and any path with %, .. or empty segments with 400, without forwarding either.
With auth on, anyone who can reach the frontend Service can read everything the broker holds, because the frontend adds the read token for them. The UI has no login of its own. Put SSO in front of the frontend, or restrict who can reach its Service with a NetworkPolicy (or both). Auth on the broker stops pods from writing to it or reading from it directly. It doesn’t protect the UI.

Enable it with the Helm chart

Create one Secret with a key per scope. The chart doesn’t generate tokens, so they stay stable across upgrades.
The chart mounts each key only where it’s needed: the controller gets ingest, the frontend and llm-bridge get read, and the broker gets all of them. The broker won’t start with the same token under two scopes. A Secret missing the read or ingest key keeps the pods in CreateContainerConfigError until you add it. supplychain.enabled=true refuses to render unless auth is on. To check it:
The CLI reads its token from KGUARDIAN_BROKER_TOKEN (or --broker-token-file):
Installed before scoped tokens existed, with a single token key? Set broker.auth.mode: shared to keep that key working. The shared token grants read and ingest, so by default the chart doesn’t give it to the frontend in shared mode, and the UI gets 401. Set frontend.brokerAuth.allowSharedToken: true to accept that (the proxy allowlist above still applies), or better, move to the scoped layout.

/metrics

/metrics stays open so Prometheus can scrape it without a token. It carries no pod names or IPs. The kguardian_seccomp_denials_total series, though, are labelled with workload_namespace, workload_kind and workload, which is enough to list the namespaces and workloads that hit seccomp denials. The bundled alerts need those labels, so they stay. Treat /metrics as sensitive and limit who can reach it with broker.networkPolicy.allowMetricsFrom.

Broker environment

Setting any of these turns auth on. Tokens are compared in constant time.
With auth off, the API is unauthenticated. Any pod that can reach the broker Service can read everything and write rows, including pod specs (peer identity), syscalls, mark_dead and seccomp node status. Turn auth on, or at least restrict access with the chart’s NetworkPolicy, a service mesh, or an API gateway.
For the broker’s current released version, see broker/VERSION — component versions evolve independently per the release strategy.

API Endpoints

Pods

Add and retrieve pod metadata

Traffic

Query network traffic data

Syscalls

Retrieve syscall observations

Services

Service IP to metadata mapping

Audit Verdicts

Query Would-Deny / Allow verdicts from the audit evaluator

Version

Running broker + chart versions, latest known releases, and update availability

Response Format

All responses are JSON with standard HTTP status codes:
  • 200 OK - Success
  • 400 Bad Request - Invalid parameters
  • 401 Unauthorized - Missing or invalid bearer token (only with auth on)
  • 403 Forbidden - Valid token without the scope this endpoint requires (only with auth on)
  • 404 Not Found - Resource not found
  • 503 Service Unavailable with Retry-After - The read budget shed the request, or Postgres cancelled the statement (statement or lock timeout, deadlock, serialization failure); retry after the number of seconds given
  • 500 Internal Server Error - Server error

Common Patterns

Pagination

The high-volume endpoints support a limit query parameter: /pod/traffic defaults to 5000 rows (clamped to [1, 20000], most-recent-first) and /audit/verdicts defaults to 100 (clamped to [1, 500]), both ordered newest-first with the primary key as a tiebreak for stable cursor-style traversal. Only /pod/traffic/{name} remains unbounded. The /pod/info and /svc/info endpoints return all rows but have stable ordering — see each page for the sort key; /pod/info?include_dead=false and /pod/namespaces are the small forms for callers that only need what runs now.

Filtering

/audit/verdicts supports server-side filtering by policy, namespace, verdict, and direction (index-backed; see the endpoint page for the full contract). The pod-name- and IP-scoped GETs already filter at the URL: prefer GET /pod/traffic/{name} over GET /pod/traffic + client-side filter on any non-trivial cluster.

Rate Limiting

No rate limiting is currently enforced at the broker. The audit forwarder bounds concurrent in-flight /evaluate calls via the AUDIT_INFLIGHT_PERMITS semaphore (default 16) and exposes the gauge as broker_audit_inflight_available on /metrics so operators can spot saturation.