如何在Azure DevOps流水线中使用AzureSignTool签名DLL?
问题描述
我需要在DLL构建完成后,使用Azure Key Vault中的证书对其进行签名。我的csproj文件中包含如下构建后任务:
<Target Name="AzureSignTool" AfterTargets="Build"> <Message Importance="High" Text="Running azuresigntool." /> <Exec Command="azuresigntool sign --azure-key-vault-tenant-id "$(AzureSignTool_TenantId)" -kvu $(AzureSignTool_KeyVaultUrl) -kvi $(AzureSignTool_ClientId) -kvs $(AzureSignTool_ClientSecret) -kvc CodeSigningCert "$(ProjectDir)$(OutDir)$(TargetFileName)"" /> <!-- Parameters provided from pipeline 'library'. --> </Target>
该任务在本地环境可正常运行(参数值来自环境变量),但在Azure DevOps构建流水线中执行时失败,报错:
Client address is not authorized and caller is not a trusted service
根据资料,解决方案是将构建服务器的IP地址添加到Key Vault的防火墙规则中。我编写了如下流水线步骤,但在配置Azure CLI任务的服务连接时遇到问题:
steps: - task: DotNetCoreCLI@2 inputs: command: 'custom' custom: 'tool' arguments: 'install --global azuresigntool' displayName: Install AzureSignTool # 该任务用于将Azure DevOps代理的IP添加到Key Vault防火墙规则 - task: AzureCLI@2 displayName: Add Agent IP From Key Vault condition: succeededOrFailed() # 无论之前任务成功或失败都运行 inputs: azureSubscription: 'Libraries-335d6548-abdc-4fd4-b313-e8c7ab8357c6' #${{ parameters.keyVaultArmSvcConnectionName }} 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' # 该任务用于将Azure DevOps代理的IP从Key Vault防火墙规则中移除 - task: AzureCLI@2 displayName: Remove Agent IP From Key Vault condition: succeededOrFailed() inputs: azureSubscription: 'Libraries-335d6548-abdc-4fd4-b313-e8c7ab8357c6' #${{ parameters.keyVaultArmSvcConnectionName }} 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
尝试了Azure订阅ID、Azure DevOps中显示的服务连接名称、AAD中显示的服务连接名称、AAD中的服务连接ID等作为azureSubscription的值,均无效,构建报错:
There was a resource authorization issue: "The pipeline is not valid. Job Job: Step AzureCLI1 input connectedServiceNameARM references service connection
whatever-I-put-for-azureSubscriptionwhich 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
请问是否可以在Azure DevOps流水线中运行AzureSignTool?具体该如何操作?
解决方案
1. 正确配置Azure DevOps服务连接
azureSubscription字段必须填写Azure DevOps中已创建并授权的服务连接的显示名称,操作步骤:
- 进入Azure DevOps项目,依次点击
项目设置→服务连接→新建服务连接 - 选择
Azure Resource Manager类型,按向导完成配置(关联目标Azure订阅) - 服务连接创建后,复制其显示名称,填入流水线YAML的
azureSubscription字段 - 进入服务连接的
安全性设置,授权当前流水线或项目使用该连接
2. 优化流水线步骤
(1)确保AzureSignTool可被调用
全局安装的工具可能不在代理PATH中,建议改为本地安装:
- task: DotNetCoreCLI@2 inputs: command: 'custom' custom: 'tool' arguments: 'install azuresigntool --tool-path $(Agent.TempDirectory)' displayName: Install AzureSignTool
后续调用时使用$(Agent.TempDirectory)/azuresigntool作为命令路径。
(2)调整Key Vault防火墙规则操作逻辑
- 若代理在公网环境,保留
curl https://checkip.amazonaws.com获取公网IP;若在私有网络,需确保Key Vault防火墙允许代理内网IP段 - 为服务连接的主体授予Key Vault的Key Vault Network Administrator权限,确保能修改网络规则
(3)将签名步骤移至流水线(可选)
避免csproj依赖环境变量,直接在流水线中执行签名:
- task: PowerShell@2 displayName: Sign DLL with AzureSignTool inputs: targetType: 'inline' script: | $(Agent.TempDirectory)/azuresigntool sign ` --azure-key-vault-tenant-id $(AzureSignTool_TenantId) ` --azure-key-vault-url $(AzureSignTool_KeyVaultUrl) ` --azure-key-vault-client-id $(AzureSignTool_ClientId) ` --azure-key-vault-client-secret $(AzureSignTool_ClientSecret) ` --azure-key-vault-certificate CodeSigningCert ` $(Build.ArtifactStagingDirectory)/**/*.dll
其中$(AzureSignTool_*)变量通过流水线的变量组或秘密变量配置。
3. 替代方案:使用托管标识访问Key Vault
若使用Azure托管代理,可配置托管标识访问Key Vault,无需添加IP防火墙规则:
- 为Azure DevOps项目的托管标识授予Key Vault的Certificate User和Key User权限
- 修改AzureSignTool命令,使用托管标识认证:
azuresigntool sign --azure-key-vault-tenant-id $(TenantId) -kvu $(KeyVaultUrl) -kvc CodeSigningCert --azure-key-vault-managed-identity $(TargetFileName)
内容的提问来源于stack exchange,提问作者Richard Barraclough

