如何使用 Azure Key Vault 中的证书/密钥对使用 Azure Pipelines 构建的代码进行签名?

Posted

技术标签:

【中文标题】如何使用 Azure Key Vault 中的证书/密钥对使用 Azure Pipelines 构建的代码进行签名?【英文标题】:How to sign code built using Azure Pipelines using a certificate/key in Azure Key Vault? 【发布时间】:2019-12-19 20:34:02 【问题描述】:

我们正在从本地构建服务器迁移到 Azure Pipelines。我们生产“shrink-wrap”桌面软件,因此很明显我们需要在发布之前对所有二进制文件进行签名。我们当前的构建基础架构使用来自 GlobalSign 的 USB 硬件令牌来执行此操作,但很明显,当我们进行云构建时,这将不起作用 - 遗憾的是,云没有配备 USB 端口:D

现在,GlobalSign 最近开始将 advertising Azure Key Vault 作为密钥存储选项,他们非常乐意将其出售给我们,但我不确定我们如何将其与我们的构建管道实际集成(或者实际上这是否可能)。

真的有人做过这个吗?

【问题讨论】:

【参考方案1】:

代码签名

我一直在使用 Azure Key Vault 和 Azure Pipelines 来获得我们的代码签名,并且成功了。所以这就是我发现的。

至关重要的是,用于代码签名的扩展验证 (EV) 证书与“普通”SSL 证书截然不同。标准的可以任意导出,这意味着您可以将其上传到 Azure Pipelines 并与标准的 Microsoft 签名工具一起使用。

但是,一旦 EV 证书在 Azure Key Vault 中,它就不会以任何通常的方式出现。您必须使用 Anodyne above 发现的出色的 Azure Sign Tool 从 Pipelines 调用它

将您的证书放入 Key Vault。您可以使用任何您喜欢的证书颁发机构来生成证书,只要他们知道您需要 EV 证书,并且最重要的是具有硬件安全模块 (HSM) 的证书>不是带有物理 USB 密钥的。任何基于云的系统(如 Key Vault)都需要 HSM 版本。

要获得从外部访问此证书的权限,您可以follow this page 但注意它错过了一步。因此,请先阅读该文档,然后阅读这些总结步骤,以设置 Key Vault:

    打开 Azure 门户,转到 Azure Active Directory 区域,并创建一个 App registration:输入一个好记的名称,忽略 Redirect URI,并保存它。 转到您的特定Key Vault,然后是Access control (IAM),然后是Add role assignment。在select 输入框中键入您刚刚创建的应用程序的名称。也选择一个Role,我建议Reader然后保存。 缺失的部分: 仍在 Key Vault 中,单击 Access policies 菜单项。单击Add Access Policy 并添加您的应用程序。 Certificate Permissions 需要勾选 Get。而Key Permissions,尽管您在这个保管库中可能根本没有任何密钥,但需要有GetSign。你会认为这两个会在证书许可中...... 返回到您刚刚创建的应用程序。选择Certificates & secrets,然后选择上传证书(一个纯粹用于远程访问 Key Vault 的新证书)或创建client secret。如果是后者,请保留密码的副本,您将不会再看到它! 在应用程序的Overview 部分将是Application (client) ID。这以及密码或证书将在稍后的 Pipelines 任务中提供给 Azure 签名工具。

处理来自 Azure 的实际代码签名需要多个步骤。以下内容适用于 Microsoft 托管代理,但类似问题会影响您拥有的任何私有代理。

    Azure 签名工具需要安装 .NET Core SDK,但版本至少为 2.x,并且由于 最新 .NET Core SDK 为always used,这意味着只要 Windows 的版本足够最新,您就不需要自己安装它。并且可以看到SDK is shipped with which Windows agent是哪个版本的。

    Azure Pipelines 中的当前Hosted OS 版本,也称为Default Hosted,在撰写本文时是Windows Server 2012 R2。这还不够最新。安装更新的 .NET Core SDK 来解决这个问题是每次构建都会拖累时间,虽然安装工作正常,但调用 Azure 签名工具可能无法正常工作。它似乎只找到旧版本的 SDK,并抛出此错误:Unable to find an entry point named 'SignerSignEx3' in DLL 'mssign32'.

    因此,最简单的做法是更改您的构建以使用更高版本的操作系统映像。 Windows 2019 就像一个魅力。并且无需安装任何版本的 .NET Core。

    然后创建一个命令行任务来安装 Azure 签名工具。您也可以使用 .NET Core CLI 任务,但没有必要。在任务中,输入:

    set DOTNET_SKIP_FIRST_TIME_EXPERIENCE=true
    dotnet tool install --global AzureSignTool --version 2.0.17
    

    自然使用你想要的任何版本。

    DOTNET_SKIP_FIRST_TIME_EXPERIENCE 环境变量并不是绝对必要的,但设置它会加快速度 (see here for an explanation)。

    最后,创建另一个命令行任务并输入您希望运行的 Azure 签名工具命令。在 Windows 上,这将类似于以下内容,请注意 ^ 而不是 / 作为行继续标记。自然见here for more parameter information:

     AzureSignTool.exe sign -du "MY-URL" ^
       -kvu https://MY-VAULT-NAME.vault.azure.net ^
       -kvi CLIENT-ID-BIG-GUID ^
       -kvs CLIENT-PASSWORD ^
       -kvc MY-CERTIFICATE-NAME ^
       -tr http://timestamp.digicert.com ^
       -v ^
       $(System.DefaultWorkingDirectory)/Path/To/My/Setup/Exe
    

