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

44
我们正在从本地构建服务器迁移到Azure Pipelines。我们生产“收缩包”桌面软件,因此在发布前需要对所有二进制文件进行签名。我们当前的构建基础设施使用GlobalSign的USB硬件令牌来完成这个过程,但显然,在云构建时这种方式行不通 - 遗憾的是,云没有配备USB端口:D
现在,GlobalSign最近开始推广Azure Key Vault作为密钥存储选项,并且他们非常乐意向我们出售此服务,但我不确定如何将其与我们的构建管道实际集成(或者是否可能)。
有人真正做到了吗?
3个回答

61

代码签名

我一直在努力使用Azure Key Vault和Azure Pipelines对我们的代码进行签名,并成功了。以下是我的发现。

关键是,用于代码签名的扩展验证(EV)证书与“普通”的SSL证书非常不同。标准证书可以随意导出,这意味着您可以将其上传到Azure Pipelines并使用标准的Microsoft Sign Tool。

但是,一旦将EV证书放入Azure Key Vault中,就无法以任何通常的方式取出。您必须使用Anodyne above发现的优秀的Azure Sign Tool从Pipelines调用它。

将证书放入Key Vault中。您可以使用任何证书颁发机构来生成证书,只要他们知道您需要一张EV证书,而且至关重要的是,需要一个硬件安全模块(HSM),而不是一个带有物理USB密钥的证书。任何像Key Vault这样的云系统都需要HSM版本。

要获取访问此证书的权限,请follow this page,但要注意它漏掉了一步。因此,首先阅读该文档,然后按照以下摘要步骤设置Key Vault:

  1. 打开 Azure 门户,在 Azure Active Directory 区域创建一个 应用程序注册:输入易记名称,忽略 重定向 URI,并保存。
  2. 进入特定的 密钥保管库,然后进入 访问控制(IAM),再选择 添加角色分配。在 选择 输入框中输入刚刚创建的应用程序名称。还需要选择一个 角色,建议选择 读取者,然后保存。
  3. 缺失的部分:仍在密钥保管库中,单击 访问策略 菜单项。单击 添加访问策略 并添加你的应用程序。需要在 证书权限 中选中 获取。尽管你在此保管库中可能没有任何密钥,但是 密钥权限 也需要选中 获取签名。你可能认为这两个会在证书权限中...
  4. 返回到刚刚创建的应用程序。选择 证书和密码,然后选择上传证书(专门用于远程访问密钥保管库)或创建 客户端密码。如果选择后者,请记下密码,否则你将无法再看到它!
  5. 在应用程序的 概述 部分中,会显示 应用程序(客户端)ID。这个和密码或证书是接下来在管道任务中传递给 Azure 签名工具的内容。

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

  1. The Azure Sign Tool needs the .NET Core SDK to be installed, but a version that's at least version 2.x, and since the latest .NET Core SDK is always used, this means as long as the version of Windows is current enough, you don't need to install it yourself. And you can see which version of the SDK is shipped with which Windows agent.

    The current Hosted OS version in Azure Pipelines, also called Default Hosted, is, at the time of writing, Windows Server 2012 R2. Which isn't up to date enough. Installing a newer .NET Core SDK to overcome this is a time drag on every build, and although the installation works, calling the Azure Sign Tool may not work. It seems to be finding only older versions of the SDK, and throws this error: Unable to find an entry point named 'SignerSignEx3' in DLL 'mssign32'.

    So the easiest thing to do is change your build to use a later OS image. Windows 2019 works like a charm. And there is no need to install any version of .NET Core.

  2. Then create a command line task to install the Azure Sign Tool. You can use a .NET Core CLI task as well, but there is no need. In the task, type this:

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

    Naturally using whichever version that you want.

    The DOTNET_SKIP_FIRST_TIME_EXPERIENCE environment variable isn't strictly necessary, but setting it speeds things up quite a bit (see here for an explanation).

  3. Finally, create another command line task and type in the Azure Sign Tool command that you wish to run with. On Windows this would be something like below, note with ^ not / as a line continuation marker. Naturally, see 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中,请按照其说明重新发行现有证书。一旦重新发行,他们将发送一封电子邮件,描述如何下载它。
