Search code examples
azure-devopsazure-keyvault

Using azuresigntool in an Azure DevOps pipeline


I need to use a certificate in a keyvault to sign my DLL after its built.

The cproj contains the post build task

  <Target Name="AzureSignTool" AfterTargets="Build">
    <Message Importance="High" Text="Running azuresigntool." />
    <Exec Command="azuresigntool sign --azure-key-vault-tenant-id &quot;$(AzureSignTool_TenantId)&quot; -kvu $(AzureSignTool_KeyVaultUrl) -kvi $(AzureSignTool_ClientId) -kvs $(AzureSignTool_ClientSecret) -kvc CodeSigningCert &quot;$(ProjectDir)$(OutDir)$(TargetFileName)&quot;" />
    <!-- Parameters provided from pipeline 'library'. -->
  </Target>

which is working locally where the parameter values are environment variables.

The next step is to get it to work in the Azure DevOps build pipeline.

The variables are set in a pipeline library and added using

variables:
  - group: azuresigntool

Now in the pipeline the azuresigntool runs with the parameter values but fails because Client address is not authorized and caller is not a trusted service. The solution (from https://luke.geek.nz/azure/accessing-keyvault-azure-devops/) is to add the IP address of the build server to the keyvault's firewall.

This is how far I've got

steps:
- task: DotNetCoreCLI@2
  inputs:
    command: 'custom'
    custom: 'tool'
    arguments: 'install --global azuresigntool'
  displayName: Install AzureSignTool

# https://luke.geek.nz/azure/accessing-keyvault-azure-devops/
# This task uses Azure CLI to add the IP address of the Azure DevOps agent to the firewall of an Azure Key Vault.
- task: AzureCLI@2
  displayName: Add Agent IP From Key Vault
  condition: succeededOrFailed()  # This task will run regardless of whether previous tasks have succeeded or failed.
  inputs:
    azureSubscription: 'Libraries-335d6548-abdc-4fd4-b313-e8c7ab8357c6' #${{ parameters.keyVaultArmSvcConnectionName }}  # The Azure subscription that the task should use. The value is taken from the keyVaultArmSvcConnectionName parameter.
    scriptType: bash
    scriptLocation: inlineScript
    inlineScript: |
      agentIP=$(curl -s https://checkip.amazonaws.com)
      echo "Agent IP: $agentIP"
      az keyvault network-rule add --name "prestwoodsoftware" --ip-address "$agentIP" --only-show-errors

- template: BuildTestPack.yml@AzurePipelineTemplates
  parameters:
    solution: 'Libraries.DllThatNeedsToBeSigned.sln'

# This task uses Azure CLI to remove the IP address of the Azure DevOps agent from the firewall of an Azure Key Vault.
- task: AzureCLI@2
  displayName: Remove Agent IP From Key Vault
  condition: succeededOrFailed()
  inputs:
    azureSubscription: 'Libraries-335d6548-abdc-4fd4-b313-e8c7ab8357c6' #${{ parameters.keyVaultArmSvcConnectionName }}  # The Azure subscription that the task should use. The value is taken from the keyVaultArmSvcConnectionName parameter.
    scriptType: bash
    scriptLocation: inlineScript
    inlineScript: |
      agentIP=$(curl -s https://checkip.amazonaws.com)
      echo "Agent IP: $agentIP"
      az keyvault network-rule remove --name "prestwoodsoftware" --ip-address "$agentIP" --only-show-errors

I think the problem is getting the Azure agent to authorise for az. How is that supposed to work?

There is no such thing as ${{ parameters.keyVaultArmSvcConnectionName }} and it's unclear what it's supposed to be. I have tried

  • the ID of my azure subscription,
  • the name of the service connection as it appears in AzureDevOps,
  • the name of the service conneciton as it appears in AAD,
  • the ID of the service connection in AAD. But none of these work.

In each case the build fails saying

There was a resource authorization issue: "The pipeline is not valid. Job Job: Step AzureCLI1 input connectedServiceNameARM references service connection whatever-I-put-for-azureSubscription which could not be found. The service connection does not exist, has been disabled or has not been authorized for use. For authorization details, refer to https://aka.ms/yamlauthz.

Is it possible to run azuresigntool in an Azure DevOps pipeline? How?


Solution

  • The ${{ parameters.keyVaultArmSvcConnectionName }} is the Azure Resource Manager type service connection(ARM service connection) in your DevOps project.

    If you follow the same format ${{ parameters.XXX}}, you need to define the service connection name as parameter at the top of your pipeline YAML.

    parameters:
    - name: keyVaultArmSvcConnectionName
      value:YourARMConnservice           # your ARM service connection name.
    

    But you can also directly type the service connection name in yaml AzureCLI task as you do now, which means not using parameter.

    The last error indicates the ARM service connection is not created, or you are not authorized to use it.

    Please follow below steps:

    1. Go to project settings -> Pipelines -> Service connections, check if the ARM service connection exists, and confirm the name is same within pipeline. Create the connection if it doesn't exist.

    2. If it exists, go to the failed build result, you could see an option to authorize the resources. You can select this option and authorize the resource on the failed build. Once the resource is authorized, you can start a new build. Check the doc for the details.

    The two AzureCLi tasks automatically detect the DevOps agent IP and add/remove it to key vault whitelist, ensure agent can access the key vault.

    In addition, you are defining secret type variables in Variable group group: azuresigntool, please note they are not mapped as environment variables in your pipeline, only non-secret type variables will be automatically mapped as environment. You can consider to use script/powershell task directly with AzureSignTool command instead of post build task:

    - powershell: '& AzureSignTool sign --azure-key-vault-tenant-id $(AzureSignTool_TenantId) -kvu $(AzureSignTool_KeyVaultUrl) -kvi $(AzureSignTool_ClientId) -kvs $(AzureSignTool_ClientSecret) -kvc CodeSigningCert "$(ProjectDir)$(OutDir)$(TargetFileName)'
      displayName: 'Sign the file'
    

    Please refer to the link and link for your reference.