[英]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.