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.
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.
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.
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.
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.
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
| Vector | Mitigation |
|---|---|
Reading Secret objects | No code path can fetch them (invariant 2) |
last-applied-configuration annotations, which embed the full prior object | Dropped unconditionally, never allowlistable |
| Env values, ConfigMap data, credential-bearing annotations | Structural masking; references such as secretKeyRef shown by name only |
| Credentials echoed into logs or events by workloads | Pattern and entropy scrubber with typed replacement tokens |
| Prompt injection via log or event text | Writes 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 counts | grep filters after redaction |
| Masked-value probing via field selectors | Field selectors are allowlisted per tool; masked fields are not filterable |
| Error messages leaking the API server URL | All client exceptions mapped to typed generic messages; details go to local stderr only |
| Enumeration via not-found errors | Names validated and scope-checked before any API call |
| Command injection | No shell-outs anywhere; the Kubernetes client library is the only egress; subprocess is never imported |
| Over-privileged kubeconfig | Startup access-review probe warns loudly, and refuses under --strict, if the credentials can read Secrets |
| API server abuse and exfiltration bandwidth | Per-tool and global token buckets, request timeouts, result byte caps |
Non-goals in v1
- No
exec,attach,port-forwardorcp. - 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.