从理论上讲,您应该会成功!标志工具的输出相当不错,通常能指出问题所在。

重新颁发证书

如果需要重新颁发证书,情况就大不一样了。

    在 Azure 中,转到证书并单击它,打开一个显示该证书版本的页面,包括当前版本和旧版本。

    点击“新版本”按钮,可能接受默认值(取决于您希望做出的选择),然后点击“创建”。

    这会将您带回版本页面,并且会出现一个消息框,说明“证书 XXXX 的创建当前正在等待”。单击此处(或在“证书操作”按钮上)打开“证书操作”侧页。在那里,下载 CSR(证书签名请求)。

    在 GlobalSign 中,按照他们的指示re-issue 现有证书。重新发布后,他们将发送一封电子邮件,说明如何下载。

    再次登录 GlobalSign,输入临时密码后,打开 CSR 并将整个文本(以-----BEGIN CERTIFICATE REQUEST----- 开头)复制到 GlobalSign。提交。

    使用“安装我的证书”按钮下载。然后在 Azure 的“证书操作”侧页中 - 使用“合并签名请求”按钮将 .CER 文件上传到 Azure。这将创建新版本的证书。

    禁用旧版本的证书。

【讨论】:

谢谢 Paul - 你省去了我写这篇文章的麻烦 :) 我已按照这些步骤操作,但我在管道中的 AzureSignTool 步骤中收到错误“Microsoft.Azure.KeyVault.Models.KeyVaultErrorException:操作返回无效状态代码“禁止”。我已将密钥保管库的访问策略中的权限授予我的“应用程序注册”应用程序、Azure DevOps 服务主体,甚至授予 Azure DevOps 角色。我错过了什么?注意:根据管道输出,成功获取token证书和secret。 很难说没有看到整个帐户,对不起。我建议联系 Azure 支持,他们在过去非常有用。 @Anodyne - 您是否从 Azure KeyVault 中发布了您的 CSR? 我需要“dotnet tool install”位上的“--ignore-failed-sources”,以允许它跳过我们在本地使用的 azure devops 工件存储库,然后检查 nuget.org。并且“CLIENT-PASSWORD”是创建秘密时的“值”。否则,这些说明非常棒,为我节省了大量时间!【参考方案2】:

是的,它能够在 Azure DevOps 服务构建管道中执行此操作。

在正常情况下,我们通常使用SignTool.exe 命令对文件进行签名。市场上还有一个扩展名Code Signing,可以对单个文件进行签名,您可以使用脚本对多个文件运行 SignTool.exe 命令。

因此,您可以将代码签名证书导出到 pfx 文件,然后将其作为安全文件上传到 Azure Devops 安全文件存储,以便您的构建可用。

Azure DevOps 可以存储安全文件。详情请查看此链接:Secure files

Azure Key Vault 实例有点复杂。我们还有一个 Azure Key Vault 任务。

在构建或发布管道中使用此任务来下载机密信息,例如 作为身份验证密钥、存储帐户密钥、数据加密密钥、 .PFX 文件和来自 Azure Key Vault 实例的密码。

该任务可用于获取所有或子集的最新值 保险库中的秘密,并将它们设置为可用于 管道的后续任务。

不确定 GlobalSign 如何将代码签名与您的环境集成。从理论上讲,它能够做到这一点。对于细节部分和实现,您可能需要与他们的售前讨论。希望这会有所帮助。

【讨论】:

感谢您回复我!我认为这里的主要问题是 GlobalSign 不会让我们拥有代码签名证书的私钥(出于安全原因)。他们坚持将密钥保存在 USB 令牌、HSM 或 Azure Key Vault 中。这意味着我们无法将私钥导出到 PFX 文件中。但是,我找到了 AzureSignTool,看起来它可以完成这项工作。如果这对我们有用,我会把它作为答案发布:) 实际上我大约半小时前才将证书放入 Key Vault,所以当/如果我开始签名工作时,我会更新。 @Anodyne 我知道这是旧的,但你有没有让导出的令牌在 Key Vault 中工作? @phanf 请参阅上面 Paul F. Wood 的答案。我无法从 USB 令牌中导出密钥(按设计这是不可能的),但我能够让 GlobalSign 颁发一个现在保存在 Azure Key Vault 中的新证书并使用 AzureSignTool。 以下信息也可能有用:我最近开始处理一个打包为 VSTO 加载项的新项目,并且 AzureSignTool 无法签署所需的 ClickOnce 清单对于 VSTO。对于那个项目,我最终选择了signpath.io,它可以签署我能想到的所有类型的文件。【参考方案3】:

如果其他人正在寻找这个并使用 RBAC,我发现这些步骤必不可少:

    RESOURCE GROUP 上的 Key Vault Reader KEY VAULT 和证书上的 Key Vault 证书官员 证书上的 Key Vault Crypto Office(使用密钥进行签名!)

【讨论】:

以上是关于如何使用 Azure Key Vault 中的证书/密钥对使用 Azure Pipelines 构建的代码进行签名?的主要内容,如果未能解决你的问题,请参考以下文章

Azure Key Vault 证书证书标识符、秘密标识符、密钥标识符之间的区别

Azure Key Vault 证书 - 创建基本约束 CA:True

Azure Key Vault 是不是支持客户端证书?

Azure Key Vault门户未显示秘密

如何在函数应用中引用 Azure Key Vault 中的密钥?

如何保护 Azure Key Vault 中的 blob 存储访问密钥