Search code examples
azure-pipelinesazure-pipelines-yaml

Create azure pipeline template to fetch credentials from keyvault


I'm trying to set up an Azure Pipelines template to fetch azure keyvault credentials and use the retrieved credentials in a later stage.

fetch-from-keyvault.yml:

parameters:
- name: secrets
  type: object
  default: []
- name: jobName
  type: string
- name: dependsOn
  type: object
  default: []

jobs:
- job: ${{ parameters.jobName }}
  dependsOn: ${{ parameters.dependsOn }}
  displayName: Fetch keyvault variables
  steps:
  - checkout: none
  - task: AzureKeyVault@2
    inputs:
      azureSubscription: 'subscriptionNameHere'
      KeyVaultName: 'kvNameHere'
      SecretsFilter: '*' <<-- once it works I'll foreach the secrets here as well
  - ${{ each secret in parameters.secrets }}:
      - script: |
        echo "##vso[task.setvariable variable=${{ secret }};isoutput=true;issecret=true;isreadonly=true]$(${{ secret }})"

azure-pipelines.yml:

stages:
- ...
- stage: someStage
  dependsOn: ...
  condition: ...
  jobs:
  - template: ../jobs/fetch-from-keyvault.yml
    parameters:
      jobName: kv
      dependsOn: waitForValidation
      secrets:
      - 'some-user'
      - 'some-pass'
  - job: someJob
    dependsOn: kv
    variables:
      someUserName: $[dependencies.kv.outputs['kv.some-user']]
    steps:
    - script: |
        echo user: $(someUserName)
    - subsequentJobThatTriesToAuthenticateWithCredentials

In the Azure pipeline build output, it can be seen that the credentials are being retrieved from the Azure Key Vault:

Downloading secret value for: some-user.

I would have expected an output similar to user: **** as the secrets are masked when outputted. However, as user: is outputted I'm expecting that either the secrets are not properly stored or passed on to the someStage job. The subsequent job that tries to authenticate also receives an HTTP 401 status exception.

Would anyone know how I create a job template to fetch keyvault secrets and use the secrets in a later job?


Solution

  • By default, the AzureKeyVault@2 task will only make the retrieved secrets available to the next task.

    You could use the RunAsPreJob: true input as described in the documentation to make all retrieved secrets available to all tasks within that job.

    If that solution does not work for you, then what you are attempting to do by saving the secrets as variables in the subsequent tasks will work for you.

    Note that the secretsFilter input on the AzureKeyVault@2 should be a comma separated string.

    Here is an example of a working task snippet:

    - task: AzureKeyVault@2
      displayName: Get KeyVault secrets
      inputs:
        azureSubscription: "${{ parameters.serviceConnection }}"
        keyVaultName: "$(keyVaultName)"
        secretsFilter: "$(secretsFilter)"
    

    Here is the output of this task running. Note that it does not show the masked secret with *** after retrieval. If it has found the secret, it will state that it has downloaded it. [enter image description here]

    I would recommend in your following task that is saving the secrets as variables, remove the - ${{ each secret in parameters.secrets }}: expression, and add your loop logic into the script itself via bash or powershell.

    If you do want to do this using an expression, you can break the comma separated string up by doing something like this: - ${{ each secret in split(variables['secretsFilter'], ',') }}: