Value Profiles

jhelm supports value profiles — a Spring-Boot-style way to keep environment-specific values (dev, staging, prod, …) in one place and activate them at render/install time. This is a jhelm extension; it has no equivalent in Go Helm, and charts that don’t use it render byte-for-byte as before.

A profile can supply values two ways, both mirroring Spring Boot:

  • Document gating — inside a values file, a ----separated document guarded by spring.config.activate.on-profile is merged only when its expression matches an active profile.

  • Sidecar files — a values-<profile>.yaml file next to a base values.yaml (or next to a -f file) is merged only when <profile> is active.

Both apply to a chart’s own values.yaml and to files passed with -f/--values.

1. Activating profiles

Profiles come from one of three sources, in order of precedence (first wins):

Source Example

-P / --profile (per command)

jhelm template r ./chart -P prod,eu

JHELM_PROFILES_ACTIVE (env)

JHELM_PROFILES_ACTIVE=prod jhelm template r ./chart

jhelm.profiles.active (config)

jhelm: {profiles: {active: [prod]}} in application.yaml

-P/--profile accepts a comma-separated list or is repeatable (-P prod -P eu == -P prod,eu). The flag, when present, fully replaces the configured default rather than adding to it. Profiles are applied left to right, so a later profile’s values win over an earlier one’s. The -P/--profile flag is available on template, install, and upgrade.

2. Document gating

# values.yaml
replicas: 1
image:
  tag: latest
---
spring.config.activate.on-profile: prod
replicas: 3
image:
  tag: stable

With no active profile the second document is skipped (replicas: 1, tag: latest). Under -P prod it is deep-merged over the first (replicas: 3, tag: stable).

The spring.config.activate.on-profile key is a jhelm directive — it is stripped before the document reaches templates, so it never appears in .Values. The nested form (spring: {config: {activate: {on-profile: prod}}}) is accepted and stripped identically.

2.1. Profile expressions

The on-profile value is a Spring-style profile expression:

Operator Meaning

prod

active when prod is active

!prod

active when prod is not active

a & b

both active

a | b

either active

a, b

comma list — same as a | b (OR)

(a | b) & !c

grouping with parentheses

3. Sidecar files

mychart/
  Chart.yaml
  values.yaml            # base
  values-prod.yaml       # merged when 'prod' active
  values-eu.yaml         # merged when 'eu' active

Sidecars follow the base file’s name and extension: values.yamlvalues-prod.yaml, and a -f team.yaml file pairs with team-prod.yaml in the same directory. A missing sidecar for an active profile is simply skipped. values-<profile>.yaml files are treated as profile overlays, so — like values.yaml — they are excluded from the chart’s .Files.

4. Precedence

Profiles resolve within each values source; they do not change the overall override order:

chart values.yaml (+ gated docs + sidecars)
  < -f / --values files (+ their gated docs + sidecars)
  < --set / --set-string / --set-file / --set-json

5. Notes and limitations

  • spring.config.activate.on-cloud-platform is not evaluated for gating (jhelm has no cloud-platform detection), but it is stripped so it never leaks into .Values.

  • Profiles are applied to the top-level chart only; subchart values.yaml files are loaded without profile resolution.

  • Remote -f <url> files support document gating but not sidecars (there is no sibling directory to resolve values-<profile>.yaml against).

  • With no active profile, loading is unchanged from earlier releases — the feature is inert until a profile is activated.

6. Fetching values from a Spring Cloud Config Server

jhelm can also fetch values from a Spring Cloud Config Server, so environment configuration can live centrally (git-backed) instead of in local files. It consumes the server’s structured Environment endpoint (GET {uri}/{application}/{profiles}[/{label}]) and reuses the active profiles from above for the {profiles} path segment. Disabled by default.

Beyond Helm parity. Everything else in jhelm renders byte-for-byte like Go Helm. The config server (and the encrypted values below) is the first deliberate step past parity: one opt-in source that adds three things Helm has no story for —

  • central storage — one server holds the values for every release, versioned in git;

  • security — the server sits behind auth/TLS, and secrets travel as ciphertext;

  • profiles — the same -P profiles pick per-environment overlays server-side.

It stays inert unless you enable it, so charts that don’t use it are unaffected. We don’t re-document Spring Cloud Config here — see its reference docs; the runnable, secured jhelm-config-server-sample module is a working starting point.

The server returns each document/file as a flat property source (dotted and [i]-indexed keys), highest precedence first. jhelm strips the spring.config.activate. / jhelm.config.activate. directives from each source (the server does not), un-flattens the keys into nested maps/lists, and merges the sources first-wins.

6.1. Enabling and precedence

