Security Model

jhelm exposes Helm operations over two network surfaces — the REST API and the MCP server — which share a single, unified security model under jhelm.security.*.

The standalone CLI honors the same jhelm.security.mode, but with a helm-like default: it runs in FULL (read-write) mode out of the box, so install / upgrade / uninstall / rollback / test work immediately, gated only by your kubeconfig and the cluster’s RBAC — exactly as helm behaves. Set jhelm.security.mode=READ_ONLY (via -Djhelm.security.mode or the JHELM_SECURITY_MODE env var) to lock a CLI down — for a shared workstation or an AI-agent guardrail — and those five commands are then refused with a non-zero exit. The CLI needs no api-key: that credential is validated against an HTTP header, which a local CLI never presents, so it applies only to the network-exposed REST/MCP adapters below.

The design in one line: MCP runs local-first, the REST API is deny-by-default behind an API key, read-only is the default everywhere, and Spring Security is the bring-your-own upgrade path for real auth.

1. Principles

  • Read-only by default. Out of the box, only non-mutating operations (template, show, lint, list, status, history, get) are available. They are safe to expose and never touch a cluster.

  • Deny-by-default for mutating operations. Cluster-mutating operations (install, upgrade, uninstall, rollback, test) are enabled only when both conditions hold: mode=FULL and an api-key is configured. FULL without a key leaves mutating operations disabled.

  • The API key is the floor, not the ceiling. The built-in key protects the network-exposed HTTP transport. For real multi-user auth (OAuth, mTLS, an upstream gateway), layer Spring Security on top — see Upgrade path: Spring Security.

2. Configuration (jhelm.security.*)

Property Default Description

jhelm.security.mode

READ_ONLY

Access mode. READ_ONLY exposes only non-mutating operations. FULL enables the cluster-mutating operations — but only when an api-key is also set (deny-by-default).

jhelm.security.api-key

(none)

Shared secret required to call mutating operations. With no key set, mutating operations stay disabled regardless of mode.

jhelm.security.api-key-header

X-API-Key

Name of the HTTP header that carries the API key.

jhelm.security.block-private-networks

false

SSRF hardening for outbound chart/repository fetches. When true, private/site-local targets (10/8, 172.16/12, 192.168/16) are refused in addition to the always-blocked loopback, link-local/cloud-metadata (169.254.0.0/16), wildcard and multicast ranges. Recommended when the server fetches on behalf of untrusted callers; left false by default so a private/internal repository stays reachable from a CLI.

jhelm:
  security:
    mode: FULL          # READ_ONLY (default) or FULL
    api-key: changeme   # required to actually enable mutating operations
    api-key-header: X-API-Key

The mutating gate is the logical AND of both settings:

mode api-key Mutating operations

READ_ONLY (default)

any

Disabled

FULL

not set

Disabled

FULL

set

Enabled

3. REST behaviour

The REST API always serves read-only endpoints. For a mutating endpoint, the outcome depends on the gate and the request’s API-key header:

Status When

403 Forbidden

Mutating is disabled — mode=READ_ONLY, or mode=FULL with no api-key configured. The operation is not available at all.

401 Unauthorized

Mutating is enabled, but the request is missing the X-API-Key header or presents an invalid value.

proceeds

Mutating is enabled and a valid X-API-Key header is present.

Read-only endpoints are always allowed and never require a key.

4. MCP behaviour

The MCP server applies the same model, with two transport-aware twists:

  • Tool gating. The cluster-mutating tools (helm_install, helm_upgrade, helm_uninstall, helm_rollback, helm_test) are only registered when mode=FULL and an api-key is set. When the gate is closed they do not exist at all — an agent never sees them.

  • HTTP filter. When an api-key is configured, an HTTP filter requires a valid X-API-Key header on the MCP HTTP endpoints (/mcp, /sse).

  • stdio / local bypass. A locally launched MCP server (stdio / localhost) never passes through the servlet filter, so it is not forced to present a key. The key protects the network-exposed HTTP transport, not a trusted local launch.

This matches how MCP is normally used: the server runs on the same machine as the agent, and the key only matters once the transport is exposed over the network. See the MCP security section for details.

5. Upgrade path: Spring Security

The built-in API key is a deliberately simple floor. For production multi-user authentication and authorization — OAuth2 / OIDC, mTLS, or delegating to an upstream API gateway — wire Spring Security into your application. Because both the REST and MCP surfaces are ordinary Spring MVC / web endpoints, standard Spring Security configuration applies on top of them.

Spring Security is configured in the embedding application, not baked into the starters. A fully secured sample is forthcoming.