Security Model¶
KubeManta is secure by default: a vanilla install is read-only, with no cluster-admin access, no stored LLM keys, and no egress for cluster data.
Authentication¶
| Layer | Detail |
|---|---|
| Login | Password authentication — passwords are bcrypt-hashed, never stored in plaintext. Sessions use signed, time-limited tokens (24-hour lifetime). |
| Reset | kubectl exec -n kubemanta-system deploy/kubemanta-agent -- km-reset-pw |
| Lockout | 6 failed attempts per IP triggers a 15-minute lockout. |
| Programmatic access | Per-user API keys (X-API-Key header), created per account in Admin → Users. No shared secret exists. See Programmatic access. |
RBAC — read-only by default¶
| ServiceAccount | Role | When active |
|---|---|---|
kubemanta |
kubemanta-reader (ClusterRole) |
Always — get/list/watch on pods, logs, services, configmaps, events, deployments, statefulsets, daemonsets, ingresses, jobs, cronjobs, nodes, namespaces |
kubemanta |
+ write verbs | Only when rbac.allowWrites=true: adds pods create/delete, pods/exec, secrets create/update/patch, deployments patch/update, namespaces create |
kubemanta-expert |
cluster-admin |
Only when expertMode.enabled=true. The token lives only in a separate, isolated pod — the main agent pod never mounts it. |
Secrets read (get/list on secrets) is separately gated by rbac.readSecrets (default false). Enable only if Secret inspection via the AI agent or terminal is required.
Namespace blocklist¶
The following namespaces are always hidden from the UI and excluded from RBAC — they cannot be observed, diagnosed, or modified through KubeManta regardless of settings:
kube-system · kube-public · kube-node-lease · istio-system · paas-core · cert-manager · ingress-nginx · traefik · monitoring · logging · flux-system · argo · argocd · kubemanta-system
All namespaces with the prefixes gke-*, gmp-*, kube-* are also blocked by prefix match.
Programmatic access¶
API access and the MCP server authenticate with per-user API keys. There is no
shared secret: the previous security.apiKey Helm value was removed because a
single cluster-wide token could not be attributed to a person, could not be revoked
without a redeploy, and bypassed the seat model.
Creating a key. An admin opens Admin → Users, expands a user's API keys, and creates one. The secret is displayed exactly once — only a SHA-256 hash is stored, so a lost key must be revoked and replaced rather than recovered.
Format is km_<prefix>_<secret>: a 160-bit CSPRNG secret, looked up by the indexed
prefix and compared with a constant-time check.
A key always acts as its owner, right now. The owner's role is read from the
users table on every request:
| What you do to the user | What happens to their existing keys |
|---|---|
| Demote admin → viewer | Keys survive and immediately act as a viewer |
| Promote viewer → admin | Keys immediately regain admin reach |
| Deactivate the user | Every key returns 401 |
| Revoke one key | That key returns 401; the owner's other keys are unaffected |
Viewers may hold keys — they are simply read-only.
Keys can never manage identity or billing. Even for an admin owner, a key is
refused (403 api_key_forbidden) on /admin/users*, /admin/api-keys*,
/me/api-keys*, /admin/sso*, /admin/sessions*, /admin/license*, and writes to
/admin/seats. This is enforced in middleware, before any handler runs, so a stolen
key cannot mint another key or escalate its own account.
Every API-key request is attributed in the audit log as <username>@<ip>, which is
what makes credential sharing visible.
AI key handling¶
LLM API keys are passed per-request in the request body. They are:
- Never written to disk or SQLite
- Never logged
- Never sent to KubeManta infrastructure
The PTY terminal is BYO-LLM: ANTHROPIC_API_KEY (and every other secret-bearing variable) is stripped from the terminal environment before a session spawns. Claude Code in the terminal authenticates per-user via its own claude OAuth login (persisted in ~/.claude on the PVC) or a key the operator exports themselves. A server-side Anthropic key (Helm agent.agentApiKey, stored in a Kubernetes Secret) is used only by the agent's autonomous alert investigation and scheduled reports — never exposed to terminal sessions.
Three-pod isolation¶
KubeManta splits privilege across three distinct security contexts so that no single compromised process holds everything:
| Pod / context | Holds | Reaches |
|---|---|---|
| Agent | The database, encryption key, session secrets, SSO config | Read-only reader ServiceAccount (writes only with rbac.allowWrites) |
| Expert-exec pod | The cluster-admin token (only when expertMode.enabled=true) |
Full cluster — but only via bearer-authenticated calls from the agent over a NetworkPolicy-restricted hop, using an ephemeral kubeconfig that is discarded after every operation |
| Terminal sidecar | Only its own storage (Claude Code session + caches) | No cluster-admin token, no database, no encryption key — runs as a distinct, lower-privilege user in its own process namespace |
So the cluster-admin token is never in the agent pod, the terminal process cannot reach the agent's secrets or database, and privileged operations are delegated over an authenticated, network-policy-restricted hop. The runtime Expert-Mode toggle is enforced on both the privileged HTTP/Helm endpoints and the AI agent write tools.
The terminal WebSocket is authenticated before the connection is accepted — an unauthenticated upgrade is refused, no session spawned — and is subject to the same IP access control as the rest of the product.
Autonomous agent write safety¶
When the AI agent is asked to perform a write operation (delete pod, restart deployment, scale):
- Normal mode (default): the agent pauses and waits for explicit human approval in the UI before executing
- Auto mode: executes writes without approval — requires explicit user opt-in; never the default
- Blast radius limit: hard cap of 5 write operations per session (
agent.blastRadiusLimit) - Circuit breaker: trips after 3 consecutive write failures (
agent.circuitBreakerThreshold); blocks all writes until auto-reset (agent.circuitBreakerResetSecs = 300s) - Max remediation cycles: 2 autonomous cycles per app per hour (anti-flap throttle)
Data storage¶
| Data | Where stored | Notes |
|---|---|---|
| Workload data, logs, events | Never stored — fetched live from the K8s API | |
| Audit log, alert history, settings | Embedded database on the PVC | In-cluster only |
| Terminal home (Claude Code session, kubeconfig, history) | PVC | Persistent across pod restarts |
| Cloud credentials (AWS/GCP/Azure) | Embedded database, AES-256-GCM encrypted | Masked •••• in all API responses |
| Helm config/data/cache | PVC | |
| LLM API keys | Never persisted | Per-request only |
| Admin password | bcrypt hash, in-cluster only |
Encryption at rest¶
Cloud credentials, Helm registry passwords, and integration secrets are encrypted with AES-256-GCM before being written to the embedded database. A random 256-bit encryption key is generated on first install, stored in a Kubernetes Secret, and preserved across upgrades and uninstalls. You can supply your own key (bring-your-own-key) via security.encryptionKey.
To disable (plaintext storage): --set security.encryptionAtRest=false (not recommended).
Pod hardening¶
| Control | Detail |
|---|---|
| seccompProfile | RuntimeDefault on all pods |
| PodSecurity | baseline enforce + restricted warn on kubemanta-system (applied manually via kubectl label namespace) |
| NetworkPolicy | Blocks all egress to 169.254.169.254 (cloud Instance Metadata Service) from all pods in kubemanta-system. Disable with security.blockImds=false only if your workloads need IMDS for Workload Identity bootstrap. |
| readOnlyRootFilesystem | true on the UI container; /tmp overlay via emptyDir |
| Non-root | Every container runs as a non-root user; the terminal sidecar runs as a distinct, lower-privilege user in its own process namespace |
Supply-chain integrity¶
All published images (kubemanta-agent, kubemanta-ui) are keyless-signed with cosign by digest and ship an SPDX SBOM attestation, both bound to the GitHub Actions OIDC identity. You can cosign verify any image before deploying it. See Supply Chain.
Tamper-evident audit¶
Every audited action is recorded in an append-only audit log that is hash-chained — each entry cryptographically covers the one before it, so any edit or interior deletion is detectable on demand, with no configuration. Actor attribution is derived from the real client IP (security.trustedProxyCidrs governs when X-Forwarded-For is trusted) and is email-aware for SSO sessions. An optional off-box WORM export (audit.worm) writes each entry to your own Object-Lock S3 bucket to close the trimming-the-newest-rows gap. See Activity & Audit.
Access & exposure¶
An in-product IP access layer (allowlist / denylist / durable auto-ban), a sliding session idle-timeout, and a service-only exposure mode let you front KubeManta with your own edge/WAF. All Free. See Access Control.
Enterprise SSO¶
Authenticate operators through your own identity provider — SAML 2.0, OIDC, or LDAP — with JIT provisioning and group→role mapping; the local admin password is always retained as break-glass. See Enterprise SSO.
AI Guardrails¶
Org-wide AI policy (master on/off switch, data residency, cost caps, write safety, namespace scope, egress allowlist, prompt audit, redaction) is configurable in Admin → AI Guardrails. See AI Guardrails.