Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 119 additions & 9 deletions src/pages/docs/features/secrets.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -197,7 +197,102 @@ environment:
```

<Callout type="warning">
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.
</Callout>

### 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=...`.

<Callout type="warning">
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.
</Callout>

## Mixing Secrets with Template Variables
Expand Down Expand Up @@ -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 |

<Callout type="warning">
If a required secret is missing, your application may fail to start or behave
Expand Down Expand Up @@ -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:
Expand Down
Loading