[英]Azure build pipeline: Is it possible to sign an MSIX within the VSBuild task using a code signing certificate stored in the Key Vault?
当使用代码签名证书 (*.PFX) 时,我能够在 VSBuild 任务中签署 MSIX 文件,该证书从 Build Pipeline 的库部分存储为安全文件,使用以下设置(为简洁起见被截断):
注意:关键是我们如何分配p:PackageCertificateKeyFile
参数。
- task: AzureKeyVault@2
inputs:
azureSubscription: 'Dev (SomeGuid)'
KeyVaultName: 'SomeKeyVault'
SecretsFilter: 'SomeCertPassword'
RunAsPreJob: false
- task: DownloadSecureFile@1
name: signingCert
inputs:
secureFile: 'SomeCertName.pfx'
- task: VSBuild@1
inputs:
platform: '$(buildPlatform)'
solution: '$(solution)'
configuration: '$(buildConfiguration)'
msbuildArgs: '
/p:AppInstallerUri=$(msixInstallUrl)
/p:AppxBundle=Never
/p:AppxBundlePlatforms="$(buildPlatform)"
/p:AppxPackageDir="$(Build.ArtifactStagingDirectory)/"
/p:AppxPackageSigningEnabled=true
/p:GenerateAppInstallerFile=true
/p:PackageCertificateThumbprint=""
/p:PackageCertificateKeyFile="$(signingCert.secureFilePath)"
/p:PackageCertificatePassword="$(SomeCertPassword)"
/p:UapAppxPackageBuildMode=SideLoadOnly
'
但是,作为将代码签名证书存储在管道库的安全文件部分的替代方法,我想将它存储在 Key Vault 的证书部分,然后在AzureKeyVault
任务中检索它。 所以,YAML 看起来像这样(为简洁起见被截断):
- task: AzureKeyVault@2
inputs:
azureSubscription: 'Dev (SomeGuid)'
KeyVaultName: 'SomeKeyVault'
SecretsFilter: 'SomeCertName,SomeCertPassword'
RunAsPreJob: false
- task: VSBuild@1
inputs:
platform: '$(buildPlatform)'
solution: '$(solution)'
configuration: '$(buildConfiguration)'
msbuildArgs: '
/p:AppInstallerUri=$(msixInstallUrl)
/p:AppxBundle=Never
/p:AppxBundlePlatforms="$(buildPlatform)"
/p:AppxPackageDir="$(Build.ArtifactStagingDirectory)/"
/p:AppxPackageSigningEnabled=true
/p:GenerateAppInstallerFile=true
/p:PackageCertificateThumbprint=""
/p:PackageCertificateKeyFile="$(SomeCertName)"
/p:PackageCertificatePassword="$(SomeCertPassword)"
/p:UapAppxPackageBuildMode=SideLoadOnly
'
想要这样做的原因是因为当我尝试运行单独的MSIX Code Signing
任务时,我cannot find *.appinstaller
文件。 在同一个构建任务中签署包似乎更简单、更容易。
但是,我收到以下错误:
错误 APPX0104:未找到证书文件“***”。 C:\\Program Files (x86)\\Microsoft Visual
据我所知,当从AzureKeyVault
任务变量中检索证书文件时,它存储为字符串而不是文件。 但是,MSBuild 任务需要一个文件。 我尝试在整个网络上搜索并尝试了一些 Powershell 脚本将导入的AzureKeyVault
任务变量从字符串转换为 base64,但我没有运气(请参阅下面的链接以供参考)。 我实际上已经尝试了大约 40 种不同的方法来做到这一点,我担心尝试列出它们只会混淆这个问题。 因此,我觉得最好提出我正在尝试做的事情并询问它是否可能,如果是,如何?
我能够通过将MSIX Packaging扩展安装到我的 Azure 订阅来解决这个问题,如下所述: https : //docs.microsoft.com/en-us/windows/msix/desktop/msix-packaging-extension?tabs=yaml
此扩展非常有用,因为与Azure 签名工具 (AST)非常相似,它似乎是此方法的唯一替代方法,它处理代码签名证书string
到base64
的转换,然后对包进行签名。 显然,引擎盖下有很多事情要做。 您需要配置构建管道才能访问密钥保管库。 但是,与AST不同的是,此扩展更易于使用,因为它不需要AST所需的所有配置。 这是因为AST处理从Key Vault检索代码签名证书的任务,而在我的实现中,我只使用Azure Key Vault任务将文件拉入我的构建管道,这也很容易设置和实现。 在我看来, AST太复杂而没有用。
下面是我使用的完整实现,它还参数化了通过我们的订阅/环境存储各种代码签名证书的 Key Vault。
trigger:
branches:
include:
- refs/heads/main
- refs/heads/demo
- refs/heads/develop
# The following is for testing purposes only. For now we disable automatically building for commits to feature branches in develop.
# - refs/heads/feature*
pool:
vmImage: 'windows-latest'
# Variable Declaration(s)
# Note: We must use the name/value combination because we are (dynamically) mixing in variable groups.
variables:
- name: buildPlatform
value: 'x64'
- name: buildConfiguration
value: 'Release'
- name: major
value: 1
- name: minor
value: 0
- name: build
value: 0
- name: revision
value: $[counter('rev', 0)]
# Set conditional variable group based off of the trigger branch (see trigger section above).
# Note: If we use SourceBranch then it will append `refs/heads/` to the SourceBranchName.
- ${{ if eq(variables['build.SourceBranch'], 'refs/heads/main') }}:
- group: PROD
- ${{ if eq(variables['build.SourceBranch'], 'refs/heads/qa') }}:
- group: QA
- ${{ if eq(variables['build.SourceBranch'], 'refs/heads/develop') }}:
- group: DEV
# The following is for testing purposes only.
# Note: If you want to run for a feature branch in develop then you must uncomment this line. Otherwise, you will get an error that the pipeline is not valid.
# "Step AzureKeyVault input ConnectedServiceName references service connection $(azureSubscription) which could not be found."
- ${{ if contains(variables['Build.SourceBranch'], 'refs/heads/feature') }}:
- group: DEV
steps:
# Update the AppXManifest file's major, minor, build, and revision parameters with the current values.
# Note: We use the day's build counter to determine the revision number.
# By rule, this counter is limited to 255 values per day and will start over at 1!
- powershell: |
[Reflection.Assembly]::LoadWithPartialName("System.Xml.Linq")
$path = "SomeAppName.MsixInstaller/Package.appxmanifest";
$doc = [System.Xml.Linq.XDocument]::Load($path);
$xName = [System.Xml.Linq.XName]::Get("{http://schemas.microsoft.com/appx/manifest/foundation/windows10}Identity");
$doc.Root.Element($xName).Attribute("Version").Value = "$(major).$(minor).$(build).$(revision)";
$doc.Save($path);
displayName: 'Version the Package Manifest'
# Retrieve the code signing certificate from the Key Vault.
# Note: 20211008 - Ignore the errors because the values are correct.
- task: AzureKeyVault@2
displayName: 'Azure Key Vault: Retrieve Variable(s)'
inputs:
azureSubscription: '$(azureSubscription)'
KeyVaultName: '$(keyVaultName)'
SecretsFilter: 'SomeCertName'
RunAsPreJob: false
# Specify the minimum version of NuGet that we want to use to restore the solution's NuGet packages.
- task: NuGetToolInstaller@1
displayName: 'NuGet: Use v5.11.0'
inputs:
versionSpec: 5.11.0
checkLatest: true
# Run NuGet restore to download the NuGet packages before building the solution.
- task: NuGetCommand@2
displayName: 'NuGet: Run restore'
inputs:
command: 'restore'
restoreSolution: '**/*.sln'
# Build the MSIX package.
# Note: Set AppxPackageSigningEnabled=false to avoid a build error (i.e., missing thumbprint). We will sign the package in a subsequent step.
- task: VSBuild@1
displayName: 'VSBuild: Build the MSIX package'
inputs:
clean: true
configuration: '$(buildConfiguration)'
platform: '$(buildPlatform)'
restoreNugetPackages: false #adding this because we're doing an explicit restore above, lets skip the implicit restore.
solution: '**/*.sln'
msbuildArgs: '
/p:AppInstallerUri="$(appServiceUri)"
/p:AppxPackageDir="$(Build.ArtifactStagingDirectory)/"
/p:AppxBundle=Never
/p:AppxBundlePlatforms="$(buildPlatform)"
/p:UapAppxPackageBuildMode=SideLoadOnly
/p:GenerateAppInstallerFile=true
/p:AppxPackageSigningEnabled=false
'
# Sign the MSIX package with the code signing certificate from the Key Vault.
- task: MsixSigning@1
displayName: 'Code Sign MSIX Package'
inputs:
package: '$(Build.ArtifactStagingDirectory)\**\*.msix'
certificateType: 'base64'
encodedCertificate: '$(DeveloperCodeSigningCertFile)'
continueOnError: true
# Publish the MSIX package in preparation for deployment. This will be consumed by the Release Pipeline.
- task: PublishBuildArtifacts@1
displayName: 'Publish ArtifactName: drop'
inputs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)'
ArtifactName: 'drop'
publishLocation: 'Container'
# Run tests (if any).
# Note: This tests sources that are found matching the given filter '**\*test*.dll,!**\*TestAdapter.dll,!**\obj\**
- task: VSTest@2
displayName: 'VSTest: Run Tests (if any)'
inputs:
platform: '$(buildPlatform)'
configuration: '$(buildConfiguration)'
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.