Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use different Service Connection for every stage in Azure Pipelines?

When using multistage pipelines from yaml in Azure Pipelines and every stage is deploying resources to a separate environment, I'd like to use a dedicated service connection for each stage. In my case every stage is making use of the same deployment jobs, i.e. yaml templates. So I'm using a lot of variables that have specific values dependent on the environment. This works fine, except for the service connection.

Ideally, the variable that contains the service connection name, is added to the stage level like this:

stages:
- stage: Build
    # (Several build-stage specific jobs here)

- stage: DeployToDEV
  dependsOn: Build
  condition: succeeded()
  variables:
    AzureServiceConnection: 'AzureSubscription_DEV' # This seems like a logical solution
  jobs:
    # This job would ideally reside in a yaml template
    - job: DisplayDiagnostics
      pool:
        vmImage: 'Ubuntu-16.04'
      steps:
        - checkout: none
        - task: AzurePowerShell@4
          inputs:
            azureSubscription: $(AzureServiceConnection)
            scriptType: inlineScript
            inline: |
              Get-AzContext
            azurePowerShellVersion: LatestVersion

- stage: DeployToTST
  dependsOn: Build
  condition: succeeded()
  variables:
    AzureServiceConnection: 'AzureSubscription_TST' # Same variable, different value
  jobs:
    # (Same contents as DeployToDEV stage)

When this code snippet is executed, it results in the error message:

There was a resource authorization issue: "The pipeline is not valid. Job DisplayDiagnostics: Step AzurePowerShell input ConnectedServiceNameARM references service connection $(AzureServiceConnection) which could not be found. The service connection does not exist or has not been authorized for use. For authorization details, refer to https://aka.ms/yamlauthz.

So, it probably can't expand the variable AzureServiceConnection soon enough when the run is started. But if that's indeed the case, then what's the alternative solution to make use of separate service connections for every stage?

One option that works for sure is setting the service connection name directly to all tasks, but that would involve duplicating identical yaml tasks for every stage, which I obviously want to avoid.

Anyone has a clue on this? Thanks in advance!

like image 565
Herman Cordes Avatar asked Aug 16 '19 06:08

Herman Cordes


People also ask

How do I provide access to service connection in Azure DevOps?

In Azure DevOps, open the Service connections page from the project settings page. In TFS, open the Services page from the "settings" icon in the top menu bar. Choose + New service connection and select Azure Resource Manager. Choose Service Principal (manual) option and enter the Service Principal details.

How do I create a generic service connection in Azure DevOps?

Create a service connectionSign in to your organization ( https://dev.azure.com/{yourorganization} ) and select your project. Select Project settings > Service connections. Select + New service connection, select the type of service connection that you need, and then select Next.

What is the function of service connections in Azure DevOps?

A service connection, in simple terms, is a defined connection that allows Azure DevOps to communicate with an external service.

What is the difference between service principal and service connection?

What is the difference between Service Principal (automatic) and Service Principal (manual) ? Service Principal (automatic) : It will create an AD App along with the service principal in Azure AD for you automatically and use it in the service connection.


1 Answers

Currently you can not pass a variable as a serviceConnection. Apparently the service connection name is picked up on push/commit and whatever that is there will be picked up.

E.g. if you have a $(variable) it will pick $(variable) instead of the value.

Workaround I have used so far is to use a template for the steps at each stage and pass a different parameter with the serviceConnection.

Refer: https://github.com/venura9/azure-devops-yaml/blob/master/azure-pipelines.yml for a sample implementation. you are more than welcome to pull request with updates.

- stage: DEV
  displayName: 'DEV(CD)'
  condition: and(succeeded('BLD'), eq(variables['Build.SourceBranch'], 'refs/heads/develop'))
  dependsOn: 
   - BLD
  variables: 
    stage: 'dev'
  jobs:

  - job: Primary_AustraliaSouthEast
    pool:
      vmImage: $(vmImage)
    steps:
    - template: 'pipelines/infrastructure/deploy.yml'
      parameters: {type: 'primary', spn: 'SuperServicePrincipal', location: 'australiasoutheast'}
    - template: 'pipelines/application/deploy.yml'
      parameters: {type: 'primary', spn: 'SuperServicePrincipal'}
like image 58
Venura Athukorala Avatar answered Oct 30 '22 22:10

Venura Athukorala