在Azure DevOps管道中对ClickOnce应用程序进行安全签名



我正在尝试使用ClickOnce应用程序在Azure DevOps中执行CI/CD。使用托管代理时,如何在生成期间安全地使代码签名证书可用?

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

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

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

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

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

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

<?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.cshttps://github.com/Microsoft/msbuild/blob/master/src/Tasks/SignFile.cs

最新更新