3
votes

I'm having difficulties with variable expression with the AzureKeyVault task. Both the azureSubscription and KeyVaultName values expressions are not being resolved to have variables in a variable Group. It works if I define those variables manually in any way in the yaml. Either in azure-pipelines.yml or in the template variables_test.yml that I import at the beginning of the stage.

I read in the documentation, that variables from a variable group should be used like this $(var) but then it throws an error saying a subscription like '$(var)' does not exist.

Template: azure-pipelines.yml:

- stage: Test

  variables:
  - template: variables_Test.yml  # Template reference
  - group: testVariableGroup

  dependsOn: []

  jobs:

  - job: Test
    
    steps:

    - task: AzureKeyVault@1
      inputs:
        azureSubscription: ${{ variables.spn_kv_app }}
        KeyVaultName: ${{ variables.keyVaultName }}
        SecretsFilter: '*'

In the logs from the staging i can see the variables being set from the variable group:

Job preparation parameters
Variables:
  keyVaultName: $[ variablegroups.testVariableGroup.keyVaultName ]
  resourceGroupName: $[ variablegroups.testVariableGroup.resourceGroupName ]
  spn_cd_app: $[ variablegroups.testVariableGroup.spn_cd_app ]
  spn_kv_app: $[ variablegroups.testVariableGroup.spn_kv_app ]
  storageAccountName: $[ variablegroups.testVariableGroup.storageAccountName ]

Important thing to note that those variables are not set to secrets in the variable group.

PS. For anyone interested. I created tickets:

https://github.com/MicrosoftDocs/vsts-docs/issues/7586

https://developercommunity.visualstudio.com/content/problem/949342/azuresubscription-serviceconnection.html

If anything will be reslved i will post an answer.

2
Any chance there was a resolution via the Developer Community? The link is dead. :/ I'm running into this same issue for the azureSubscription and a few other values in tasks other than Key Vault - Gregg L
@GreggL To be honest i forgot about this because we solved it with having the names hardcoded in the YAML. This works for us as for now but I can see this being an issue in the feature when we get more and azureSubscriptions to cover. - Repcak
That's ok. I appreciate the reply nonetheless! FWIW, I was able to get around this by creating "variable-only" template files. Each environment we deployed to had a corresponding "[env_name]-variables.yml" file checked into source control that contained the values for that environment. The appropriate job(s) load the corresponding template (file) (as variables) and can now get the "environment" values needed in the tasks. A little clunky, but it's manageable for now. - Gregg L
Does this also work as in this example for the AzureSubscription field in tasks like Azure Powershell? Because we also use variable only templates per environment for version control. - Repcak
It works for the azureSubscription field in the Azure CLI task, but I haven't tried Azure Powershell yet - Gregg L

2 Answers

1
votes

I don't think this is a bug, but rather a product limitation. There are two kinds of fields you can't assign "external" (AKA from a var group) variables:

  • The ones that point to Service Connections, used in many different types of tasks, such as an ARM Template Deployment. (may have many different names depending on the task, such as "azureSubscription", "serviceConnection", etc)
  • The environment names, mandatory in in deployment jobs

This is actually documented, but in a very hidden place (should be on the main variables page!). See the last paragraph here.

You may say "But I used this in situation XYZ and it worked!" and I will agree with you, but that is very unpredictable, depends on the type of task. As a rule of thumb, I never use service connections and environments in variable groups.

But a workaround exists! Instead of using vargroups, you can use variables with static values in your main pipeline (which can later call as many templates as you like) or even use a "variable file" that will work just like an variable group, an external yaml template that contains those variables and its values. So, by doing this, you can keep these parameters in a single place, without having to look for them on every pipelines and templates in your solution.

Here's the most basic example:

main_pipeline.yml:

variables:
  - service_connection: my-service-connection-name
  - environment: Production

jobs:
  - deployment: JOB_DEPLOY
    environment: ${{ variables.environment }}
    strategy:
      runOnce:
        deploy:
          steps:
            - task: AzurePowerShell@5
              inputs:
                azureSubscription: '${{ variables.service_connection }}'
                ScriptType: 'FilePath'
                ScriptPath: '$(Build.Repository.LocalPath)/my_script.ps1'

You could also point to an external variable template:

main_pipeline.yml:

variables:
  - template: project-settings.yml@self

jobs:
  - deployment: JOB_DEPLOY
    environment: ${{ variables.environment }}
    strategy:
      runOnce:
        deploy:
          steps:
            - task: AzurePowerShell@5
              inputs:
                azureSubscription: '${{ variables.service_connection }}'
                ScriptType: 'FilePath'
                ScriptPath: '$(Build.Repository.LocalPath)/my_script.ps1'

project-settings.yml:

variables:
  - name: service_connection
    value: my-service-connection-name
  - name: environment
    value: Production

Both examples will work the same way. The important thing is to have the static values in a file, and use what is called "template expression" syntax (the ${{ }}). The reason for this is because template expressions get processed before running the pipeline, and at that time, only static values are available to the system. This makes those service connections and environments be able to get values for the variables at the time they need it.

0
votes

Variable group yaml variable expression in Azure Devops Pipeline

It should be work with $(var). Try to check following test yaml file:

Main Yaml:

trigger:
- master

variables:
- group: Test2

pool:
  vmImage: 'windows-latest'

stages:

- template: azure-pipelines.yml

The template azure-pipelines.yml:

stages:
- stage: Test

  dependsOn: []

  jobs:

  - job: Test

    steps:

    - task: AzureKeyVault@1
      inputs:
        azureSubscription: $(spn_kv_app)
        KeyVaultName: $(keyVaultName)
        SecretsFilter: '*'

And my Variables Group:

enter image description here

As the test result:

enter image description here

So, it works fine on my side. Please check your Variables Group name and the name of the Variables.

Hope this helps.