再次登录GlobalSign,在输入临时密码后,打开CSR并复制整个文本(以-----BEGIN CERTIFICATE REQUEST-----开头)到GlobalSign中。提交它。
使用“安装我的证书”按钮进行下载。然后在Azure“证书操作”侧面页面中,使用“合并已签名请求”按钮将.CER文件上传到Azure。这将创建证书的新版本。
禁用旧版本的证书。

1
谢谢Paul - 你帮我省去了写这个的麻烦 :) - Anodyne
很抱歉,没有看到整个账户的情况很难说。我建议联系Azure支持,他们在过去非常有用。 - Paul F. Wood
@Anodyne - 你是在 Azure KeyVault 中发布了你的 CSR 吗? - Norbert Hüthmayr
我需要在 "dotnet tool install" 部分使用 "--ignore-failed-sources",以便它可以跳过我们本地使用的 Azure DevOps 工件库并检查 nuget.org。创建密钥时,“CLIENT-PASSWORD” 是“value”。否则,这些说明非常棒,为我节省了大量时间! - Peter Drier
1
在本地 Azure DevOps 环境中,这个怎么运行呢? - undefined
显示剩余2条评论

5
是的,在Azure DevOps服务构建管道中可以实现这一点。
对于正常情况,我们通常使用SignTool.exe命令来签名文件。市场上也有一个扩展程序代码签名,它可以为单个文件签名,您可以使用脚本运行SignTool.exe命令以签署多个文件。
因此,您可以将代码签名证书导出为pfx文件,然后将其上传为安全文件到Azure Devops安全文件存储,使其可用于您的构建。
Azure DevOps可以存储安全文件。有关详细信息,请查看此链接:安全文件 Azure Key Vault实例有点更复杂。我们还有一个Azure Key Vault任务。
使用此任务在构建或发布流水线中从 Azure Key Vault 实例下载密钥,例如身份验证密钥、存储帐户密钥、数据加密密钥、.PFX 文件和密码。该任务可用于获取来自保险库的所有或部分密钥的最新值,并将它们设置为变量,可在流水线的后续任务中使用。
不确定 GlobalSign 如何将代码签名与您的环境集成。理论上,它可以做到这一点。有关详细部分和实现,请与其售前人员讨论。希望这可以帮助到您。

2
感谢您回复我!我认为这里的主要问题是GlobalSign不允许我们拥有代码签名证书的私钥(出于安全原因)。他们坚持将密钥保存在USB令牌、HSM或Azure Key Vault中。这意味着我们无法将私钥导出到PFX文件。然而,我找到了AzureSignTool,它看起来可能能够完成这项工作。如果这对我们有用,我会将其发布为答案 :) - Anodyne
1
我大约半个小时前刚刚将证书存入了密钥保管库,所以如果我成功签名的话,我会进行更新。 - Anodyne
1
@phanf 请参考Paul F. Wood上面的答案。我无法从USB令牌中导出密钥(这是设计上不可能的),但我能够让GlobalSign发放一个新证书,现在它保存在Azure Key Vault中并使用AzureSignTool。 - Anodyne
1
以下信息可能也有用:我最近开始开展一个新项目,它被打包为VSTO插件,而AzureSignTool无法签署VSTO所需的ClickOnce清单。对于该项目,我最终选择了https://signpath.io,它可以签署我能想到的每种类型的文件。 - Anodyne
@Anodyne 我们尝试使用signpath.io构建我们的ClickOnce项目,但到目前为止一直未能成功发送正确的.zip artifact和manifest等。您是否有关于如何将signpath.io添加到Azure管道中的信息?谢谢。 - phanf
显示剩余2条评论

2
如果其他人正在寻找这个并且使用RBAC,我发现以下步骤至关重要:
  1. 在资源组上赋予“密钥保管库读取者”角色
  2. 在密钥保管库和证书上赋予“密钥保管库证书操作员”角色
  3. 在证书上赋予“密钥保管库加密操作员”角色(以便使用密钥进行签名!)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接