Azure 52: AzureKeyVault@2 chained with Helm `--set secrets`
easy⏱ 5 mincourseazure
AzureKeyVault@2 — pull pattern
The task connects via an ARM Service Connection, lists secrets in the vault that match SecretsFilter (use * for everything), and exposes each one as a pipeline variable named after the secret. Names are normalised: dashes become underscores, but Lythia uses lowercase-dashed names consistently so the mapping is predictable.
- task: AzureKeyVault@2
inputs:
azureSubscription: $(armDrivewayProdSC)
KeyVaultName: lease-cons-s-kv-prod
SecretsFilter: '*'
RunAsPreJob: true
Helm --set secrets pattern
The universal api chart's secret.yaml template creates one K8s Secret with keys matching secrets.* from values. Pipeline appends --set secrets.FINANCE_SERVICE_BUS_CONNECTION_STRING=\"$(lease-cons-s-kv-prod-connectionstring)\". Note the escaped quotes: connection strings contain ; which Helm interprets unless quoted.
helm upgrade --install $(serviceName) ./chart \
-f values.yaml -f values-prod.yaml \
--set image.tag=$(GIT_SEM_VER) \
--set secrets.FINANCE_SERVICE_BUS_CONNECTION_STRING=\"$(lease-cons-s-kv-prod-connectionstring)\" \
--set secrets.AZURE_BLOB_EDS_TSV_CONNECTION_STRING=\"$(primaryconnectionstring)\"
Why not CSI Secrets Store driver?
Lythia is migrating toward the CSI driver for new workloads (auto-rotation, no pipeline awareness of secrets). The build-time pattern persists for two reasons: (1) backward compat with the universal chart's existing secrets.* shape, (2) some secrets are NEEDED at startup before the CSI driver finishes mounting — Spring Boot fails health checks otherwise. Both patterns coexist for now.
Build the fanout
Write fanoutSecrets({ vaults, mapping }) where vaults: string[], mapping: Record<string, { vault, secretName }> is the pod-env-var-name → vault+secret mapping. Return { keyVaultSteps, helmSetFlags }. Every entry in mapping must point to a vault present in vaults — throw otherwise. Log a 3-vault fanout for odyssey-api (Service Bus + Mongo + Blob).
Use distinct secret names per env
Don't reuse the name DB_PASSWORD across dev/uat/prod vaults. Use DB-PASSWORD-dev, DB-PASSWORD-uat, etc. If someone accidentally points a prod pipeline at the dev vault during a rename, the helm --set would still 'work' but with the wrong value. Distinct names cause a hard failure: secret not found.
Quiz: a secret rotated mid-deploy
Q: Pipeline starts at 13:00, pulls the secret value at 13:01, finishes helm at 13:05. Ops rotates the secret at 13:03. What value is running in the pod? The 13:01 value. Pipeline pattern is snapshot-based. For auto-rotation you'd need the CSI driver pattern from lesson 36.