From 195806911cc4a2a66a6d9bf7113e2aa9e46b7c65 Mon Sep 17 00:00:00 2001 From: Vigneshraj Sekar Babu Date: Mon, 4 May 2026 11:48:47 -0700 Subject: [PATCH] docs: document helm custom value secret refs --- src/pages/docs/features/secrets.mdx | 128 ++++++++++++++++++++++++++-- 1 file changed, 119 insertions(+), 9 deletions(-) diff --git a/src/pages/docs/features/secrets.mdx b/src/pages/docs/features/secrets.mdx index de87eb73..b98378b4 100644 --- a/src/pages/docs/features/secrets.mdx +++ b/src/pages/docs/features/secrets.mdx @@ -12,7 +12,7 @@ import { Callout } from "nextra/components"; ## Overview -Lifecycle integrates with cloud secret providers to securely inject secrets into your ephemeral environments. You can reference secrets directly in your `lifecycle.yaml` environment variables using a template syntax, and Lifecycle handles the rest. +Lifecycle integrates with cloud secret providers to securely inject secrets into your ephemeral environments. You can reference secrets directly in your `lifecycle.yaml` environment variables and native Helm custom values using a template syntax, and Lifecycle handles the rest. Supported providers: @@ -153,7 +153,7 @@ For a secret containing: ## Where Secrets Work -The secret syntax works in all `env` blocks: +The secret syntax works in all `env` blocks and in native Helm custom values: ### GitHub Services @@ -197,7 +197,102 @@ environment: ``` - Helm and Codefresh deployment types do not currently support cloud secrets. + Codefresh Helm deployments do not support cloud secrets in Helm custom values. + Use native Helm deployment for secret-backed Helm values. + + +### Native Helm Custom Values + +Native Helm deployments support full-value secret references in `helm.chart.values`. +Lifecycle mounts the synced Kubernetes Secret into the Helm job and passes the +value with Helm `--set-file`, so the resolved secret value is read from a file +instead of being written into the Helm command. + +```yaml +services: + - name: postgres + helm: + repository: myorg/orders-api + branchName: main + deploymentMethod: native + chart: + name: postgresql + repoUrl: https://charts.example.com + values: + - "auth.username={{aws:myapp/postgres:username}}" + - "auth.password={{aws:myapp/postgres:password}}" + - "auth.database=orders" +``` + +Lifecycle renders the plain value normally and turns the secret-backed values +into `--set-file` arguments: + +```bash +helm upgrade --install postgres bitnami/postgresql \ + --set auth.database=orders \ + --set-file auth.username=/var/run/lifecycle/helm-secrets/.../helm.auth.username... \ + --set-file auth.password=/var/run/lifecycle/helm-secrets/.../helm.auth.password... +``` + +Only complete Helm values can be secret references: + +```yaml +chart: + values: + # Correct + - "auth.password={{aws:myapp/postgres:password}}" + + # Wrong: partial interpolation is not supported for Helm secret values + - "databaseUrl=postgres://app:{{aws:myapp/postgres:password}}@postgres:5432/orders" +``` + +For composite values, put the full value in your cloud secret and reference it +directly: + +```yaml +chart: + values: + - "databaseUrl={{aws:myapp/postgres:databaseUrl}}" +``` + +Native Helm custom values can still use regular Lifecycle template variables: + +```yaml +services: + - name: api + requires: + - name: postgres + helm: + deploymentMethod: native + chart: + name: api + values: + - "env.DATABASE_HOST={{postgres_internalHostname}}" + - "env.DATABASE_PASSWORD={{aws:myapp/postgres:password}}" +``` + +If the same Helm key is set more than once, Lifecycle resolves the final winning +value first, then decides whether to pass it with `--set` or `--set-file`: + +```yaml +chart: + values: + # Secret value wins because it is later + - "env.API_TOKEN={{api_internalHostname}}" + - "env.API_TOKEN={{aws:myapp/api:token}}" + + # Template value wins because it is later + - "env.CALLBACK_HOST={{aws:myapp/api:callbackHost}}" + - "env.CALLBACK_HOST={{api_internalHostname}}" +``` + +In the first pair, Lifecycle emits `--set-file env.API_TOKEN=...`. In the +second pair, Lifecycle emits `--set env.CALLBACK_HOST=...`. + + + Do not add Helm `--debug` or `--dry-run` args when using secret-backed Helm + values. Lifecycle rejects those combinations because Helm can print rendered + values into job logs. ## Mixing Secrets with Template Variables @@ -238,12 +333,14 @@ env: Lifecycle uses a "warn and continue" approach for secret errors: -| Scenario | Behavior | -| --------------------- | ----------------------------------------------------- | -| Secret not found | Warning logged, env var not set, deployment continues | -| Key not found in JSON | Warning logged, env var not set | -| Provider not enabled | Warning logged, env var not set | -| Invalid syntax | Validation error at deploy time | +| Scenario | Behavior | +| ---------------------------------- | ----------------------------------------------------- | +| Secret not found | Warning logged, env var not set, deployment continues | +| Key not found in JSON | Warning logged, env var not set | +| Provider not enabled | Warning logged, env var not set | +| Invalid syntax | Validation error at deploy time | +| Partial Helm secret interpolation | Validation error at deploy time | +| Helm value secret ref on Codefresh | Unsupported deploy path error | If a required secret is missing, your application may fail to start or behave @@ -322,6 +419,19 @@ DB_PASSWORD: "{{path:key}}" DB_PASSWORD: "{{aws:path:key}}" ``` +For native Helm custom values, the whole value after `=` must be the secret +reference: + +```yaml +chart: + values: + # Wrong - partial Helm secret interpolation + - "auth.password=prefix-{{aws:path:key}}" + + # Correct + - "auth.password={{aws:path:key}}" +``` + ### Permission Denied If you see permission errors: