bashazureazure-devops

Azure DevOps: access secret variable programmatically


Context: Monorepository (Nx) with multiple applications

In Azure DevOps I'm trying to retrieve the deployment token of my applications. Since it's not secure to store the token in a JSON on the repo, I want to save in a configuration file the name of the secret in secretName (that will be somewhere) and then retrieve it using a simple script:

    for app in $apps; do
       # Check if the deployment-config.json exists for the app
       configPath="apps/$app/deployment-configs/deployment-config.${{ parameters.target_environment }}.json"
       if [ -f "$configPath" ]; then
          secretName=$(jq -r '.secretName' "$configPath") # Retrieve secret name from config file
          # TODO: RETRIEVE SECRET STORED IN A SECURE PLACE!
       fi
    done

Now at this point I have the name of the variable containing my script.

Setting a pipeline secret doesn't work since I need to explicitly pass all the secrets as env parameters (not ideal when you have multiple apps over 3 different environments). So something like secretValue=${!secretName} won't work.

Is there a way to achieve this without explicitly settings secrets as env? Using Azure KeyVault can be a valid way to implement

Update: get tokens with CLI

In my case, for static web apps, storing the tokens in a keyvault was not required since they could be directly accessed by calling az staticwebapp secrets list --name "$appName" --query "properties.apiKey" -o tsv


Solution

  • If you store the secrets on Azure DevOps (in a variable group or in a pipeline), it is not possible to use Azure DevOps REST API or CLI to get the values of secrets. To call the secrets in a script, you must use the 'env' key to map the secrets as environment variables for use.


    For your case, you can consider storing the secrets on Azure Key Vault. In your Bash script, after fetching the name of secret, you can use the Azure CLI "az keyvault secret show" to fetch the value of secret based on the name. Also see "Retrieve a secret from Key Vault".

    So, you can set you Bash script like as below:

    for app in $apps; do
       # Check if the deployment-config.json exists for the app
       configPath="apps/$app/deployment-configs/deployment-config.${{ parameters.target_environment }}.json"
       if [ -f "$configPath" ]; then
          # Fetch the secret name from config file
          secretName=$(jq -r '.secretName' "$configPath")
          # Fetch the secret value using Azure CLI
          secretValue=$(az keyvault secret show --vault-name "keyVaultName" --name "$secretName" --query value --output tsv)
       fi
    done
    

    In the pipeline of Azure DevOps, you can use the AzureCLI@2 task to run this Bash script like as below.

    parameters:
    # The name of the ARM service connection.
    - name: ArmConnection
      type: string
      default: 'xxxx'
    
    - name: target_environment
      type: string
      default: 'xxxx'
    # the name of the Azure Key Vault.
    - name: keyVaultName
      type: string
      default: 'xxxx'
    
    steps:
    - task: AzureCLI@2
      displayName: 'Retrieve secret'
      inputs:
        azureSubscription: ${{ parameters.ArmConnection }}
        scriptType: 'bash'
        scriptLocation: 'inlineScript'
        inlineScript: |
          for app in $apps; do
             configPath="apps/$app/deployment-configs/deployment-config.${{ parameters.target_environment }}.json"
             if [ -f "$configPath" ]; then
                secretName=$(jq -r '.secretName' "$configPath")
                secretValue=$(az keyvault secret show --vault-name "${{ parameters.keyVaultName }}" --name "$secretName" --query value --output tsv)
             fi
          done
    

    In addition, after creating the ARM connection, ensure the App registration (or User Assigned Managed Identity) used by the connection has the Get and List permissions of secrets on the Azure Key Vault.