在Azure DevOps管道中安全签署ClickOnce应用程序 [英] Securely Signing ClickOnce Applications in Azure DevOps Pipeline

查看:47
本文介绍了在Azure DevOps管道中安全签署ClickOnce应用程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用ClickOnce应用程序在Azure DevOps中进行CI/CD.使用托管代理时,如何在构建过程中安全地提供我的代码签名证书?

I'm trying to do CI/CD in Azure DevOps with a ClickOnce application. How can I securely make my code signing certificate available during the build when using a hosted agent?

请注意,我知道您可以按照中的建议使用脚本Visual Studio团队服务部署人员/构建证书错误.但是,这种方法并不安全.证书将被加载到托管代理正在运行的帐户的证书存储中.这将允许代理以及其他Azure DevOps帐户潜在地访问和使用证书.

Note I'm aware you can use a script as suggested at Visual studio team services deploymen/buildt certificate error. However this approach is not secure. The certificate would be loaded into the certificate store of the account the hosted agent is running under. This would allow the agent, and hence other Azure DevOps accounts, to potentially access and use the certificate.

推荐答案

此问题的解决方案是覆盖内置任务SignFile.有趣的是,SignFile任务使用Microsoft.Build.Tasks.Deployment.ManifestUtilities.SecurityUtilities.SignFile中的内置函数,该函数具有两个重载,一个重载需要指纹,而另一个重载则需要文件和密码.

The solution to the issue is to override the built in task SignFile. Interestingly enough the task SignFile uses a built in function in Microsoft.Build.Tasks.Deployment.ManifestUtilities.SecurityUtilities.SignFile which has two overloads, one that takes a thumbprint, and one that takes a file and password.

然后的解决方案是创建一个新任务,该任务可以引用其他重载.由于我们无法更改调用的SignFile,因此我们需要维护相同的签名,并将适当的变量放在环境变量中.在这种情况下,"CertificateFile"和"CertificatePassword".

The solution is then to create a new Task that can reference the other overload. Since we cannot change the calling SignFile we need to maintain the same signature, and place the appropriate variables in the environment variables. In this case "CertificateFile" and "CertificatePassword".

然后在覆盖的SignFile中引用这两个.我要做的是创建一个新的目标文件(filesign.targets)并将代码放置在那里.签入到我的存储库中,并从主项目文件中引用了它. <Import Project="filesign.targets" />

Then reference those two in the overwritten SignFile. What I did was to create a new targets file (filesign.targets) and place the code there. Checked that in to my repository and referenced it from the main project file(s). <Import Project="filesign.targets" />

通过这种方式,我们还可以将密钥文件保存在Azure密钥保管库中,在构建时加载它们,并为该构建提供唯一的密码.

This way we can also hold our key files in an Azure Key Vault, load them at built and give them a unique password just for that build.

目标文件包含新的FileSign任务:

The targets file holds the new FileSign task:

<?xml version="1.0" encoding="Windows-1252"?>
<!--
***********************************************************************************************
Microsoft.VisualStudio.Tools.Office.targets

WARNING:  DO NOT MODIFY this file unless you are knowledgeable about MSBuild and have
created a backup copy.  Incorrect changes to this file will make it
impossible to load or build your projects from the command-line or the IDE.

This file defines the steps in the standard build process specific for Visual Studio Tools for 
Office projects.

Copyright (C) Microsoft Corporation. All rights reserved.
***********************************************************************************************
-->

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

    <UsingTask TaskName="SignFile" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll">

    <ParameterGroup>
      <SigningTarget Required="true" ParameterType="Microsoft.Build.Framework.ITaskItem" />
      <CertificateThumbprint ParameterType="System.String" />
      <TargetFrameworkVersion ParameterType="System.String" />
      <TimestampUrl ParameterType="System.String" />
      <CertificateFile ParameterType="System.String" />
      <CertificatePassword ParameterType="System.String" />
    </ParameterGroup>
    <Task>
      <Reference Include="mscorlib" />
      <Reference Include="Microsoft.Build.Tasks.Core" />
      <Using Namespace="System" />
      <Code Type="Fragment" Language="cs">
        <![CDATA[
                var EnvCertFile = System.Environment.GetEnvironmentVariable("CertificateFile");

                Log.LogMessage("CertFile:!!" + EnvCertFile);

                if (string.IsNullOrWhiteSpace(CertificateFile) && string.IsNullOrWhiteSpace(EnvCertFile)) {
                    var signFile = new Microsoft.Build.Tasks.SignFile();
                    signFile.CertificateThumbprint = CertificateThumbprint;
                    signFile.SigningTarget = SigningTarget;
                    signFile.TargetFrameworkVersion = TargetFrameworkVersion;
                    signFile.TimestampUrl = TimestampUrl;
                    return signFile.Execute();
                } else {

                    var certificate = string.IsNullOrWhiteSpace(CertificateFile) ? EnvCertFile : CertificateFile;
                    var EnvCertPassword = System.Environment.GetEnvironmentVariable("CertificatePassword");
                    var certificatePassword = string.IsNullOrWhiteSpace(CertificatePassword) ? EnvCertPassword : CertificatePassword;
                    var testString = new System.Security.SecureString();
                    // Use the AppendChar method to add each char value to the secure string.
                    if (!string.IsNullOrWhiteSpace(certificatePassword))
                        foreach (char ch in certificatePassword)
                            testString.AppendChar(ch);
                    Microsoft.Build.Tasks.Deployment.ManifestUtilities.SecurityUtilities.SignFile(certificate, testString,
                        TimestampUrl == null ? null : new Uri(TimestampUrl),
                        SigningTarget.ItemSpec);
                    return true;
                }

]]>
      </Code>
    </Task>
  </UsingTask>
</Project>

代码基于: https://gist.github.com/KirillOsenkov/4cd32c40bffd3045f77e

参考: https://github.com/Microsoft/msbuild/blob/fc10ea8ce260b764bb9fa5033b327af9fefcaabe/src/Tasks/ManifestUtil/SecurityUtil.cs https://github.com/Microsoft/msbuild/blob/master/src/Tasks/SignFile.cs

这篇关于在Azure DevOps管道中安全签署ClickOnce应用程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