From 43444192cc10b104ef58e87e27e914dcb1b89de8 Mon Sep 17 00:00:00 2001 From: jnfrati Date: Fri, 30 Oct 2026 15:27:44 +0100 Subject: [PATCH] feat(netbird): env values take valueFrom, so a key can move to a Secret without replacing the list --- charts/netbird/docs/configuration.md | 7 +++++++ charts/netbird/templates/_helpers.tpl | 16 ++++++++++++++-- charts/netbird/templates/dashboard/_helpers.tpl | 6 +++--- charts/netbird/tests/render.sh | 10 ++++++++++ 4 files changed, 34 insertions(+), 5 deletions(-) diff --git a/charts/netbird/docs/configuration.md b/charts/netbird/docs/configuration.md index 9b13246..39d2baf 100644 --- a/charts/netbird/docs/configuration.md +++ b/charts/netbird/docs/configuration.md @@ -114,6 +114,11 @@ Every component accepts literal, structured, and Secret-backed environment entri ```yaml env: STATIC_NAME: static-value + SECRET_NAME: + valueFrom: + secretKeyRef: + name: provider-credentials + key: client-secret envRaw: - name: POD_NAME @@ -125,6 +130,8 @@ envFromSecret: PROVIDER_CLIENT_ID: provider-credentials/client-id ``` +An `env` value is a string or a map with only `valueFrom`. Unlike `envRaw`, a list that replaces as a whole, `env` merges per key, so one layered values file, or a chart that depends on this one, can turn a default literal into a Secret reference without touching other entries. + `envFromSecret` references use `secret-name/secret-key` syntax. Provider examples use this mechanism for identity-provider, STUN, TURN, and database credentials. For the dashboard, `dashboard.env` overrides environment values generated from `dashboard.config`. Prefer `dashboard.config` for supported fields. diff --git a/charts/netbird/templates/_helpers.tpl b/charts/netbird/templates/_helpers.tpl index 807170f..d9a5b92 100644 --- a/charts/netbird/templates/_helpers.tpl +++ b/charts/netbird/templates/_helpers.tpl @@ -136,6 +136,19 @@ app.kubernetes.io/component: {{ .component }} {{- end -}} {{- end -}} +{{/* One env entry: a literal, or a map holding only valueFrom, so a parent chart's default can be replaced per key. Context: name, value. */}} +{{- define "netbird.envEntry" -}} +- name: {{ .name }} +{{- if kindIs "map" .value }} +{{- if or (ne (len .value) 1) (not (hasKey .value "valueFrom")) }} +{{- fail (printf "env.%s must be a string or a map with only valueFrom" .name) }} +{{- end }} + {{- toYaml .value | nindent 2 }} +{{- else }} + value: {{ .value | quote }} +{{- end }} +{{- end -}} + {{/* User-supplied environment entries. Context: values, reserved (names the chart sets). */}} {{- define "netbird.env" -}} {{- $names := list -}} @@ -150,8 +163,7 @@ app.kubernetes.io/component: {{ .component }} {{- $seen = append $seen $name -}} {{- end -}} {{- range $key := keys .values.env | sortAlpha }} -- name: {{ $key }} - value: {{ index $.values.env $key | quote }} +{{ include "netbird.envEntry" (dict "name" $key "value" (index $.values.env $key)) }} {{- end }} {{- with .values.envRaw }} {{ toYaml . }} diff --git a/charts/netbird/templates/dashboard/_helpers.tpl b/charts/netbird/templates/dashboard/_helpers.tpl index b31c170..af17433 100644 --- a/charts/netbird/templates/dashboard/_helpers.tpl +++ b/charts/netbird/templates/dashboard/_helpers.tpl @@ -27,13 +27,13 @@ {{- if not $clientSecretRef -}} {{- $_ := set $generated "AUTH_CLIENT_SECRET" $auth.clientSecret -}} {{- end -}} -{{- $environment := mergeOverwrite $generated (deepCopy .Values.dashboard.env) -}} +{{- $environment := $generated -}} +{{- range $key, $value := .Values.dashboard.env }}{{ $_ := set $environment $key $value }}{{ end -}} {{- /* envFromSecret and envRaw win: drop the plain entry so the name appears once. */ -}} {{- range $key := keys .Values.dashboard.envFromSecret }}{{ $_ := unset $environment $key }}{{ end -}} {{- range .Values.dashboard.envRaw }}{{ $_ := unset $environment .name }}{{ end -}} {{- range $key := keys $environment | sortAlpha }} -- name: {{ $key }} - value: {{ index $environment $key | quote }} +{{ include "netbird.envEntry" (dict "name" $key "value" (index $environment $key)) }} {{- end }} {{- if and $clientSecretRef (not (hasKey .Values.dashboard.env "AUTH_CLIENT_SECRET")) (not (hasKey .Values.dashboard.envFromSecret "AUTH_CLIENT_SECRET")) }} - name: AUTH_CLIENT_SECRET diff --git a/charts/netbird/tests/render.sh b/charts/netbird/tests/render.sh index daacbc0..ac8e755 100755 --- a/charts/netbird/tests/render.sh +++ b/charts/netbird/tests/render.sh @@ -174,4 +174,14 @@ out="$(render "${required[@]}" --set-string backend.split.signal.config.pprofAdd grep -A1 "name: NB_PPROF_ADDR" <<<"$out" | grep -qF '"127.0.0.1:6061"' || { echo "FAIL: NB_PPROF_ADDR"; exit 1; } grep -A1 "name: NB_TRUSTED_PROXIES" <<<"$out" | grep -qF '"10.0.0.0/8"' || { echo "FAIL: NB_TRUSTED_PROXIES"; exit 1; } +# 23. env takes a valueFrom map, for backends and the dashboard, and rejects anything else in a map. +out="$(render "${required[@]}" \ + --set backend.split.management.env.FROM_SECRET.valueFrom.secretKeyRef.name=s \ + --set backend.split.management.env.FROM_SECRET.valueFrom.secretKeyRef.key=k \ + --set dashboard.env.AUTH_AUDIENCE.valueFrom.secretKeyRef.name=dash \ + --set dashboard.env.AUTH_AUDIENCE.valueFrom.secretKeyRef.key=aud)" +grep -A4 "name: FROM_SECRET" <<<"$out" | grep -qF "name: s" || { echo "FAIL: env valueFrom"; exit 1; } +grep -A4 "name: AUTH_AUDIENCE" <<<"$out" | grep -qF "name: dash" || { echo "FAIL: dashboard env valueFrom"; exit 1; } +fails_with "env.BAD must be a string or a map with only valueFrom" "${required[@]}" --set backend.split.signal.env.BAD.value=x + echo "render checks passed"