Setting --config-server-uri (or jhelm.config-server.enabled=true + uri) turns it on. By default the config server sits between local files and --set — matching Spring Boot’s config-data model, where command-line args outrank imported config-server values:

chart values < -f / profile files < CONFIG SERVER < --set family

Two flags mirror Spring’s knobs:

  • jhelm.config-server.override-none=true — config server drops to the lowest precedence (every local file and --set wins). Mirrors spring.cloud.config.override-none.

  • jhelm.config-server.override-system-properties=true — config server moves above the --set family. Mirrors spring.cloud.config.override-system-properties.

6.2. CLI options (on template/install/upgrade)

Option Meaning

--config-server-uri

config-server base URI (enables the source)

--config-name

application name (default: release name)

--config-label

label / git branch (default: server default)

--config-username / --config-password

basic auth

--config-token

bearer token (takes precedence over basic auth)

--config-fail-fast

abort if the server is unreachable (default: warn and continue)

The matching properties are jhelm.config-server.{enabled,uri,name,label,username,password,token,fail-fast,override-none,override-system-properties}; a CLI option overrides the corresponding property. Because these bind via Spring, the config server is available to the library, REST, and MCP surfaces too, not only the CLI.

6.3. Security

The config-server fetch uses jhelm’s SSRF-guarded HTTP path (the same one used for chart repositories): the URL is validated, credentials are host-gated, and TLS follows jhelm.insecure-skip-tls-verify. In server mode (jhelm.security.block-private-networks=true) a private/site-local config-server host is refused, closing the SSRF vector for a user-supplied URI. fail-fast=false (the default) logs a warning and continues with local values when the server is unreachable.

7. Encrypted values ({cipher})

Secrets in values don’t have to be plaintext. Any string value of the form {cipher}<hex> is a Spring Cloud Config encrypted token; when a decryption key is configured, jhelm decrypts it at render time, after values are merged and before templates run. This works the same whether the token comes from a -f values file, a chart’s own values.yaml, or a config-server response — so you can commit ciphertext to git and keep the plaintext off disk and off the wire.

With no key configured, {cipher} strings are left untouched (rendered verbatim), so the feature is inert until you opt in.

7.1. Enabling

Set a symmetric key:

Property Meaning

jhelm.encrypt.key

symmetric key; setting it enables decryption

jhelm.encrypt.salt

hex salt (default deadbeef, matching Spring Cloud)

jhelm.encrypt.fail-on-error

true (default) aborts on an undecryptable token; false logs a warning and leaves the token in place

The key binds via Spring, so it can come from an environment variable (JHELM_ENCRYPT_KEY=…), a mounted application.yaml, or your secret store — the usual Spring Boot externalized-config channels. It applies to template, install, and upgrade across the CLI, library, REST, and MCP surfaces.

7.2. Encrypting and decrypting from the CLI

# encrypt a value into a {cipher} token (reads jhelm.encrypt.key, or pass --key)
jhelm encrypt "s3cret-password"
jhelm encrypt "s3cret-password" --key my-key      # explicit key
echo -n "s3cret" | jhelm encrypt                  # value from stdin

# decrypt a token back to plaintext (prefix optional)
jhelm decrypt "{cipher}f0e1d2c3…"

Drop the token into a values file and render as usual:

# secrets.yaml
db:
  password: '{cipher}f0e1d2c3…'   # quote it — YAML treats a bare { as a flow map
JHELM_ENCRYPT_KEY=my-key jhelm template my-release ./chart -f secrets.yaml

7.3. Spring Cloud parity

jhelm uses the same primitive as Spring Cloud Config’s EncryptorFactory for a plain-text key (Encryptors.text(key, salt), default salt deadbeef), so tokens are byte-compatible in both directions: a token minted by a config server’s POST /encrypt decrypts with jhelm decrypt, and a jhelm encrypt token decrypts via the server’s POST /decrypt. This is the symmetric (shared-key) scheme; keystore/RSA {cipher} tokens are not yet supported.

By default a config server decrypts {cipher} values before serving them. To keep secrets encrypted on the wire and let jhelm decrypt them client-side, set spring.cloud.config.server.encrypt.enabled=false on the server — the approach the jhelm-config-server-sample module ships, so the plaintext never leaves the operator’s machine.

7.4. Security notes

  • The key is as sensitive as the secrets it protects — supply it from a secret store or environment variable, never commit it. jhelm reads it only from configuration, never writes or logs it.

  • Decryption failures are hard errors by default (fail-on-error=true) so a wrong key or a corrupted token fails the render rather than silently shipping ciphertext into a manifest.

  • Rendered manifests contain the plaintext secret — treat template output and installed release data with the same care as any other secret material.