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 byspring.config.activate.on-profileis merged only when its expression matches an active profile. -
Sidecar files — a
values-<profile>.yamlfile next to a basevalues.yaml(or next to a-ffile) 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 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.
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.yaml → values-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-platformis 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.yamlfiles are loaded without profile resolution. -
Remote
-f <url>files support document gating but not sidecars (there is no sibling directory to resolvevalues-<profile>.yamlagainst). -
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 —
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
|
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--setwins). Mirrorsspring.cloud.config.override-none. -
jhelm.config-server.override-system-properties=true— config server moves above the--setfamily. Mirrorsspring.cloud.config.override-system-properties.
6.2. CLI options (on template/install/upgrade)
| Option | Meaning |
|---|---|
|
config-server base URI (enables the source) |
|
application name (default: release name) |
|
label / git branch (default: server default) |
|
basic auth |
|
bearer token (takes precedence over basic auth) |
|
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 |
|---|---|
|
symmetric key; setting it enables decryption |
|
hex salt (default |
|
|
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
templateoutput and installed release data with the same care as any other secret material.