Documentation

Threat model

The five security invariants, the attack surfaces they close, and how CI verifies that none of them quietly regress.


What is protected

The asset is cluster credential material and Secret contents: the kubeconfig (API server URL, CA data, client certificates, bearer tokens), Kubernetes Secret objects, and any secret values that leak into adjacent places such as env values, annotations, ConfigMaps and workload stdout.

The adversary of record is the LLM's context window. Anything that crosses the MCP boundary may be logged, retained or exfiltrated by whatever sits on the other side, so the only winning move is to never put secrets there.


Security invariants

Enforced by construction, verified in CI.

01

Credentials stay in server memory

The kubeconfig is loaded in-process against a pinned context and is never serialized into an MCP frame, tool description, log line or error message. The frame-capture leak test records every JSON-RPC frame of a full scripted session and greps for canaries and kubeconfig markers: zero hits, or the build fails.

02

Secrets are unreadable by design

Secret, ServiceAccount, CertificateSigningRequest and TokenReview have no entry in the kind registry, so the server never fetches them and cannot leak them. Asking for one returns a policy error with zero API calls.

03

Everything model-visible passes redaction

Three layers: structural per-kind field rules, pattern and entropy scrubbing of all free text, and output shaping with byte caps. Failures fail closed: a redaction exception returns a generic error, never the payload.

04

Writes need out-of-model human approval

A model-supplied parameter is never consent. Approval arrives via MCP elicitation or the out-of-band CLI, which binds a SHA-256 hash of the exact arguments to the approval id and burns each approval on first use.

05

Scope is enforced server-side on every call

Independent of RBAC: namespace allow and deny lists (deny wins), cluster-scope opt-in, kubeconfig context pinning, with the least-privilege RBAC manifests as a second independent layer.


Attack surfaces and mitigations

VectorMitigation
Reading Secret objectsNo code path can fetch them (invariant 2)
last-applied-configuration annotations, which embed the full prior objectDropped unconditionally, never allowlistable
Env values, ConfigMap data, credential-bearing annotationsStructural masking; references such as secretKeyRef shown by name only
Credentials echoed into logs or events by workloadsPattern and entropy scrubber with typed replacement tokens
Prompt injection via log or event textWrites always require human approval; untrusted-output framing; static tool descriptions; the approval card shows live state fetched at approval time
Approval bait-and-switch (approve A, execute B)Argument-hash binding, burn on use, and a fresh-read resourceVersion carried in the patch (409 on conflict)
Secret-probing via grep match countsgrep filters after redaction
Masked-value probing via field selectorsField selectors are allowlisted per tool; masked fields are not filterable
Error messages leaking the API server URLAll client exceptions mapped to typed generic messages; details go to local stderr only
Enumeration via not-found errorsNames validated and scope-checked before any API call
Command injectionNo shell-outs anywhere; the Kubernetes client library is the only egress; subprocess is never imported
Over-privileged kubeconfigStartup access-review probe warns loudly, and refuses under --strict, if the credentials can read Secrets
API server abuse and exfiltration bandwidthPer-tool and global token buckets, request timeouts, result byte caps

Non-goals in v1

  • No exec, attach, port-forward or cp.
  • No Secret reads under any circumstances.
  • Not a general kubectl replacement.
  • A single-operator local trust domain: stdio transport, no network listener, no multi-tenant auth.

Residual risks

  • The entropy scrubber has false positives on long high-entropy identifiers and false negatives on low-entropy secrets outside key=value shapes. Tune redaction.entropy_threshold, never disable the pass.
  • Namespace and resource names in scope are visible to the model by design. If the names themselves are sensitive, scope them out.
  • A hostile workload can still spam misleading diagnostics. The payoff is capped at a human-read approval card, but human attention is the last line of defense: read the card.