From 81e66e311c08facea168c3f45211a1e0b44caaef Mon Sep 17 00:00:00 2001 From: willdavsmith Date: Thu, 2 Jul 2026 10:14:28 -0700 Subject: [PATCH] Resolve ${connection:.} sentinels in container env values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a connectionTokens table built from the same decrypted resourceConnections (and the same exclusions) as connectionEnvVars, then resolve any ${connection:.} sentinel found in a container env `value` to the connected resource's real property value. Both top-level connection properties and the nested `properties` bag are covered. This lets an application reference a specific connected-resource property by name in an env var — including a sensitive property delivered decrypted through connection injection — without relying on the fixed CONNECTION__ naming, and without a per-app startup shim or custom image. Backward-compatible: env values that contain no sentinel pass through unchanged, and secrets-resource connections / disableDefaultEnvVars are skipped exactly as for the default connection env vars. Signed-off-by: willdavsmith --- .../bicep/kubernetes-containers.bicep | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/Compute/containers/recipes/kubernetes/bicep/kubernetes-containers.bicep b/Compute/containers/recipes/kubernetes/bicep/kubernetes-containers.bicep index e6d26aa8..9e2586fc 100644 --- a/Compute/containers/recipes/kubernetes/bicep/kubernetes-containers.bicep +++ b/Compute/containers/recipes/kubernetes/bicep/kubernetes-containers.bicep @@ -111,6 +111,34 @@ var connectionEnvVars = reduce(items(resourceConnections), [], (acc, conn) => : acc ) +// Token table for ${connection:.} sentinels used in container env values. Uses the same +// decrypted source (resourceConnections) and the same exclusions as connectionEnvVars, so any connected +// resource property (top-level or nested `properties` bag) can be referenced by name in an env value and +// is resolved to its real (decrypted) value — without the fixed CONNECTION__ naming. +var connectionTokens = reduce(items(resourceConnections), [], (acc, conn) => + !isSecretsResource[conn.key] && connectionDefinitions[conn.key].?disableDefaultEnvVars != true + ? concat( + acc, + reduce(items(conn.value ?? {}), [], (tokenAcc, prop) => + (prop.key == 'properties' || prop.key == 'secretName' || contains(excludedProperties, prop.key)) + ? tokenAcc + : concat(tokenAcc, [{ + token: concat('$', '{connection:', conn.key, '.', prop.key, '}') + value: string(prop.value) + }]) + ), + reduce(items(conn.value.?properties ?? {}), [], (tokenAcc, prop) => + (prop.key == 'secretName' || contains(excludedProperties, prop.key)) + ? tokenAcc + : concat(tokenAcc, [{ + token: concat('$', '{connection:', conn.key, '.', prop.key, '}') + value: string(prop.value) + }]) + ) + ) + : acc +) + // Use replicas from properties, default to 1 if not specified var replicaCount = resourceProperties.?replicas != null ? int(resourceProperties.replicas) : 1 @@ -139,7 +167,7 @@ var containerSpecs = reduce(containerItems, [], (acc, item) => concat(acc, [{ { name: envItem.key }, - contains(envItem.value, 'value') ? { value: envItem.value.value } : {}, + contains(envItem.value, 'value') ? { value: reduce(connectionTokens, string(envItem.value.value), (acc, t) => replace(string(acc), t.token, t.value)) } : {}, (contains(envItem.value, 'valueFrom') && contains(envItem.value.valueFrom, 'secretKeyRef')) ? { valueFrom: { secretKeyRef: {