fix(audit,web,deploy): audit ids, web dry-run view, hardened chart, docs

Audit: correlation event_ids include stage and response code so the
multi-stage lines of one request no longer collapse under dedup; match
scans are bounded to a time window and a page instead of the object's full
history.

Web: dry-run results are read from dry_run_result (nested) so the verdict is
rendered correctly and conflicts/errors/skipped are shown; the plans view no
longer POSTs an unsolicited plan on page load; coverage and streams surface
API errors instead of showing a misleading empty state and follow cursor
pagination so they are not stuck on the oldest page; the diff path tokenizer
handles backslash-escaped dotted keys.

Deploy/CI: the chart no longer grants the query server a cluster-wide read
ClusterRole, runs as non-root with a read-only root filesystem, adds
liveness/readiness probes, wires the ConfigMap as env (STORE_PATH,
LISTEN_ADDR), defaults the journal to a PVC instead of an ephemeral
emptyDir, and adds imagePullSecrets; the replay ClusterRole drops the
unused update verb; a Dockerfile builds a static distroless image; GitHub
actions are pinned by commit SHA, jobs set least-privilege permissions, the
Vercel deploy skips fork PRs, CI passes the Makefile test timeouts, and
make lint runs a real web syntax check.

Docs: event-schema/consistency no longer describe an ingest_sequence field,
an observed-time-based event_id, or restart-from-checkpoint; the threat
model documents the unauthenticated HTTP API surface and the chart's RBAC
change; replay-safety matches the enforced dry-run gate.
This commit is contained in:
lakshit verma 2026-08-06 06:57:11 +05:30
parent 44fbd878a1
commit 9f4b6c2c5a
No known key found for this signature in database
GPG key ID: EB498AFC60A7A01A
23 changed files with 251 additions and 96 deletions

View file

@ -14,7 +14,7 @@ This document lists the threats that krply is designed against, the controls tha
| Invalid owner references | Orphaned objects | Remove or remap UIDs, replay roots only | replay-safety |
| Name collision | Community confusion | Rename or coordinate | none |
Each row of the risk table maps to at least one control above. The controls are structural. The journal format, the planner policy, and the RBAC manifests enforce them. They do not depend on operator discipline alone.
Each row of the risk table maps to at least one control above. The controls are structural. The journal format, the planner policy, and the RBAC manifests enforce them. They do not depend on operator discipline alone. The exception is the HTTP API surface, which is unauthenticated by design and relies on network placement; see "HTTP API surface" below.
## Trust boundaries
@ -51,7 +51,19 @@ Rules:
- No cluster-admin.
- No write access to the source cluster.
Reference manifests: ../../deploy/rbac/. The Helm chart ships a recorder ClusterRole bound to its own ServiceAccount. See ../../deploy/helm/krply/.
Reference manifests: ../../deploy/rbac/. The Helm chart ships no ClusterRole for the krply-server ServiceAccount because the server reads only the journal and resolves the replay target through its own in-cluster configuration. See ../../deploy/helm/krply/.
## HTTP API surface
The query API served by krply-server is **unauthenticated** and is intended to run on a trusted network. This is a deliberate simplification, not a hard control:
| Surface | Risk | Mitigation (as shipped) |
|---|---|---|
| Read endpoints (`/v1/health`, clusters, streams, events, history, diff, snapshots, plans) | Anyone who can reach the port can read the journal, which may contain recorded ConfigMaps and object bodies | Bind to a trusted interface, place the server behind an authenticated reverse proxy, or restrict it to loopback; do not expose it to the public internet |
| `POST /v1/replay-plans/{id}/dry-run` and `POST /v1/replay-runs` | A network peer could trigger a dry run or an apply against the target cluster | The server resolves the target cluster only through its own kubeconfig and never accepts a client-supplied kubeconfig. Apply requires `confirm: true` and a plan whose dry run already succeeded; plans are held in server memory and are not persisted across restarts |
| CORS | A malicious web page could drive the API from a victim's browser | Set `KRPLY_CORS_ORIGINS` to an explicit allowlist. The default is `*`, so the wildcard must be overridden before the server is exposed anywhere a browser could reach it |
If the server is exposed beyond a trusted network, add authentication and TLS at the proxy before it.
## What the tool does NOT claim