在 NuGet 还原期间使用自签名 SSL 证书且“无法获取本地颁发者证书”时,Azure DevOps Server 管道构建失败

问题描述 投票:0回答:3

升级到 Azure DevOps Server 2019 后,自动化管道构建在 NuGet 恢复步骤中失败,显示:

错误:错误:无法获取本地颁发者证书

包恢复失败

Microsoft 的文档指出在 Windows 上运行的构建代理使用 Windows 证书存储,因此我检查了构建服务器上是否正确安装了所需的证书,但它仍然失败。

有很多问题具有类似的症状,但原因并不相同。经过调查,我找到了解决方案,但我没有发现任何关于这个确切问题的内容,所以我将发布一个答案,希望能节省其他人一些时间!

ssl-certificate azure-pipelines nuget-package-restore azure-devops-server-2019
3个回答
15
投票

事实证明,Azure DevOps 构建代理正在使用不使用 Windows 证书存储的 Node.js 版本。

所需的解决方案是以 PEM 格式导出服务器 TLS 证书的根 CA 证书的副本,并使用名为

NODE_EXTRA_CA_CERTS
的系统环境变量或使用名为
NODE.EXTRA.CA.CERTS
NODE_EXTRA_CA_CERTS
的任务变量 其值指向导出的 PEM 证书。这样,这个旧版本的 NodeJS 将获取该证书,从而能够验证服务器的证书链。

开发者社区问题链接


13
投票

我使用带有以下脚本的 PowerShell 代理作业。这有效地为管道的 Node.JS 提供了“使用 Windows 计算机证书存储”选项。

一些注意事项:

  • 使用ProcMon监控node.exe表明每次运行管道时都会读取

    NODE_EXTRA_CA_CERTS
    中引用的文件。然而,其他人建议运行
    Restart-Service vstsagent* -Force
    才能使更改生效。这不是我的经验,但也许环境之间的不同会导致这种行为。

  • 这会额外增加约 1 秒的管道执行时间。对于“Windows 上管道中的节点的设置和忘记证书管理”来说,这可能是一个可以接受的价格,但仍然值得注意。

# If running in a pipeline then use the Agent Home directory,
# otherwise use the machine temp folder which is useful for testing
if ($env:AGENT_HOMEDIRECTORY -ne $null) { $TargetFolder = $env:AGENT_HOMEDIRECTORY }
else { $TargetFolder = [System.Environment]::GetEnvironmentVariable('TEMP','Machine') }

# Loop through each CA in the machine store
Get-ChildItem -Path Cert:\LocalMachine\CA | ForEach-Object {

    # Convert cert's bytes to Base64-encoded text and add begin/end markers
    $Cert = "-----BEGIN CERTIFICATE-----`n"
    $Cert+= $([System.Convert]::ToBase64String($_.export([System.Security.Cryptography.X509Certificates.X509ContentType]::Cert),'InsertLineBreaks'))
    $Cert+= "`n-----END CERTIFICATE-----`n"

    # Append cert to chain
    $Chain+= $Cert
}

# Build target path
$CertFile = "$TargetFolder\TrustedRootCAs.pem"

# Write to file system
$Chain | Out-File $CertFile -Force -Encoding ASCII

# Clean-up
$Chain = $null

# Let Node (running later in the pipeline) know from where to read certs
Write-Host "##vso[task.setvariable variable=NODE.EXTRA.CA.CERTS]$CertFile"

1
投票

我格式化了来自 @alifen 的 PowerShell 脚本。下面的脚本可以在构建代理本身上执行。它采用目标路径参数并在服务器上设置环境变量。

感谢@alifen


[CmdletBinding()]
param (
    [Parameter()]
    [string]
    $TargetFolder = "$env:SystemDrive\Certs"
)
If (-not(Test-Path $TargetFolder))
{
    $null = New-Item -ItemType Directory -Path $TargetFolder -Force
}
# Loop through each CA in the machine store
Get-ChildItem -Path Cert:\LocalMachine\CA | ForEach-Object {

    # Convert cert's bytes to Base64-encoded text and add begin/end markers
    $Cert = "-----BEGIN CERTIFICATE-----`n"
    $Cert += $([System.Convert]::ToBase64String($_.export([System.Security.Cryptography.X509Certificates.X509ContentType]::Cert), 'InsertLineBreaks'))
    $Cert += "`n-----END CERTIFICATE-----`n"

    # Append cert to chain
    $Chain += $Cert
}

# Build target path
$CertFile = "$TargetFolder\TrustedRootCAs.pem"

# Write to file system
Write-Host "[$($MyInvocation.MyCommand.Name)]: Exporting certs to: [$CertFile]"
$Chain | Out-File $CertFile -Force -Encoding ASCII

# Set Environment variable
Write-Host "[$($MyInvocation.MyCommand.Name)]: Setting environment variable [NODE_EXTRA_CA_CERTS] to [$CertFile]"
[Environment]::SetEnvironmentVariable("NODE_EXTRA_CA_CERTS", "$CertFile", "Machine")

© www.soinside.com 2019 - 2024. All rights reserved.