繁体   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