Search code examples
azureazure-devopsazure-pipelinesazure-pipelines-yamlserviceconnection

dynamically using a Service Connection in an Azure DevOps pipeline based on the calling repository


I have an Azure DevOps pipeline setup with YAML templates shared across multiple repositories. Specifically, I have:

  1. A YAML template file named kv_template.yaml in Repo1 (Project1). This template runs an Azure CLI task that requires a service connection to authenticate with Azure.
  2. Service Connection 1 is configured for Project1 and is used by kv_template.yaml when run directly in Repo1.
  3. Service Connection 2 is configured for Project2 and should be used when kv_template.yaml is called by a pipeline in Repo2 (Project2).

I’ve considered Sharing multiple Service Connections in the Repository where kv_template.yaml is saved, but I’m not sure of the best way to detect or pass which repository/project is calling kv_template.yaml. My ideal solution would dynamically use Service Connection 1 when kv_template.yaml is called within Repo1 and Service Connection 2 when called within Repo2.

My objective is to have kv_template.yaml dynamically select the appropriate service connection based on which repository/pipeline is calling it, without needing to hardcode or duplicate the template file.

Is there a way in Azure DevOps YAML to detect the calling repository or project and use the appropriate Service Connection?

kv_template.yaml script:

- name: parameter1
  type: string
- name: parameter2
  type: string

jobs:
  - job: Job1
    steps:
      - checkout: self
      - task: AzureCLI@2
        inputs:
          azureSubscription: '$(SERVICE_CONNECTION_1)'
          scriptType: 'pscore'
          scriptLocation: 'scriptPath'
          scriptPath: 'helper_scripts/script.ps1'
          arguments: '-WebhookURL "${{ parameters.parameter1 }}" -KeyVaultsToCheck "${{ parameters.parameter2 }}"'
        env:
          GLOBAL_SUBSCRIPTION: $(GLOBAL_SUBSCRIPTION) 
    

Solution

  • My objective is to have kv_template.yaml dynamically select the appropriate service connection based on which repository/pipeline is calling it, without needing to hardcode or duplicate the template file.

    I don't have enough context to understand how the template is being used, but if you're referencing the template in different pipelines have you considered replacing the pipeline variable with a parameter for the service connection?

    parameters:
    - name: azureSubscription
      type: string
    
      # other parameters here
    
    jobs:
      - job: Job1
        steps:
          - checkout: self
          - task: AzureCLI@2
            inputs:
              azureSubscription: ${{ parameters.azureSubscription }}
              # ...
    

    Removing the dependency on the pipeline variable improves the reusability of the template IMO.

    I’m not sure of the best way to detect or pass which repository/project is calling kv_template.yaml

    Take a look into the predefined variables.

    Some of these can be used to dynamically load a variables template using template expressions:

    jobs:
      - job: Job1
        variables:
          # reference variables template for the specified project
          - template: /pipelines/variables/${{ variables['System.TeamProject'] }}-variables.yaml
        steps:
          - checkout: self
          - task: AzureCLI@2
            inputs:
              azureSubscription: $(SERVICE_CONNECTION)
              # ...
    

    This means each project would have its own variable templates:

    # /pipelines/variables/foo-variables.yaml
    # variables for project foo
    
    variables:
      - name: SERVICE_CONNECTION
        value: fooServiceConnection
    
      # other variables here
    

    A simpler approach would be to use a condition instead:

    variables:
      ${{ if eq(variables['System.TeamProject'], 'foo') }}:
        SERVICE_CONNECTION: fooServiceConnection
      ${{ elseif eq(variables['System.TeamProject'], 'bar') }}:
        SERVICE_CONNECTION: barServiceConnection
    

    Or, as an alternative:

    variables:
      SERVICE_CONNECTION: ${{ variables['System.TeamProject'] }}ServiceConnection
    
      # result:
      # SERVICE_CONNECTION: fooServiceConnection
    

    Please note that not all predefined variables are available in template expressions (${{ ... }}). For example, the above workarounds work when using variables such as System.TeamProject or Build.SourceBranch but won't work for Build.Repository.Name (not available at compile time).

    Please see the Available in templates? column in predefined variables to check which variables can be used in template expressions (i.e. at compile time).