签名是处理 MSIX 包时要执行的关键任务之一。 如果未使用受信任的证书对 MSIX 包进行签名,则用户将无法安装该应用程序。 同时,签名也是安全性方面最重要的任务之一。 证书必须安全存储,以避免恶意参与者可以重复使用它们来使用我们的标识对应用程序进行签名。 Azure Key Vault 是支持此要求的最佳选项。
在本文中,我们将了解如何在 CI/CD 管道中使用 Azure Key Vault,以便我们可以在过程中自动对 MSIX 包进行签名。
重要
本文中所述的过程基于名为 Azure SignTool 的开源工具,该工具适用于 Azure Pipelines 和 GitHub Actions。 如果你使用的是 Azure Pipelines,那么还可将 MSIX 扩展与 Azure Key Vault 任务结合使用。
先决条件
- 一个 Azure 帐户。 如果还没有 Azure 帐户, 请从此处开始。
- 一个 Azure 密钥保管库。 有关详细信息,请参阅 创建 Key Vault。
- 导入到 Azure Key Vault 的有效包签名证书。 Azure Key Vault 生成的默认证书不适用于代码签名。 有关如何创建包签名证书的详细信息,请参阅 创建用于包签名的证书。
- 一个 CI/CD 管道,用于生成托管在 Azure Pipelines 或 GitHub Actions 上的 MSIX 包。 有关详细信息,请参阅 使用 YAML 文件配置 CI/CD 管道。
在 Azure 上注册应用程序
若要将包签名为 CI/CD 管道的一部分,我们将使用名为 Azure SignTool 的工具。 它的工作方式类似于 Windows 10 SDK 中包含的标准 SignTool 实用工具,但不是使用本地证书,而是连接到 Azure Key Vault 以使用其中一个可用证书。 但是,若要建立连接,我们首先需要在 Azure 上注册应用程序,这将提供我们需要的凭据,使 Azure SignTool 能够针对 Azure Key Vault 服务进行身份验证。
打开 Azure 门户,在可用服务中选择 Azure Active Directory 。 单击 “应用注册 ”并选择“ 新建注册 ”以启动该过程。 为应用程序命名(例如,下图中为 SignToolForContoso ),然后保留默认设置。
下一步是将应用程序视为公共客户端,因为我们处于不需要重定向 URI 的场景。 移动到 “身份验证”部分 ,在 “高级设置”下,将开关 “将应用程序视为公共客户端 ”更改为 “是”。
最后一步是创建客户端密码,这是我们需要从 Azure SignTool 进行身份验证的密码。 移动到 “证书和机密”部分,然后单击“ 新建客户端密码”。 为其指定名称,选择过期时间,然后按 “添加 ”按钮。 你将被重定向回主页,秘密及其值将被一同列出。 请务必复制它并将其存储在安全的地方。 你将无法再次检索它。 刷新页面后,机密就会被屏蔽,并且不会有任何方式显示它。 唯一的选择是生成新机密。
最后一个信息需要与客户端密码一起保存:应用程序标识符。 返回到应用程序的主页(单击 “概述”),并在上半部分查找值 “应用程序”(客户端)ID:
启用对 Azure Key Vault 的访问权限
下一步是配置刚刚创建的用于访问 Azure Key Vault 服务的 Azure 应用程序。 从 Azure 门户移动到包含要用于对 MSIX 包进行签名的证书的 Azure Key Vault 实例。 转到 “访问策略 ”部分,然后单击“ 添加访问策略”。 该工具支持选择一个可用的模板来定义我们想要授予的权限,但在我们的方案中,没有人适合。 因此,我们需要使用下拉列表手动设置以下选项:
- 在 “密钥权限”下,启用 “签名 ”选项。
- 在 “证书权限”下,启用 “获取 ”选项。
最后一个重要步骤是指定要访问此策略的应用程序。 单击 “选择主体 ”,并使用其名称搜索在上一步中创建的 Azure 应用程序。 在此示例中,它称为 SignToolForContoso。
找到它后,按 Select。 这就是政策应有的样子。
完成该过程后,单击“ 添加” 以创建策略。
使用 Azure SignTool 在本地对包进行签名
完成 Azure 配置后,可以使用 Azure SignTool 对包进行签名。 在本部分中,我们将在本地使用该工具进行熟悉。 在下一部分中,我们将将其用作 CI/CD 管道的一部分。
该工具可用作 .NET 全局工具。 请确保 已安装最新的 .NET SDK,然后打开命令提示符并启动以下命令:
dotnet tool install --global AzureSignTool
现在,可以使用 AzureSignTool 命令对包进行签名,该命令需要以下参数:
kvu
是 Azure Key Vault 的 URL。 可以在 Azure 门户的服务主页的 DNS 名称下找到它。kvi
是您已注册且之前已记录的 Azure 应用的应用程序 ID。kvs
是之前生成并记录的客户端密码。kvc
是要使用的证书的友好名称。tr
是时间戳服务器的 URL。 通过使用此选项,即使证书过期,我们的包也能正常工作。v
是要签名的 MSIX 包的路径。
这是一个示例命令:
AzureSignTool sign -kvt "<tenantID>" -kvu "https://contosoexpenses-blog.vault.azure.net/" -kvi "aaaabbbb-0000-cccc-1111-dddd2222eeee" -kvs "this-is-the-secret" -kvc "MyCertificate" -tr http://timestamp.digicert.com -v .\MyContosoApp.msix
注释
若要了解有关 AzureSignTool 的详细信息,请运行 AzureSignTool sign --help
将 Azure SignTool 与 Azure Pipelines 配合使用
本部分假定你已为 Azure Pipelines 上的 Windows 应用程序配置了 YAML 文件的 CI/CD 管道,如这里所述。
首先,需要创建一些变量来存储 Azure SignTool 连接到 Azure Key Vault 所需的信息。 在 Azure DevOps 中选择管道,然后按顶部的 “编辑 ”按钮。 进入 YAML 编辑器后,单击顶部的 “变量 ”按钮打开面板。 你将单击“+”按钮添加以下变量:
- AzureKeyVaultName,带有保管库的易记名称。
- AzureKeyVaultUrl,带有保管库的 URL。
- AzureKeyVaultClientId,带有 Azure 应用程序的应用 ID。
- AzureKeyVaultClientSecret,其中包含 Azure 应用程序的客户端密码。
创建每个变量时,请确保启用 “保留此值 机密”选项。 它将确保有权访问管道的其他人无法查看其值。
现在,你可添加 .NET Core 任务在代理上安装 Azure SignTool,来自定义现有 YAML 管道。 这是要添加的 YAML:
- task: DotNetCoreCLI@2
displayName: 'Install Azure SignTool'
inputs:
command: custom
custom: tool
arguments: 'install --global AzureSignTool'
下一步是添加 PowerShell 任务以执行对包进行签名的命令。 创建 MSIX 包后,只有在生成过程结束时才能执行此任务。
- powershell: '& AzureSignTool sign -kvu $(AzureKeyVaultUrl) -kvi $(AzureKeyVaultClientId) -kvs $(AzureKeyVaultClientSecret) -kvc $(AzureKeyVaultName) -tr http://timestamp.digicert.com -v "$(System.DefaultWorkingDirectory)\MyPipeline\MyContosoApp\MyContosoApp.msix"'
displayName: 'Sign the package'
该命令类似于用于在本地对包进行签名的命令。 唯一的区别是:
- 我们使用语法 $(Variable-Name) 创建的变量,而不是对各种参数使用固定值
- MSIX 包的路径指向在生成结束时创建 MSIX 包的代理上的文件夹。
将 Azure SignTool 与 GitHub Actions 配合使用
本部分假设你已有一个 CI/CD 管道用于在 GitHub Actions 上配置有 YAML 文件的 Windows 应用程序,如此处所述。
作为第一步,就像我们在 Azure Pipeline 上所做的那样,我们需要安全地存储凭据。 GitHub 使用 机密 ,可以在存储库的设置中添加机密。 在托管 Windows 应用程序的 GitHub 存储库上后,单击 “设置” ,然后移动到 “机密”。
与使用 Azure Pipelines 执行的作类似,你将单击 “新建机密 ”以创建四个机密:
- AzureKeyVaultName,带有保管库的易记名称。
- AzureKeyVaultUrl,带有保管库的 URL。
- AzureKeyVaultClientId,带有 Azure 应用程序的应用 ID。
- AzureKeyVaultClientSecret,其中包含 Azure 应用程序的客户端密码。
与 Azure Pipeline 的区别在于,机密是隐式隐藏的,因此无需启用任何保护它们的选项。
现在,通过存储库的操作选项卡,您可以打开现有工作流,并添加您需要执行签名的任务。 第一个工具将在代理上安装 AzureSign 工具:
- name: Install AzureSignTool
run: dotnet tool install --global AzureSignTool
第二个模块将对包进行签名,因此,该过程必须在 Visual Studio 构建完成并生成 MSIX 包之后执行。
- name: Sign package
run: |
Get-ChildItem -recurse -Include **.msix | ForEach-Object {
$msixPath = $_.FullName
& AzureSignTool sign -kvu "${{ secrets.AzureKeyVaultUrl }}" -kvi "${{ secrets.AzureKeyVaultClientId }}" -kvs "${{ secrets.AzureKeyVaultClientSecret }}" -kvc ${{ secrets.AzureKeyVaultName }} -tr http://timestamp.digicert.com -v $msixPath
}
与我们在 Azure Pipelines 中使用的任务相比,此任务存在一些差异。 第一个是 GitHub 使用不同的语法来访问机密,即 ${{ 机密。SECRET_NAME }}。 因此,各种参数填充了我们之前在“密码”部分中创建的值。 另一个是,你需要使用不同的方法来查找要签名的 MSIX 包。 该任务使用 PowerShell 脚本来循环访问存储在生成输出中的所有文件,而不是指向特定的 MSIX 包。 如果该文件具有 MSIX 扩展名,则它将使用 AzureSignTool 命令对其进行签名。
部署包
无论所选的 CI/CD 平台如何,在流结束时,都会使用 Azure Key Vault 上存储的证书对 MSIX 包进行签名。 现在,可以使用任何其他可用任务通过首选分发版来部署包:Microsoft应用商店、网站、Microsoft Intune 等。