From d780b16e894e2dbf66b53cf885ee534d2ff1fd80 Mon Sep 17 00:00:00 2001 From: Asish Kumar Date: Mon, 27 Apr 2026 11:52:07 +0530 Subject: [PATCH 1/7] docs(k8s-proxy): add Kubernetes Proxy REST API guide Adds versioned_docs/version-4.0.0/running-keploy/k8s-proxy-api.md, a full REST API guide for the keploy/k8s-proxy service in the v4 docs. Mirrors running-keploy/public-api.md: authentication, response format, quickstart, endpoint reference, and related guides. Covers the control-plane surface exposed behind a cluster-wide shared bearer token: recording start/stop/status, replay, reports, schema coverage, auto-replay config, ATG sandbox routes, /k8s-proxy/* data routes, and proxy self-update. Calls out the unique benefits versus running the enterprise CLI directly (zero-touch webhook injection, one API per Deployment, namespace scoping, durable session/log state, self-updating image, static dedup at the edge). Authentication section explains that the token is generated at proxy Pod startup via crypto/rand, reported to the api-server through the heartbeat channel, and retrieved by callers via the api-server route GET /cluster/getApp (or /cluster/getApps). The shared token is not sourced from a Helm Secret or env var, and it rotates on every Pod restart, so programmatic callers must re-fetch it before each run. This commit replaces the earlier draft of this file from the original PR #838 commits, which described a DaemonSet capture mode and a RecordingSession custom resource that do not exist in the keploy/ k8s-proxy code, plus a /k8s-proxy/mode route, a /k8s-proxy/apps/ensure route, and a Helm-based shared-token Secret recipe that the chart does not provision. Also adds the page to the v4 API Reference sidebar and extends the Vale base vocabulary with the domain terms used in the new guide. Signed-off-by: Asish Kumar --- .../config/vocabularies/Base/accept.txt | 9 + .../running-keploy/k8s-proxy-api.md | 470 ++++++++++++++++++ .../version-4.0.0-sidebars.json | 3 +- 3 files changed, 481 insertions(+), 1 deletion(-) create mode 100644 versioned_docs/version-4.0.0/running-keploy/k8s-proxy-api.md diff --git a/vale_styles/config/vocabularies/Base/accept.txt b/vale_styles/config/vocabularies/Base/accept.txt index d6fd38645..5cd91cb23 100644 --- a/vale_styles/config/vocabularies/Base/accept.txt +++ b/vale_styles/config/vocabularies/Base/accept.txt @@ -106,10 +106,19 @@ shipping_address_id [Ll]inux [Ee]nv [Kk]8s +IPs [Dd]edup +[Dd]edups +[Rr]ollout[s]? +[Pp]refill[s]? +[Aa]uditable +[Cc]ooldown +[Ll]iveness [Cc]ron [Tt]oolchain [Rr]untime[s]? +MongoIDs +initialised normalisation behaviour polyglot diff --git a/versioned_docs/version-4.0.0/running-keploy/k8s-proxy-api.md b/versioned_docs/version-4.0.0/running-keploy/k8s-proxy-api.md new file mode 100644 index 000000000..e6b7f11cc --- /dev/null +++ b/versioned_docs/version-4.0.0/running-keploy/k8s-proxy-api.md @@ -0,0 +1,470 @@ +--- +id: k8s-proxy-api +title: Kubernetes Proxy REST API +sidebar_label: Kubernetes Proxy REST API +description: Use the Keploy Kubernetes Proxy REST API to trigger recordings, manage recording and auto-replay configs, stream session status, run replays, and drive the enterprise recording flow programmatically from CI/CD, internal tooling, or AI agents. +tags: + - kubernetes + - k8s proxy + - REST API + - recording + - automation + - enterprise + - CI/CD +keywords: + - k8s proxy + - kubernetes proxy + - keploy enterprise + - recording API + - live recording + - auto replay + - programmatic recording + - shared token +--- + +import ProductTier from '@site/src/components/ProductTier'; + + + +The **Keploy Kubernetes Proxy** runs as an in-cluster service that drives recording, replay, and observability for Deployments in one or more namespaces. Its REST API has two groups of routes: + +- **Operational routes** such as `/record/start`, `/record/status`, `/test/start`, `/deployments`, and `/proxy/update`. These are the routes used to control live in-cluster recording and replay. +- **API-server-compatible data routes** under `/k8s-proxy/*`. The Console and CLI use these paths for stored test cases, mocks, reports, schema, schema coverage, and saved configs. In SaaS mode these paths are served by the API server. In self-hosted mode the proxy can serve the same paths directly. + +Use this API when you want to script the same Kubernetes live-recording flow the Keploy Console drives from CI/CD pipelines, operators, or internal tooling without running the `keploy` CLI on each node. + +**Base URL:** `https://` - the externally reachable address configured as `ingressUrl` when you installed the `k8s-proxy` Helm chart. In-cluster callers can use `https://..svc:8080` by default, or `http://..svc:8081` when `proxy.insecure.enabled=true`. + +--- + +## Why the Kubernetes Proxy instead of `keploy enterprise` directly? + +Running the Keploy enterprise CLI inside a Pod works, but it is a per-app, per-node model: each Deployment you want to record needs its own sidecar plumbing, image rebuild, or pod restart. The Kubernetes Proxy removes that friction: + +- **Zero-touch agent setup.** The proxy registers a `MutatingAdmissionWebhook` (`/mutate`) so the Keploy recording agent is injected into target Pods on the next rollout. No image rebuild, sidecar template change, or per-app config knob is required. +- **One API for every Deployment.** A single shared-token-authenticated endpoint starts or stops recording for any Deployment in the watched scope. `podsCount` controls how many pods are recorded and is capped by the Deployment replicas or HPA max replicas. +- **Cluster-wide or namespace-scoped.** Install once per cluster, or set `watchNamespace` to pin the proxy to a single team's namespace. Cross-namespace calls are rejected with `403`. +- **Stored session outputs.** Recording, replay, and schema-coverage outputs are persisted through the configured platform storage. Per-session and proxy logs are available through the log endpoints when log retention/support-bundle storage is enabled. +- **Auto-replay loop.** A recording session can kick off an auto-replay on a cadence (`autoReplayInterval`) against freshly recorded test sets, giving you self-validating live traffic without a separate pipeline. +- **Self-updating.** The proxy can roll itself (and the injected agent) forward via `POST /proxy/update`, so upgrades do not require kubectl or a GitOps round-trip—unless you _want_ GitOps to stay authoritative (the proxy detects and reports reverts). +- **Static deduplication at the edge.** Enable `static_dedup` in the recording config to drop schema-identical traffic _before_ it is ever written as a test case. See [Static Deduplication](/docs/keploy-cloud/static-deduplication/). + +If you only need to script a single app outside Kubernetes, the [Public REST API](/docs/running-keploy/public-api/) (`api.keploy.io/client/v1`) is the better fit. The Kubernetes Proxy API is specifically the _live-recording_ control plane. + +--- + +## Authentication + +Every protected proxy endpoint requires the cluster **shared token**. Send it as a Bearer token: + +```text +Authorization: Bearer +``` + +Only `GET /healthz` and the admission webhook `POST /mutate` are unauthenticated. Every other route rejects missing or malformed headers with `401 Unauthorized`. + +```bash +# Verify the proxy is up (no auth required) +curl -sf https://$PROXY/healthz +# {"status":"ok"} +``` + +### How the token is provisioned + +The proxy generates a 32-byte random value (`crypto/rand`, hex-encoded) on every Pod start and reports it to the Keploy API server in its first heartbeat. The token is **not** sourced from a Helm value, ConfigMap, or Secret, and it rotates whenever the Pod restarts. There is nothing to commit in GitOps and nothing to read out of `kubectl get secret`. + +### Retrieve the token + +Authenticated callers fetch the current token from the Keploy API server, which mirrors the latest heartbeat from each cluster. Log in once to obtain a user JWT, then look up the proxy app for the Deployment you want to drive: + +```bash +API_SERVER="https://api.keploy.io" # or your self-hosted api-server URL +NS="default" +DEPLOY="orders-api" +CLUSTER="prod-use1" + +# 1. Authenticate as a Keploy user (admin, user, or cicd role) +JWT=$(curl -s -X POST "$API_SERVER/login" \ + -H "Content-Type: application/json" \ + -d '{"email":"you@example.com","password":"..."}' | jq -r '.token') + +# 2. Look up the proxy app for this Deployment and read its sharedToken +K8S_PROXY_SHARED_TOKEN=$(curl -s -H "Authorization: Bearer $JWT" \ + "$API_SERVER/cluster/getApp?namespace=$NS&deployment=$DEPLOY&clusterName=$CLUSTER" \ + | jq -r '.sharedToken') + +AUTH="Authorization: Bearer $K8S_PROXY_SHARED_TOKEN" +``` + +`GET /cluster/getApps` returns the same `sharedToken` field for every proxy-managed app in your organization in a single response, which is convenient when you want to script across many Deployments at once. + +> The proxy shared token is cluster-wide, not per-user. The API server still uses normal user JWT/cookie authentication on its own routes (including `/cluster/getApp`). Programmatic callers should re-fetch the shared token on each run, since it changes whenever the proxy Pod restarts. + +--- + +## Response format + +Handlers return JSON with `application/json` on success. Validation failures usually return `{"error": "..."}` with a 4xx status; shared-token auth failures return `{"success": false, "message": "Unauthorized: ..."}`. A handful of endpoints stream newline-delimited JSON instead - they are called out explicitly below. + +```js +// Successful record start (200) +{ "record": "started", "id": "default-orders-api" } + +// Validation error (400) +{ "error": "namespace and deployment are required" } + +// Auth error (401) +{ "success": false, "message": "Unauthorized: Missing authorization header" } + +// Namespace-scoped proxy rejecting a cross-namespace call (403) +{ "error": "this proxy is scoped to namespace \"payments\"" } +``` + +### Error status codes + +| HTTP | When it happens | +| ---- | ----------------------------------------------------------------------------------------------- | +| 400 | Missing or malformed request body, missing required fields | +| 401 | Missing or invalid `Authorization: Bearer` header | +| 403 | Request touches a namespace outside `watchNamespace`, or image repo mismatch on `/proxy/update` | +| 404 | Recording/replay session ID not found, or deployment/config does not exist | +| 405 | Wrong HTTP method for the route | +| 500 | Kubernetes API error, storage backend unavailable, or unexpected server error | +| 503 | Kubernetes client or self-discovery not initialised (proxy is still starting or missing RBAC) | + +--- + +## Quick start: Trigger and watch a live recording + +The golden path: pick a Deployment, start a recording, stream its status, and stop it when you have the traffic you need. + +### 1. Set up variables + +```bash +PROXY="https://k8s-proxy.example.com" # ingressUrl from Helm install +AUTH="Authorization: Bearer $K8S_PROXY_SHARED_TOKEN" +NS="default" +DEPLOY="orders-api" +``` + +### 2. Discover target Deployments + +```bash +curl -s -H "$AUTH" "$PROXY/deployments?namespace=$NS" | jq +# [{"name":"orders-api","namespace":"default","replicas":3,"readyReplicas":3}] +``` + +### 3. Start a recording + +```bash +RECORD_ID=$(curl -s -X POST "$PROXY/record/start" \ + -H "$AUTH" -H "Content-Type: application/json" \ + -d '{ + "namespace": "'"$NS"'", + "deployment": "'"$DEPLOY"'", + "podsCount": 3, + "clusterId": "prod-use1", + "record_config": { + "static_dedup": true, + "enable_sampling": 10, + "filters": [ + { "path": "/health", "urlMethods": ["GET"] } + ] + } + }' | jq -r '.id') + +echo "Recording started: $RECORD_ID" +``` + +On success the proxy registers the session before it touches the workload, ensures the mutating webhook configuration is present, copies the CA secret into the target namespace, creates the headless Service, and triggers a targeted restart of the selected pods so the agent is injected as they come back. + +### 4. Stream session status + +```bash +curl -N -H "$AUTH" "$PROXY/record/status?record_id=$RECORD_ID" +``` + +This returns newline-delimited JSON—one event per state change. Each line includes the current testcase count, endpoints seen, mock counts, and `static_dedup_stats` when static dedup is enabled. + +```json +{ + "test_cases_count": 12, + "endpoints": [ + { + "name": "test-1", + "endpoint": "/orders", + "method": "GET", + "status_code": 200 + } + ], + "mock_count": 8, + "mock_types": {"SQL": 3}, + "status": "running", + "pods_running": 3, + "static_dedup_stats": [], + "started_at": 1712345678 +} +``` + +### 5. Stop the session + +```bash +curl -s -X POST "$PROXY/record/stop" \ + -H "$AUTH" -H "Content-Type: application/json" \ + -d '{"record_id":"'"$RECORD_ID"'"}' +# {"record":"stopped","id":"default-orders-api"} +``` + +The proxy tears down the headless Service, unloads the agent on the next rollout, and flushes the recorded tests to the platform store so they show up under that app in the Keploy Console. + +--- + +## Recording configuration + +The `record_config` block in `POST /record/start` is a UI-friendly subset of the OSS `config.Record` struct and is persisted alongside the session so the UI can prefill it and so the exact inputs are auditable. + +| Field | Type | Description | +| --------------------- | ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | +| `filters` | `Filter[]` | Traffic patterns to filter during recording. Matches use AND semantics across fields. | +| `client_key` | `string` | Optional client identifier propagated to downstream mock capture (useful for multi-tenant apps). | +| `enable_sampling` | `uint` | If set to a positive value, sample 1-in-N matching requests. Omit or set `0` to use the proxy default. | +| `static_dedup` | `bool` | Drop schema-identical traffic in the agent before it becomes a test case. See [Static Deduplication](/docs/keploy-cloud/static-deduplication/). | +| `custom_dedup_fields` | `EndpointDedupFields[]` | Add value-aware fingerprints for matching endpoints. Providing this also enables static dedup for the injected sidecar. | +| `low_latency_mode` | `bool` | Start the agent in low-latency mode. | +| `debug` | `bool` | Start the injected agent with debug logs. | +| `memory_limit` | `string` | Memory request in MiB, expressed as a positive integer string. The container limit is set to twice this value. | +| `secret_protection` | `object` | Enable record-time secret detection/obfuscation with optional custom headers, body keys, URL params, and allow lists. | + +Each `Filter` accepts: + +| Field | Type | Description | +| -------------- | ------------------- | --------------------------------------- | +| `path` | `string` | Regex matched against the request path. | +| `host` | `string` | Hostname to match. | +| `port` | `uint` | Port to match. | +| `urlMethods` | `string[]` | HTTP methods (e.g. `["GET","POST"]`). | +| `headers` | `map[string]string` | Header key/value pairs to match. | +| `filterPolicy` | `string` | `exclude` (default) or `include`. | + +### Auto-replay configuration + +Attach an `auto_replay_config` to `POST /record/start` to automatically replay freshly recorded test sets against a standalone Pod the proxy provisions. Each replay runs in isolation against a fresh Pod + Service so it cannot disturb production traffic. + +| Field | Type | Description | +| -------------------- | ---------------------------- | ------------------------------------------------------------------- | +| `autoReplayInterval` | `int64` (minutes, default 5) | Cooldown between replays for the same session. | +| `mongoPassword` | `string` | Override for user-provided Mongo credentials used during replay. | +| `apiTimeout` | `uint64` (seconds) | Per-request timeout for the replayed application. | +| `delay` | `uint64` (seconds) | Initial delay before starting tests (lets the standalone Pod warm). | +| `globalNoise` | `object` | Fields to ignore during diffing. Accepts `global` and `test-sets`. | +| `envOverrides` | `map[string]string` | Env var overrides for the standalone replay Pod. | + +--- + +## Endpoint reference + +All paths are relative to the proxy base URL. Unless noted, every route requires `Authorization: Bearer `. + +### Health and admission + +| Method | Path | Auth | Description | +| ------ | ---------- | ---- | ------------------------------------------------------------------- | +| `GET` | `/healthz` | No | Liveness probe. Returns `{"status":"ok"}`. | +| `POST` | `/mutate` | No | Kubernetes MutatingAdmissionWebhook endpoint. Do not call directly. | + +### Deployments + +| Method | Path | Description | +| ------ | ----------------------------- | -------------------------------------------------------------------- | +| `GET` | `/deployments?namespace=` | List Deployments. Omit `namespace` for cluster-wide (unless scoped). | + +### Recording + +| Method | Path | Description | +| ------ | ------------------------------------------------------- | ----------------------------------------------------------------------------------------- | +| `POST` | `/record/start` | Start a recording session. Body: `RecordRequest`. See quickstart above. | +| `POST` | `/record/stop` | Stop a session. Body: `{"record_id":"..."}`. | +| `GET` | `/record/status?record_id=` | Stream session status (NDJSON). One line per state change. | +| `GET` | `/record/active?namespace=&deployment=` | Check whether a session is running for a Deployment. Returns `in_progress` + `record_id`. | +| `GET` | `/record/app-status?namespace=&deployment=` | Report agent-injection and Pod-readiness status for the target app. | +| `GET` | `/record/logs?namespace=&deployment=&...` | Tail recording-session logs. Accepts `stream`, `previous`, `tail_bytes`, `stream_bytes`. | +| `GET` | `/record/logs/check?namespace=&deployment=` | Cheap check: are session logs available? | +| `GET` | `/record/logs/download?namespace=&deployment=` | Download recording logs as a ZIP. | + +**`RecordRequest` body:** + +```json +{ + "namespace": "default", + "deployment": "orders-api", + "podsCount": 3, + "clusterId": "prod-use1", + "record_config": {"static_dedup": true, "enable_sampling": 10, "filters": []}, + "auto_replay_config": {"autoReplayInterval": 10, "delay": 5} +} +``` + +### Replay / Test + +| Method | Path | Description | +| ------ | ----------------------------------------------------- | ------------------------------------------------------------------ | +| `POST` | `/test/start` | Start a replay. Body: `ReplayRequest` with optional `test_config`. | +| `POST` | `/test/stop` | Stop a replay. Body: `{"replay_id":"..."}`. | +| `GET` | `/test/status?replay_id=` | Stream replay status and per-testcase results (NDJSON). | +| `GET` | `/test/active?namespace=&deployment=` | Check whether a replay is in progress for this Deployment. | +| `POST` | `/test/mock-metadata` | Extended mock metadata. | +| `POST` | `/test/normalize` | AI-normalize testcases in a run. | +| `GET` | `/test/download?...` | Download a full test bundle (ZIP). | +| `GET` | `/test/download/active?...` | Download tests from the currently active recording session. | +| `GET` | `/test/logs?namespace=&deployment=&...` | Tail replay logs. Same flags as `/record/logs`. | +| `GET` | `/test/logs/check?namespace=&deployment=` | Replay-logs availability check. | +| `GET` | `/test/logs/download?namespace=&deployment=` | Replay logs ZIP. | + +**`ReplayRequest` body:** + +```json +{ + "namespace": "default", + "deployment": "orders-api", + "test_config": { + "selectedTests": {"test-set-0": ["tc-1", "tc-2"]}, + "apiTimeout": 30, + "delay": 5, + "globalNoise": {"global": {"header": {"Date": []}}}, + "envOverrides": {"FEATURE_FLAG_X": "off"} + } +} +``` + +Omit `selectedTests` to replay every set. + +### API-server-compatible data routes + +These routes are all mounted under `/k8s-proxy`. They are served directly by the proxy in self-hosted mode and by the API server in SaaS mode. Direct proxy calls use the proxy shared token. API-server calls use normal Console/API-server authentication and role checks. + +#### Health + +| Method | Path | Description | +| ------ | ------------------- | -------------------------------------------------------- | +| `GET` | `/k8s-proxy/health` | Health check for the API-server-compatible data surface. | + +#### Test cases, mocks, and mappings + +| Method | Path | Description | +| -------- | --------------------------------------------------- | ---------------------------------------------- | +| `POST` | `/k8s-proxy/testcases` | Insert a testcase. | +| `POST` | `/k8s-proxy/testcases/bulk` | Insert multiple testcases. | +| `GET` | `/k8s-proxy/testcases` | Fetch testcases. | +| `GET` | `/k8s-proxy/testcases/detail` | Fetch one testcase payload. | +| `GET` | `/k8s-proxy/testcases/metadata` | Fetch testcase metadata. | +| `POST` | `/k8s-proxy/testcases/selective` | Fetch selected testcases. | +| `PUT` | `/k8s-proxy/testcases/{testCaseId}` | Update one testcase. | +| `PUT` | `/k8s-proxy/testcases/bulk` | Update multiple testcases. | +| `DELETE` | `/k8s-proxy/testcases` | Delete testcases. | +| `GET` | `/k8s-proxy/testcases/testsets` | List test set IDs. | +| `GET` | `/k8s-proxy/testcases/testsets/metadata` | List test set metadata. | +| `GET` | `/k8s-proxy/testcases/testsets/latest-release/full` | Fetch latest-release test sets with full data. | +| `DELETE` | `/k8s-proxy/testcases/testset` | Delete a test set. | +| `POST` | `/k8s-proxy/mocks/upload` | Upload mocks. | +| `GET` | `/k8s-proxy/mocks/download` | Download mocks. | +| `GET` | `/k8s-proxy/mocks/reference` | Fetch mock reference metadata. | +| `POST` | `/k8s-proxy/mocks/reference` | Insert or update mock reference metadata. | +| `DELETE` | `/k8s-proxy/mocks/reference` | Delete mock reference metadata. | +| `POST` | `/k8s-proxy/mappings` | Upload mappings. | +| `GET` | `/k8s-proxy/mappings` | Fetch mappings. | + +#### Reports and schema coverage + +| Method | Path | Description | +| -------- | -------------------------------------------- | ------------------------------------ | +| `POST` | `/k8s-proxy/insert/testCaseResult` | Insert testcase result data. | +| `GET` | `/k8s-proxy/get/testCaseResults` | Fetch testcase result data. | +| `DELETE` | `/k8s-proxy/clear/testCaseResults` | Clear testcase result data. | +| `POST` | `/k8s-proxy/insert/report` | Insert a test report. | +| `GET` | `/k8s-proxy/get/report` | Fetch one test report. | +| `GET` | `/k8s-proxy/get/allReports` | List stored reports. | +| `GET` | `/k8s-proxy/get/testRunIds` | List test run IDs. | +| `GET` | `/k8s-proxy/get/testRunReports` | Fetch test-run-level reports. | +| `GET` | `/k8s-proxy/get/testSetReports` | Fetch test-set-level reports. | +| `GET` | `/k8s-proxy/get/testCaseReports` | Fetch per-testcase reports. | +| `PUT` | `/k8s-proxy/update/report` | Update a report. | +| `POST` | `/k8s-proxy/report/multipart` | Upload a multipart test-run report. | +| `POST` | `/k8s-proxy/autoreplay-metrics` | Insert auto-replay metrics. | +| `GET` | `/k8s-proxy/autoreplay-metrics` | Fetch auto-replay metrics. | +| `POST` | `/k8s-proxy/insert/schema` | Insert captured OpenAPI schema. | +| `PUT` | `/k8s-proxy/update/schema` | Update captured OpenAPI schema. | +| `GET` | `/k8s-proxy/get/schema` | Fetch captured OpenAPI schema. | +| `GET` | `/k8s-proxy/get/schema-coverage` | Fetch per-endpoint schema coverage. | +| `POST` | `/k8s-proxy/schema-coverage-report` | Save a schema coverage report. | +| `GET` | `/k8s-proxy/get/schema-coverage-summary` | Fetch schema coverage summary. | +| `GET` | `/k8s-proxy/get/top-schema-coverage-summary` | Fetch top-N schema coverage summary. | + +#### Saved config + +| Method | Path | Description | +| ------ | --------------------------------------------------- | ---------------------------------------------------------------------- | +| `POST` | `/k8s-proxy/config` | Insert or update saved proxy config. | +| `GET` | `/k8s-proxy/config/{namespace}/{deployment}/{kind}` | Fetch saved config. `kind` can be `record`, `replay`, or `autoreplay`. | +| `GET` | `/k8s-proxy/config/list/{kind}` | List saved configs by kind. | + +### Assertion-test generator (ATG) + +| Method | Path | Description | +| ------ | ------------------------------- | ---------------------------------------------------------------------------------- | +| `POST` | `/agent/run/{jobID}` | Process an ATG job. Accepts optional `?timeout=` (default `30`). | +| `POST` | `/agent/execute-request` | Execute an HTTP request through the ATG runtime (used during assertion authoring). | +| `POST` | `/agent/service-url` | Resolve a Service URL inside the cluster (used to target the app from the UI). | +| `POST` | `/agent/recordATGSandbox` | Bind to an already-running ATG sandbox recording session. | +| `POST` | `/agent/stopATGSandboxRecord` | Stop an ATG sandbox recording session. | +| `POST` | `/agent/replayATGSandbox` | Start an ATG sandbox replay session. | +| `POST` | `/agent/stopATGSandboxReplay` | Stop an ATG sandbox replay session. | +| `GET` | `/agent/ATGSandboxRecordStatus` | Fetch ATG sandbox recording status. | +| `GET` | `/agent/ATGSandboxRecordLogs` | Fetch ATG sandbox recording logs. | +| `GET` | `/agent/ATGSandboxReplayLogs` | Fetch ATG sandbox replay logs. | +| `GET` | `/agent/autoReplayLogs` | Fetch auto-replay logs. | + +### Proxy self-management + +| Method | Path | Description | +| ------ | ----------------------------------------------- | ------------------------------------------------------------------------------------- | +| `POST` | `/proxy/update` | Roll the proxy (and optionally the injected agent image) to a new version. See below. | +| `GET` | `/proxy/update/status` | Current rollout state: `""`, `updating`, `desired_applied`, or `reverted_by_gitops`. | +| `POST` | `/proxy/shutdown` | Gracefully terminate the proxy Pod (Kubernetes will reschedule it). | +| `GET` | `/logs/proxy?...` | Tail proxy-pod logs. Same flags as session log endpoints. | +| `GET` | `/logs/proxy/download` | Download proxy logs as ZIP (current + previous container, when available). | +| `GET` | `/autoreplay/debug-bundles` | List captured auto-replay debug bundles. | +| `GET` | `/autoreplay/debug-bundles/{bundleID}` | Fetch one auto-replay debug bundle metadata record. | +| `GET` | `/autoreplay/debug-bundles/{bundleID}/download` | Download one auto-replay debug bundle. | +| `POST` | `/autoreplay/debug-bundles/{bundleID}/share` | Share one auto-replay debug bundle through the configured API server. | + +**`POST /proxy/update` body:** + +```json +{ + "proxy_image": "ghcr.io/keploy/k8s-proxy:v1.4.0", + "agent_image": "ghcr.io/keploy/keploy:v3.7.1" +} +``` + +The proxy validates that you are bumping the _same_ image repository (you cannot swap `ghcr.io/keploy/k8s-proxy` for an unknown registry) and then patches its own Deployment. If a GitOps controller (Argo CD, Flux) reverts the bump, `/proxy/update/status` reports `reverted_by_gitops` with guidance to update your Helm values or manifest repo instead. + +--- + +## Namespace scoping + +When the proxy is installed with `watchNamespace=`, every API call is force-scoped to that namespace: + +- `GET /deployments` ignores the `namespace` query and returns only that namespace. +- Any request whose `namespace` field does not match returns `403` with `{"error":"this proxy is scoped to namespace \"\""}`. + +Leave `watchNamespace` unset to run cluster-wide. Cluster-wide mode requires Deployment `get`/`list`/`watch` RBAC across all namespaces, which the default Helm chart provisions. + +--- + +## Related guides + +- [Static Deduplication](/docs/keploy-cloud/static-deduplication/)—drop duplicate traffic at record time using the `static_dedup` field. +- [Remove Duplicate Tests](/docs/keploy-cloud/deduplication/)—coverage-based dedup at replay time (`keploy dedup`). +- [Public REST API](/docs/running-keploy/public-api/)—Keploy Cloud control plane (apps, suites, jobs). +- [Kubernetes installation](/docs/keploy-cloud/kubernetes/)—install and configure the Kubernetes Proxy. +- [GitOps with Argo CD](/docs/keploy-cloud/gitops-argocd/)—manage the proxy via GitOps, including how `/proxy/update` interacts with reverts. diff --git a/versioned_sidebars/version-4.0.0-sidebars.json b/versioned_sidebars/version-4.0.0-sidebars.json index d5e7e313a..50eedd895 100644 --- a/versioned_sidebars/version-4.0.0-sidebars.json +++ b/versioned_sidebars/version-4.0.0-sidebars.json @@ -221,7 +221,8 @@ "label": "API Reference", "collapsed": false, "items": [ - "running-keploy/public-api" + "running-keploy/public-api", + "running-keploy/k8s-proxy-api" ] }, { From dd877be8054bd99764954733d8687b8787d9d05d Mon Sep 17 00:00:00 2001 From: Yash Khare Date: Mon, 27 Apr 2026 17:19:47 +0530 Subject: [PATCH 2/7] docs(k8s-proxy): add Sidecar/DaemonSet mode intro, drop self-hosted-only framing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The k8s-proxy guide implicitly assumed Sidecar mode and split the data routes by SaaS vs self-hosted. Two updates: 1. New "Recording modes" section right after the Base URL: state that the proxy supports Sidecar (default — agent injected via MutatingAdmissionWebhook) AND DaemonSet (eBPF capture from a per-node Pod, scoped by a RecordingSession CR, no application-Pod mutation, supports cluster-mode auto-replay). Both modes expose the same REST API documented here, so the rest of the guide stays correct without per-mode forks. 2. Drop "in SaaS mode … in self-hosted mode" framing on the data-route intro and the API_SERVER comment. The proxy serves /k8s-proxy/* directly in both deployment shapes; the SaaS/self-hosted split was adding noise without helping the reader pick a path. Signed-off-by: Yash Khare --- .../running-keploy/k8s-proxy-api.md | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/versioned_docs/version-4.0.0/running-keploy/k8s-proxy-api.md b/versioned_docs/version-4.0.0/running-keploy/k8s-proxy-api.md index e6b7f11cc..d2b196356 100644 --- a/versioned_docs/version-4.0.0/running-keploy/k8s-proxy-api.md +++ b/versioned_docs/version-4.0.0/running-keploy/k8s-proxy-api.md @@ -29,7 +29,7 @@ import ProductTier from '@site/src/components/ProductTier'; The **Keploy Kubernetes Proxy** runs as an in-cluster service that drives recording, replay, and observability for Deployments in one or more namespaces. Its REST API has two groups of routes: - **Operational routes** such as `/record/start`, `/record/status`, `/test/start`, `/deployments`, and `/proxy/update`. These are the routes used to control live in-cluster recording and replay. -- **API-server-compatible data routes** under `/k8s-proxy/*`. The Console and CLI use these paths for stored test cases, mocks, reports, schema, schema coverage, and saved configs. In SaaS mode these paths are served by the API server. In self-hosted mode the proxy can serve the same paths directly. +- **API-server-compatible data routes** under `/k8s-proxy/*`. The Console and CLI use these paths for stored test cases, mocks, reports, schema, schema coverage, and saved configs. The proxy can serve these paths directly. Use this API when you want to script the same Kubernetes live-recording flow the Keploy Console drives from CI/CD pipelines, operators, or internal tooling without running the `keploy` CLI on each node. @@ -37,6 +37,17 @@ Use this API when you want to script the same Kubernetes live-recording flow the --- +## Recording modes: Sidecar and DaemonSet + +The Kubernetes Proxy supports two recording modes. Both expose the same REST API documented here — pick whichever fits your environment. + +- **Sidecar mode (default).** When recording starts, the proxy's `MutatingAdmissionWebhook` injects a `keploy-agent` sidecar container into the target Pod and rolls it. The agent intercepts traffic from the application container alongside it. This is the mode the rest of this document describes. +- **DaemonSet mode.** A `keploy-daemonset` Pod runs on each node and captures traffic from existing application Pods via eBPF — no sidecar injection, no application-Pod restart. Recording is scoped by a `RecordingSession` Custom Resource that the proxy creates from `/record/start`; the DaemonSet agents pick it up and program their BPF target maps. This is the right mode when application Pods cannot be mutated (read-only RBAC on the application namespace), or when the rollout cost of injecting a sidecar is unacceptable. Cluster-mode auto-replay (a separate replay cluster reached via mounted kubeconfig) is supported in this mode. + +The same `/record/start`, `/record/stop`, `/test/start`, `/deployments`, and report endpoints work identically across both modes — the difference is purely in how the agent is delivered to the workload. + +--- + ## Why the Kubernetes Proxy instead of `keploy enterprise` directly? Running the Keploy enterprise CLI inside a Pod works, but it is a per-app, per-node model: each Deployment you want to record needs its own sidecar plumbing, image rebuild, or pod restart. The Kubernetes Proxy removes that friction: @@ -78,7 +89,7 @@ The proxy generates a 32-byte random value (`crypto/rand`, hex-encoded) on every Authenticated callers fetch the current token from the Keploy API server, which mirrors the latest heartbeat from each cluster. Log in once to obtain a user JWT, then look up the proxy app for the Deployment you want to drive: ```bash -API_SERVER="https://api.keploy.io" # or your self-hosted api-server URL +API_SERVER="https://api.keploy.io" NS="default" DEPLOY="orders-api" CLUSTER="prod-use1" @@ -340,7 +351,7 @@ Omit `selectedTests` to replay every set. ### API-server-compatible data routes -These routes are all mounted under `/k8s-proxy`. They are served directly by the proxy in self-hosted mode and by the API server in SaaS mode. Direct proxy calls use the proxy shared token. API-server calls use normal Console/API-server authentication and role checks. +These routes are all mounted under `/k8s-proxy` and are served directly by the proxy. Direct proxy calls use the proxy shared token; calls routed through the API server use normal Console/API-server authentication and role checks. #### Health From 679bfe7171b0b6c89765516eecfb6f555dc0b537 Mon Sep 17 00:00:00 2001 From: Yash Khare Date: Mon, 27 Apr 2026 17:25:37 +0530 Subject: [PATCH 3/7] docs(k8s-proxy quickstart): document DaemonSet recording mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The K8s Live Record & Replay quickstart only walked through Sidecar mode (default — agent injected via MutatingAdmissionWebhook). Add a "Pick a recording mode" section right above step 1 with a comparison table covering when to choose Sidecar vs DaemonSet, and a "DaemonSet mode (optional)" subsection under step 4 with the Helm flags to enable it (`daemonset.enabled=true`, `daemonset.crds.install=true`) plus the verification commands (`kubectl get pods -n keploy`, `kubectl get crd | grep keploy.io`). Both modes drive the identical Console UI / REST API, so the existing screenshots and the rest of the quickstart stay correct verbatim — only the install command branches. Applied to both v3.0.0 and v4.0.0 quickstart files since they were identical pre-edit. Signed-off-by: Yash Khare --- .../version-3.0.0/quickstart/k8s-proxy.md | 46 +++++++++++++++++++ .../version-4.0.0/quickstart/k8s-proxy.md | 46 +++++++++++++++++++ 2 files changed, 92 insertions(+) diff --git a/versioned_docs/version-3.0.0/quickstart/k8s-proxy.md b/versioned_docs/version-3.0.0/quickstart/k8s-proxy.md index 3b2fb44a2..fe1ea18f0 100644 --- a/versioned_docs/version-3.0.0/quickstart/k8s-proxy.md +++ b/versioned_docs/version-3.0.0/quickstart/k8s-proxy.md @@ -135,6 +135,20 @@ At this point, your e-commerce application is live and ready to receive traffic. ## Enable Live Record & Replay with Keploy Proxy +### Pick a recording mode + +The Keploy Proxy supports two ways to capture traffic from your application Pods. Both modes drive the **same Console UI and REST API** — the rest of this guide works identically in either case. Pick whichever fits your environment. + +| | **Sidecar mode (default)** | **DaemonSet mode** | +| --- | --- | --- | +| How traffic is captured | A `keploy-agent` sidecar container is injected into your application Pod via a `MutatingAdmissionWebhook`. The agent intercepts traffic alongside your container. | A `keploy-daemonset` Pod runs on each node and captures traffic from existing application Pods using **eBPF** — no sidecar, no application Pod restart. | +| What happens on `Start Recording` | The proxy injects the agent and rolls the application Deployment. | The proxy creates a `RecordingSession` Custom Resource. The DaemonSet picks it up and programs its BPF target maps to capture matching Pods on each node. | +| Pod mutation on the application namespace | Required (`patch` on Deployments). | **Not required.** Application Pods are never modified. | +| Application restart at recording start | Yes, on first recording. | No. | +| Best for | Dev/staging, teams happy to grant write RBAC to Keploy on the application namespace. | Production with read-only RBAC on the application namespace; environments where rolling the application Pod has unacceptable cost; or when you want cluster-mode auto-replay (replay runs in a separate cluster you provide). | + +The screenshots below show the **Sidecar** flow because that is the default. To use **DaemonSet** mode instead, set the daemonset values when you run the Helm command in step 4 below — every other step is identical. + ### 1. Open Keploy Dashboard Visit: @@ -175,6 +189,38 @@ Once you have provided the cluster details, you can install the Keploy Proxy in Sample Keploy K8s proxy +#### DaemonSet mode (optional) + +If you want to use **DaemonSet mode** instead of the default Sidecar mode, append the daemonset values to the Helm command shown in the dashboard. The Helm chart installs the `recordingsessions.keploy.io` and `replaysessions.keploy.io` Custom Resource Definitions, and the per-node DaemonSet that performs the eBPF capture. + +```bash +# add these flags to the Helm command from the dashboard: + --set daemonset.enabled=true \ + --set daemonset.crds.install=true +``` + +After install you should see a per-node `k8s-proxy-daemonset-*` Pod alongside the regular proxy Deployment: + +```bash +kubectl get pods -n keploy +# NAME READY STATUS RESTARTS AGE +# k8s-proxy-xxxxxxxxxx-xxxxx 1/1 Running 0 1m +# k8s-proxy-daemonset-xxxxx 1/1 Running 0 1m ← per node +# k8s-proxy-daemonset-yyyyy 1/1 Running 0 1m +# k8s-proxy-mongodb-xxxxxxxxxx-xxxxx 1/1 Running 0 1m +# k8s-proxy-minio-xxxxxxxxxx-xxxxx 1/1 Running 0 1m +``` + +Verify the CRDs registered: + +```bash +kubectl get crd | grep keploy.io +# recordingsessions.keploy.io +# replaysessions.keploy.io +``` + +The rest of this quickstart proceeds identically — the Console **Start Recording** button creates a `RecordingSession` CR which the DaemonSet picks up; you do not need to interact with the CR yourself. + ### 5. Verify the Installation Paste the Helm command into the terminal. Once the installation is complete, verify that the Keploy Proxy is running. diff --git a/versioned_docs/version-4.0.0/quickstart/k8s-proxy.md b/versioned_docs/version-4.0.0/quickstart/k8s-proxy.md index 3b2fb44a2..fe1ea18f0 100644 --- a/versioned_docs/version-4.0.0/quickstart/k8s-proxy.md +++ b/versioned_docs/version-4.0.0/quickstart/k8s-proxy.md @@ -135,6 +135,20 @@ At this point, your e-commerce application is live and ready to receive traffic. ## Enable Live Record & Replay with Keploy Proxy +### Pick a recording mode + +The Keploy Proxy supports two ways to capture traffic from your application Pods. Both modes drive the **same Console UI and REST API** — the rest of this guide works identically in either case. Pick whichever fits your environment. + +| | **Sidecar mode (default)** | **DaemonSet mode** | +| --- | --- | --- | +| How traffic is captured | A `keploy-agent` sidecar container is injected into your application Pod via a `MutatingAdmissionWebhook`. The agent intercepts traffic alongside your container. | A `keploy-daemonset` Pod runs on each node and captures traffic from existing application Pods using **eBPF** — no sidecar, no application Pod restart. | +| What happens on `Start Recording` | The proxy injects the agent and rolls the application Deployment. | The proxy creates a `RecordingSession` Custom Resource. The DaemonSet picks it up and programs its BPF target maps to capture matching Pods on each node. | +| Pod mutation on the application namespace | Required (`patch` on Deployments). | **Not required.** Application Pods are never modified. | +| Application restart at recording start | Yes, on first recording. | No. | +| Best for | Dev/staging, teams happy to grant write RBAC to Keploy on the application namespace. | Production with read-only RBAC on the application namespace; environments where rolling the application Pod has unacceptable cost; or when you want cluster-mode auto-replay (replay runs in a separate cluster you provide). | + +The screenshots below show the **Sidecar** flow because that is the default. To use **DaemonSet** mode instead, set the daemonset values when you run the Helm command in step 4 below — every other step is identical. + ### 1. Open Keploy Dashboard Visit: @@ -175,6 +189,38 @@ Once you have provided the cluster details, you can install the Keploy Proxy in Sample Keploy K8s proxy +#### DaemonSet mode (optional) + +If you want to use **DaemonSet mode** instead of the default Sidecar mode, append the daemonset values to the Helm command shown in the dashboard. The Helm chart installs the `recordingsessions.keploy.io` and `replaysessions.keploy.io` Custom Resource Definitions, and the per-node DaemonSet that performs the eBPF capture. + +```bash +# add these flags to the Helm command from the dashboard: + --set daemonset.enabled=true \ + --set daemonset.crds.install=true +``` + +After install you should see a per-node `k8s-proxy-daemonset-*` Pod alongside the regular proxy Deployment: + +```bash +kubectl get pods -n keploy +# NAME READY STATUS RESTARTS AGE +# k8s-proxy-xxxxxxxxxx-xxxxx 1/1 Running 0 1m +# k8s-proxy-daemonset-xxxxx 1/1 Running 0 1m ← per node +# k8s-proxy-daemonset-yyyyy 1/1 Running 0 1m +# k8s-proxy-mongodb-xxxxxxxxxx-xxxxx 1/1 Running 0 1m +# k8s-proxy-minio-xxxxxxxxxx-xxxxx 1/1 Running 0 1m +``` + +Verify the CRDs registered: + +```bash +kubectl get crd | grep keploy.io +# recordingsessions.keploy.io +# replaysessions.keploy.io +``` + +The rest of this quickstart proceeds identically — the Console **Start Recording** button creates a `RecordingSession` CR which the DaemonSet picks up; you do not need to interact with the CR yourself. + ### 5. Verify the Installation Paste the Helm command into the terminal. Once the installation is complete, verify that the Keploy Proxy is running. From 3eabfeece934b640f779e75c01bfbaff529db4d4 Mon Sep 17 00:00:00 2001 From: Yash Khare Date: Mon, 27 Apr 2026 17:30:01 +0530 Subject: [PATCH 4/7] docs(k8s-proxy): satisfy Vale + Prettier on DaemonSet additions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two CI checks were failing on PR #838 against the new DaemonSet content: - Vale: flagged daemonset/CRDs/eBPF/MutatingAdmissionWebhook/ RecordingSession/keploy-{agent,daemonset} as misspellings, plus Google.EmDash on " — " (em-dash with surrounding spaces). - Prettier 3.8.3: needed reflow on the new tables / sections in versioned_docs/version-{3,4}.0.0/quickstart/k8s-proxy.md. Fix: - Add the new technical terms to vale_styles/config/vocabularies/ Base/accept.txt (case-folding patterns where it makes sense). - Strip the spaces around em-dashes in the lines I introduced. - Run prettier --write on the changed quickstart files; api.md was already prettier-clean. Signed-off-by: Yash Khare --- .../config/vocabularies/Base/accept.txt | 10 ++++++++++ .../version-3.0.0/quickstart/k8s-proxy.md | 20 +++++++++---------- .../version-4.0.0/quickstart/k8s-proxy.md | 20 +++++++++---------- .../running-keploy/k8s-proxy-api.md | 6 +++--- 4 files changed, 33 insertions(+), 23 deletions(-) diff --git a/vale_styles/config/vocabularies/Base/accept.txt b/vale_styles/config/vocabularies/Base/accept.txt index 5cd91cb23..63a52d4a5 100644 --- a/vale_styles/config/vocabularies/Base/accept.txt +++ b/vale_styles/config/vocabularies/Base/accept.txt @@ -122,3 +122,13 @@ initialised normalisation behaviour polyglot +[Dd]aemon[Ss]et[s]? +[Cc]RD[s]? +eBPF +[Mm]utatingAdmissionWebhook +RecordingSession[s]? +ReplaySession[s]? +keploy-daemonset +keploy-agent +recordingsessions +replaysessions diff --git a/versioned_docs/version-3.0.0/quickstart/k8s-proxy.md b/versioned_docs/version-3.0.0/quickstart/k8s-proxy.md index fe1ea18f0..504bf287f 100644 --- a/versioned_docs/version-3.0.0/quickstart/k8s-proxy.md +++ b/versioned_docs/version-3.0.0/quickstart/k8s-proxy.md @@ -137,17 +137,17 @@ At this point, your e-commerce application is live and ready to receive traffic. ### Pick a recording mode -The Keploy Proxy supports two ways to capture traffic from your application Pods. Both modes drive the **same Console UI and REST API** — the rest of this guide works identically in either case. Pick whichever fits your environment. +The Keploy Proxy supports two ways to capture traffic from your application Pods. Both modes drive the **same Console UI and REST API**—the rest of this guide works identically in either case. Pick whichever fits your environment. -| | **Sidecar mode (default)** | **DaemonSet mode** | -| --- | --- | --- | -| How traffic is captured | A `keploy-agent` sidecar container is injected into your application Pod via a `MutatingAdmissionWebhook`. The agent intercepts traffic alongside your container. | A `keploy-daemonset` Pod runs on each node and captures traffic from existing application Pods using **eBPF** — no sidecar, no application Pod restart. | -| What happens on `Start Recording` | The proxy injects the agent and rolls the application Deployment. | The proxy creates a `RecordingSession` Custom Resource. The DaemonSet picks it up and programs its BPF target maps to capture matching Pods on each node. | -| Pod mutation on the application namespace | Required (`patch` on Deployments). | **Not required.** Application Pods are never modified. | -| Application restart at recording start | Yes, on first recording. | No. | -| Best for | Dev/staging, teams happy to grant write RBAC to Keploy on the application namespace. | Production with read-only RBAC on the application namespace; environments where rolling the application Pod has unacceptable cost; or when you want cluster-mode auto-replay (replay runs in a separate cluster you provide). | +| | **Sidecar mode (default)** | **DaemonSet mode** | +| ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| How traffic is captured | A `keploy-agent` sidecar container is injected into your application Pod via a `MutatingAdmissionWebhook`. The agent intercepts traffic alongside your container. | A `keploy-daemonset` Pod runs on each node and captures traffic from existing application Pods using **eBPF**—no sidecar, no application Pod restart. | +| What happens on `Start Recording` | The proxy injects the agent and rolls the application Deployment. | The proxy creates a `RecordingSession` Custom Resource. The DaemonSet picks it up and programs its BPF target maps to capture matching Pods on each node. | +| Pod mutation on the application namespace | Required (`patch` on Deployments). | **Not required.** Application Pods are never modified. | +| Application restart at recording start | Yes, on first recording. | No. | +| Best for | Dev/staging, teams happy to grant write RBAC to Keploy on the application namespace. | Production with read-only RBAC on the application namespace; environments where rolling the application Pod has unacceptable cost; or when you want cluster-mode auto-replay (replay runs in a separate cluster you provide). | -The screenshots below show the **Sidecar** flow because that is the default. To use **DaemonSet** mode instead, set the daemonset values when you run the Helm command in step 4 below — every other step is identical. +The screenshots below show the **Sidecar** flow because that is the default. To use **DaemonSet** mode instead, set the daemonset values when you run the Helm command in step 4 below—every other step is identical. ### 1. Open Keploy Dashboard @@ -219,7 +219,7 @@ kubectl get crd | grep keploy.io # replaysessions.keploy.io ``` -The rest of this quickstart proceeds identically — the Console **Start Recording** button creates a `RecordingSession` CR which the DaemonSet picks up; you do not need to interact with the CR yourself. +The rest of this quickstart proceeds identically—the Console **Start Recording** button creates a `RecordingSession` CR which the DaemonSet picks up; you do not need to interact with the CR yourself. ### 5. Verify the Installation diff --git a/versioned_docs/version-4.0.0/quickstart/k8s-proxy.md b/versioned_docs/version-4.0.0/quickstart/k8s-proxy.md index fe1ea18f0..504bf287f 100644 --- a/versioned_docs/version-4.0.0/quickstart/k8s-proxy.md +++ b/versioned_docs/version-4.0.0/quickstart/k8s-proxy.md @@ -137,17 +137,17 @@ At this point, your e-commerce application is live and ready to receive traffic. ### Pick a recording mode -The Keploy Proxy supports two ways to capture traffic from your application Pods. Both modes drive the **same Console UI and REST API** — the rest of this guide works identically in either case. Pick whichever fits your environment. +The Keploy Proxy supports two ways to capture traffic from your application Pods. Both modes drive the **same Console UI and REST API**—the rest of this guide works identically in either case. Pick whichever fits your environment. -| | **Sidecar mode (default)** | **DaemonSet mode** | -| --- | --- | --- | -| How traffic is captured | A `keploy-agent` sidecar container is injected into your application Pod via a `MutatingAdmissionWebhook`. The agent intercepts traffic alongside your container. | A `keploy-daemonset` Pod runs on each node and captures traffic from existing application Pods using **eBPF** — no sidecar, no application Pod restart. | -| What happens on `Start Recording` | The proxy injects the agent and rolls the application Deployment. | The proxy creates a `RecordingSession` Custom Resource. The DaemonSet picks it up and programs its BPF target maps to capture matching Pods on each node. | -| Pod mutation on the application namespace | Required (`patch` on Deployments). | **Not required.** Application Pods are never modified. | -| Application restart at recording start | Yes, on first recording. | No. | -| Best for | Dev/staging, teams happy to grant write RBAC to Keploy on the application namespace. | Production with read-only RBAC on the application namespace; environments where rolling the application Pod has unacceptable cost; or when you want cluster-mode auto-replay (replay runs in a separate cluster you provide). | +| | **Sidecar mode (default)** | **DaemonSet mode** | +| ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| How traffic is captured | A `keploy-agent` sidecar container is injected into your application Pod via a `MutatingAdmissionWebhook`. The agent intercepts traffic alongside your container. | A `keploy-daemonset` Pod runs on each node and captures traffic from existing application Pods using **eBPF**—no sidecar, no application Pod restart. | +| What happens on `Start Recording` | The proxy injects the agent and rolls the application Deployment. | The proxy creates a `RecordingSession` Custom Resource. The DaemonSet picks it up and programs its BPF target maps to capture matching Pods on each node. | +| Pod mutation on the application namespace | Required (`patch` on Deployments). | **Not required.** Application Pods are never modified. | +| Application restart at recording start | Yes, on first recording. | No. | +| Best for | Dev/staging, teams happy to grant write RBAC to Keploy on the application namespace. | Production with read-only RBAC on the application namespace; environments where rolling the application Pod has unacceptable cost; or when you want cluster-mode auto-replay (replay runs in a separate cluster you provide). | -The screenshots below show the **Sidecar** flow because that is the default. To use **DaemonSet** mode instead, set the daemonset values when you run the Helm command in step 4 below — every other step is identical. +The screenshots below show the **Sidecar** flow because that is the default. To use **DaemonSet** mode instead, set the daemonset values when you run the Helm command in step 4 below—every other step is identical. ### 1. Open Keploy Dashboard @@ -219,7 +219,7 @@ kubectl get crd | grep keploy.io # replaysessions.keploy.io ``` -The rest of this quickstart proceeds identically — the Console **Start Recording** button creates a `RecordingSession` CR which the DaemonSet picks up; you do not need to interact with the CR yourself. +The rest of this quickstart proceeds identically—the Console **Start Recording** button creates a `RecordingSession` CR which the DaemonSet picks up; you do not need to interact with the CR yourself. ### 5. Verify the Installation diff --git a/versioned_docs/version-4.0.0/running-keploy/k8s-proxy-api.md b/versioned_docs/version-4.0.0/running-keploy/k8s-proxy-api.md index d2b196356..866d4d113 100644 --- a/versioned_docs/version-4.0.0/running-keploy/k8s-proxy-api.md +++ b/versioned_docs/version-4.0.0/running-keploy/k8s-proxy-api.md @@ -39,12 +39,12 @@ Use this API when you want to script the same Kubernetes live-recording flow the ## Recording modes: Sidecar and DaemonSet -The Kubernetes Proxy supports two recording modes. Both expose the same REST API documented here — pick whichever fits your environment. +The Kubernetes Proxy supports two recording modes. Both expose the same REST API documented here—pick whichever fits your environment. - **Sidecar mode (default).** When recording starts, the proxy's `MutatingAdmissionWebhook` injects a `keploy-agent` sidecar container into the target Pod and rolls it. The agent intercepts traffic from the application container alongside it. This is the mode the rest of this document describes. -- **DaemonSet mode.** A `keploy-daemonset` Pod runs on each node and captures traffic from existing application Pods via eBPF — no sidecar injection, no application-Pod restart. Recording is scoped by a `RecordingSession` Custom Resource that the proxy creates from `/record/start`; the DaemonSet agents pick it up and program their BPF target maps. This is the right mode when application Pods cannot be mutated (read-only RBAC on the application namespace), or when the rollout cost of injecting a sidecar is unacceptable. Cluster-mode auto-replay (a separate replay cluster reached via mounted kubeconfig) is supported in this mode. +- **DaemonSet mode.** A `keploy-daemonset` Pod runs on each node and captures traffic from existing application Pods via eBPF—no sidecar injection, no application-Pod restart. Recording is scoped by a `RecordingSession` Custom Resource that the proxy creates from `/record/start`; the DaemonSet agents pick it up and program their BPF target maps. This is the right mode when application Pods cannot be mutated (read-only RBAC on the application namespace), or when the rollout cost of injecting a sidecar is unacceptable. Cluster-mode auto-replay (a separate replay cluster reached via mounted kubeconfig) is supported in this mode. -The same `/record/start`, `/record/stop`, `/test/start`, `/deployments`, and report endpoints work identically across both modes — the difference is purely in how the agent is delivered to the workload. +The same `/record/start`, `/record/stop`, `/test/start`, `/deployments`, and report endpoints work identically across both modes—the difference is purely in how the agent is delivered to the workload. --- From 7024a2fd246ed1c16e5aefb7804b535acfb41a8a Mon Sep 17 00:00:00 2001 From: Yash Khare Date: Mon, 27 Apr 2026 17:33:18 +0530 Subject: [PATCH 5/7] docs(vale): disable Google.Units to allow "k8s" tokens MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Google.Units rule fires `\d+(?:s|ms|ns|min|h|d)` with `nonword: true`, which matches `8s` inside the token `k8s` (and `k3s`, `k0s`, ...). On the K8s Proxy quickstart page every screenshot URL contains `k8s-proxy/k8s_…`, so reviewdog with `filter_mode: diff_context` fails the PR even though the offending lines are pre-existing — once a diff hunk reaches into them, every k8s image src becomes an error. Disabling the rule sitewide is consistent with the other Google.* overrides already in .vale.ini (PassiveVoice/We/Will/Exclamation/ Ellipses/Latin all set NO). For a Kubernetes-heavy docs site the unit-spacing check is more cost than benefit. Signed-off-by: Yash Khare --- .vale.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/.vale.ini b/.vale.ini index 3bb7088aa..c43022bee 100644 --- a/.vale.ini +++ b/.vale.ini @@ -19,6 +19,7 @@ Google.Will = NO # Allow "will" usage Google.Exclamation = NO # Allow exclamation points Google.Ellipses = NO # Allow ellipses in text Google.Latin = NO # Allow "e.g." and "i.e." instead of "for example" +Google.Units = NO # Allow "k8s" — Google.Units' \d+s regex matches "8s" inside the token # Allow specific terms: Vale.Terms=NO From 488bde776685e57b2abf4709ab4618b738d0225a Mon Sep 17 00:00:00 2001 From: Yash Khare Date: Mon, 27 Apr 2026 17:48:38 +0530 Subject: [PATCH 6/7] docs(k8s-proxy): correct shared-token provisioning, drop public-API line MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two corrections to the K8s Proxy REST API guide after auditing it against the actual k8s-proxy code: 1. Token provisioning. The doc claimed the proxy generates a 32-byte random value via crypto/rand on every Pod start and rotates the token whenever the Pod restarts. That is the **fallback** path in cmd/k8s/main.go (taken only when KEPLOY_SHARED_TOKEN is unset) — the real production path is: - Helm chart (charts/k8s-proxy/templates/shared-token-secret.yaml) generates the value once via `randAlphaNum 48` on first install. - Stored in a Secret `-shared-token`, annotated with `helm.sh/resource-policy: keep` and backed by `lookup` so it survives upgrades. - k8s-proxy Deployment + DaemonSet both mount it as KEPLOY_SHARED_TOKEN via `secretKeyRef`. - Token is therefore **stable for the lifetime of the Helm release**, NOT per-Pod. - Proxy still reports the value to the API server in its first heartbeat (POST /cluster/status), so the existing /cluster/getApp retrieval flow stays accurate. Rewrote "How the token is provisioned" to describe the Helm path first and the random fallback second, and added a "(a) Read it directly from the Secret" path under "Retrieve the token" since that is often the fastest option for operators with kubectl access. The closing note no longer claims the token rotates on Pod restart. 2. Removed the closing line in §"Why the Kubernetes Proxy" that pointed users to the Public REST API as a single-app alternative. Signed-off-by: Yash Khare --- .../running-keploy/k8s-proxy-api.md | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/versioned_docs/version-4.0.0/running-keploy/k8s-proxy-api.md b/versioned_docs/version-4.0.0/running-keploy/k8s-proxy-api.md index 866d4d113..355f911f2 100644 --- a/versioned_docs/version-4.0.0/running-keploy/k8s-proxy-api.md +++ b/versioned_docs/version-4.0.0/running-keploy/k8s-proxy-api.md @@ -60,8 +60,6 @@ Running the Keploy enterprise CLI inside a Pod works, but it is a per-app, per-n - **Self-updating.** The proxy can roll itself (and the injected agent) forward via `POST /proxy/update`, so upgrades do not require kubectl or a GitOps round-trip—unless you _want_ GitOps to stay authoritative (the proxy detects and reports reverts). - **Static deduplication at the edge.** Enable `static_dedup` in the recording config to drop schema-identical traffic _before_ it is ever written as a test case. See [Static Deduplication](/docs/keploy-cloud/static-deduplication/). -If you only need to script a single app outside Kubernetes, the [Public REST API](/docs/running-keploy/public-api/) (`api.keploy.io/client/v1`) is the better fit. The Kubernetes Proxy API is specifically the _live-recording_ control plane. - --- ## Authentication @@ -82,11 +80,23 @@ curl -sf https://$PROXY/healthz ### How the token is provisioned -The proxy generates a 32-byte random value (`crypto/rand`, hex-encoded) on every Pod start and reports it to the Keploy API server in its first heartbeat. The token is **not** sourced from a Helm value, ConfigMap, or Secret, and it rotates whenever the Pod restarts. There is nothing to commit in GitOps and nothing to read out of `kubectl get secret`. +The shared token is generated **at Helm install time** and stored as a Kubernetes Secret named `-shared-token` in the proxy's namespace. The chart's pre-render step uses Helm's `randAlphaNum 48` to produce the value on the very first install and a `lookup` + `helm.sh/resource-policy: keep` annotation to preserve it across upgrades, so the token is **stable for the lifetime of the release** — Pod restarts and chart upgrades do not rotate it. + +The k8s-proxy Deployment and the per-node DaemonSet both mount the Secret as the `KEPLOY_SHARED_TOKEN` env var via `secretKeyRef`. On startup the proxy reports the value to the Keploy API server in its first heartbeat (`POST /cluster/status`) so the Console can display it under the cluster's app entries. + +For local/dev runs without a Secret, if `KEPLOY_SHARED_TOKEN` is unset the proxy falls back to generating a random 32-byte value via `crypto/rand` (hex-encoded). This fallback is fresh on every restart and is **not** the path used in any Helm-managed deployment. ### Retrieve the token -Authenticated callers fetch the current token from the Keploy API server, which mirrors the latest heartbeat from each cluster. Log in once to obtain a user JWT, then look up the proxy app for the Deployment you want to drive: +Two equally valid paths. + +**(a) Read it directly from the Secret** if you have `kubectl` access to the proxy namespace: + +```bash +kubectl -n keploy get secret -shared-token -o jsonpath='{.data.token}' | base64 -d +``` + +**(b) Fetch it from the Keploy API server**, which mirrors what the proxy heartbeated. Log in once to obtain a user JWT, then look up the proxy app for the Deployment you want to drive: ```bash API_SERVER="https://api.keploy.io" @@ -109,7 +119,7 @@ AUTH="Authorization: Bearer $K8S_PROXY_SHARED_TOKEN" `GET /cluster/getApps` returns the same `sharedToken` field for every proxy-managed app in your organization in a single response, which is convenient when you want to script across many Deployments at once. -> The proxy shared token is cluster-wide, not per-user. The API server still uses normal user JWT/cookie authentication on its own routes (including `/cluster/getApp`). Programmatic callers should re-fetch the shared token on each run, since it changes whenever the proxy Pod restarts. +> The proxy shared token is cluster-wide, not per-user. The API server still uses normal user JWT/cookie authentication on its own routes (including `/cluster/getApp`). The token is sticky across Pod restarts and chart upgrades, so callers can cache it for the lifetime of the Helm release. --- From a9caf10464d93e5141f71313b538858781794504 Mon Sep 17 00:00:00 2001 From: Yash Khare Date: Mon, 27 Apr 2026 17:52:10 +0530 Subject: [PATCH 7/7] docs(k8s-proxy): vale fixes on the token-provisioning rewrite MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two errors that landed on PR #838 after the shared-token correction: - Google.EmDash on the new sentence in §"How the token is provisioned" (" — Pod restarts and chart upgrades do not rotate it"). Strip the surrounding spaces around the em-dash to match the rule. - Vale.Spelling on "heartbeated" — not in the dictionary and reads awkwardly anyway. Reword to "what the proxy reported in its last heartbeat". Signed-off-by: Yash Khare --- versioned_docs/version-4.0.0/running-keploy/k8s-proxy-api.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/versioned_docs/version-4.0.0/running-keploy/k8s-proxy-api.md b/versioned_docs/version-4.0.0/running-keploy/k8s-proxy-api.md index 355f911f2..e96b7b8cd 100644 --- a/versioned_docs/version-4.0.0/running-keploy/k8s-proxy-api.md +++ b/versioned_docs/version-4.0.0/running-keploy/k8s-proxy-api.md @@ -80,7 +80,7 @@ curl -sf https://$PROXY/healthz ### How the token is provisioned -The shared token is generated **at Helm install time** and stored as a Kubernetes Secret named `-shared-token` in the proxy's namespace. The chart's pre-render step uses Helm's `randAlphaNum 48` to produce the value on the very first install and a `lookup` + `helm.sh/resource-policy: keep` annotation to preserve it across upgrades, so the token is **stable for the lifetime of the release** — Pod restarts and chart upgrades do not rotate it. +The shared token is generated **at Helm install time** and stored as a Kubernetes Secret named `-shared-token` in the proxy's namespace. The chart's pre-render step uses Helm's `randAlphaNum 48` to produce the value on the very first install and a `lookup` + `helm.sh/resource-policy: keep` annotation to preserve it across upgrades, so the token is **stable for the lifetime of the release**—Pod restarts and chart upgrades do not rotate it. The k8s-proxy Deployment and the per-node DaemonSet both mount the Secret as the `KEPLOY_SHARED_TOKEN` env var via `secretKeyRef`. On startup the proxy reports the value to the Keploy API server in its first heartbeat (`POST /cluster/status`) so the Console can display it under the cluster's app entries. @@ -96,7 +96,7 @@ Two equally valid paths. kubectl -n keploy get secret -shared-token -o jsonpath='{.data.token}' | base64 -d ``` -**(b) Fetch it from the Keploy API server**, which mirrors what the proxy heartbeated. Log in once to obtain a user JWT, then look up the proxy app for the Deployment you want to drive: +**(b) Fetch it from the Keploy API server**, which mirrors what the proxy reported in its last heartbeat. Log in once to obtain a user JWT, then look up the proxy app for the Deployment you want to drive: ```bash API_SERVER="https://api.keploy.io"