簡體   English   中英

Azure 構建管道:是否可以使用存儲在 Key Vault 中的代碼簽名證書在 VSBuild 任務中簽署 MSIX?

[英]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)非常相似,它似乎是此方法的唯一替代方法,它處理代碼簽名證書stringbase64的轉換,然后對包進行簽名。 顯然,引擎蓋下有很多事情要做。 您需要配置構建管道才能訪問密鑰保管庫。 但是,與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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM