As a learning exercise, I'm trying to set up a template to retrieve azure keyvault secrets dynamically. The secrets need to be available between jobs:
parameters:
- name: secretsFilter
type: string
jobs:
- job: kv
displayName: Fetch keyvault variables
pool: MAPLE-STAGING
steps:
- checkout: none
- task: AzureKeyVault@2
inputs:
azureSubscription: 'x'
KeyVaultName: 'y'
SecretsFilter: ${{ parameters.secretsFilter }}
- script: |
secrets="${{ replace(parameters.secretsFilter, ',', ' ') }}"
for secretName in $secrets; do
echo "##vso[task.setvariable variable=$secretName;isoutput=true;issecret=false;isreadonly=true]$($secretName)"
done
name: kv
- template: keyvault-practice.yml
parameters:
secretsFilter: 'some-user,some-password'
I've managed to split the string and iterate through the items. I'm still having trouble however with storing the item's value. Storing the variable without a loop would look similar to this:
echo "##vso[task.setvariable variable=some-user-name;isoutput=true;issecret=true;isreadonly=true]$(some-user-name)"
I think I'm incorrectly mixing up runtime bash variables with compile-time azure pipeline placeholders when I'm using $($secretName)
in my loop, as I receive the message line 4: some-user-name: command not found
. My other option would be to declare an array object
- name: secrets
type: object:
default: []
instead of a comma separated string and loop the items when rendering the script, instead of what I'm doing right now. However, I haven't figured out how to accomplish this yet.
Would anyone know how my setup can be modified in order to dynamically retrieve keyvault secrets?
Ok, so we answered this question yesterday, outlining different approaches for this.
I want to address why your script doesn’t work. The KeyVault task pulls down the secrets and adds them as environment variables. However, tasks that use the azure-devops-pipeline-tasks api have logic to filter secrets out of the environment variables as a security precaution to prevent secrets from leaking into places where they weren’t intended. As such, you have to opt-in secrets into a task by passing them through the env
argument of the task.
As your script is dynamically defining the secretsFilter as a parameter, you can dynamic define the env
argument.
- script: |
secrets="${{ replace(parameters.secretsFilter, ',', ' ') }}"
for secretName in $secrets; do
echo "##vso[task.setvariable variable=$secretName;isoutput=true;issecret=false;isreadonly=true]$($secretName)"
done
name: secretOutputs
displayName: Create output variables
env:
${{ each secretName in secrets }}:
${{ secretName }}: $(${{ secretName }})