Today I was reviewing a colleague's Helm chart for a service that required API keys and database passwords. The classic dilemma: we don't want sensitive values in `values.yaml`, but we also don't want to template the Secret manifests directly into the chart, as it breaks the principle of separation of concerns.
I've typically seen three approaches, each with drawbacks:
* **Templating Secrets in the chart:** Litters your chart with `{{ .Values.dbPassword }}`, which is insecure if the chart is public.
* **Using external secret managers (e.g., Sealed Secrets, External Secrets):** Excellent, but adds operational complexity.
* **`helm install` with `--set`:** Cumbersome for many secrets and doesn't solve the issue of storing the chart with placeholder values.
However, I discovered Helm's `--post-renderer` flag offers a clean middle ground. A post-renderer is a executable that receives the fully rendered Kubernetes manifests (after all Helm templating) on stdin and can modify them before they are sent to the cluster.
The key insight: you can use a simple script to inject secret values *after* templating, leaving your chart clean and your `values.yaml` free of actual secrets.
Here's a minimal example using a Bash script as a post-renderer. Let's assume your chart creates a Secret manifest with placeholder data.
**Chart's `templates/secret.yaml`:** (Note the placeholder)
```yaml
apiVersion: v1
kind: Secret
metadata:
name: myapp-secrets
type: Opaque
data:
db-password: "#DB_PASSWORD#"
api-key: "#API_KEY#"
```
**Post-renderer script (`inject-secrets.sh`):**
```bash
#!/bin/bash
sed -e "s/#DB_PASSWORD#/$(echo -n "$DB_PASSWORD" | base64)/g"
-e "s/#API_KEY#/$(echo -n "$API_KEY" | base64)/g"
```
**Usage:**
```bash
export DB_PASSWORD="supersecret"
export API_KEY="myapikey123"
helm install myapp ./mychart --post-renderer ./inject-secrets.sh
```
The chart remains generic and reusable. The secret injection is controlled at deploy time via environment variables. This is particularly useful for CI/CD pipelines where secrets are available as environment variables.
Important considerations:
* The post-renderer script must be executable and available on the machine running `helm`.
* For production, you'd want a more robust post-renderer (e.g., a small Go binary) that can handle complex substitutions and potentially fetch from a vault.
* This does not encrypt the secrets within the rendered manifests; they are injected in plain text during the render phase. The security relies on your ability to secure the deployment process and environment.
This pattern elegantly decouples secret management from chart development. It's a pragmatic solution for teams not yet ready to adopt full-blown external secret operators.
--crusader
Commit early, deploy often, but always rollback-ready.