如何安全地配置CI服务器以对二进制文件进行数字签名?

gre*_*mac 16 teamcity continuous-integration code-signing authenticode signtool

有许多站点可以解释如何signtool.exe.pfx证书文件上运行,该文件归结为:

signtool.exe sign /f mycert.pfx /p mypassword /t http://timestamp.server.com \
  /d "My description"   file1.exe file2.exe
Run Code Online (Sandbox Code Playgroud)

我有一个持续集成的CI流程设置(使用TeamCity),它像大多数CI流程一样,完成所有工作:检查源代码,编译,签署所有.exes,将软件包签入安装程序,然后签署安装程序.exe.目前有3个构建代理程序,运行相同的VM,其中任何一个都可以运行此过程.

不安全的实施

为了实现这一目标,就安全性而言,我做了一些Bad Things(TM):.pfx文件在源代码管理中,并且它的密码在构建脚本中(也在源代码管理中).这意味着任何能够访问源代码存储库的开发人员都可以获取pfx文件并执行他们喜欢的任何恶意内容.(我们是一个相对较小的开发商店,相信每个人都可以访问,但显然这仍然不好).

最终的安全实施

我能找到"正确"做到这一点,就是你:

  • 将pfx和密码保存在某些安全介质上(如带有手指解锁的加密USB驱动器),可能不在一起
  • 仅指定几个人可以访问签名文件
  • 只签署一个非连接的专用机器上的最终版本,该机器保存在一个锁定的保险库中,直到您需要将其带出来进行此代码签名仪式.

虽然我可以看到这个安全性的优点..这是一个非常繁重的过程,并且在时间方面很昂贵(运行此过程,安全地保留证书备份,确保代码签名机器处于工作状态等) ).

我确信有些人会跳过步骤,只需手动签署存储在他们个人系统上的证书的文件,但这仍然不是很好.

它也与安装程序中使用的签名文件(也由构建服务器构建)不兼容 - 当您安装了具有UAC提示以获得管理员访问权限的.exe时,这一点很重要.

中间地带?

我更关心的是没有向用户提供可怕的"不受信任的应用程序"UAC提示,而不是证明它是我的公司.同时,将私钥和密码存储在每个开发人员(以及QA和高级技术支持)都可以访问的源代码存储库中显然不是一个好的安全实践.

我想要的是CI服务器在构建过程中仍然像今天一样签名,但没有密码(或证书的私钥部分)可供访问源代码存储库的每个人访问.

有没有办法将密码保留在构建之外或以某种方式保护?我应该告诉signtool使用证书存储区(我如何使用3个构建代理程序和构建作为非交互式用户帐户运行)?别的什么?

gre*_*mac 7

我最终采用了与@GiulioVlan建议的非常相似的方法,但有一些变化.

MSBuild任务

我创建了一个执行signtool.exe的新MSBuild任务.此任务有两个主要目的:

  • 它隐藏了所显示的密码
  • 它可以在发生故障时重试时间戳服务器
  • 它使呼叫变得容易

资料来源:https://gist.github.com/gregmac/4cfacea5aaf702365724

这专门接受所有输出并通过清洁功能运行它,用全部*替换密码.

我不知道审查常规MSBuild命令的方法,因此如果您使用命令行将密码直接传递给signtool.exe将显示密码 - 因此需要执行此任务(除了其他好处).

注册表中的密码

我讨论了几种存储密码"带外"的方法,最后决定使用注册表.它很容易从MSBuild访问,手动管理相当容易,如果用户没有RDP和远程注册表访问机器,它实际上是相当安全的(否则有人会这样说吗?).据推测,有很多方法可以使用花哨的GPO来保护它,但这超出了我想要的长度.

这可以通过msbuild轻松读取:

$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\1 Company Dev@CodeSigningCertPassword)
Run Code Online (Sandbox Code Playgroud)

并且通过注册表很容易管理:

在此输入图像描述

为什么不在别处?

  • 在构建脚本中:任何拥有源代码的人都可以看到它
  • 源代码管理中加密/混淆/隐藏:如果有人获得源代码的副本,他们仍然可以解决这个问题
  • 环境变量:在Teamcity Web UI中,每个构建代理都有一个详细信息页面,它实际显示所有环境变量及其值.可以限制对此页面的访问,但这意味着其他一些功能也受到限制
  • 构建服务器上的文件:可能,但似乎更有可能通过文件共享或其他东西无意中访问它

从MSBuild调用

在标签中:

<Import Project="signtool.msbuild.tasks"/>
Run Code Online (Sandbox Code Playgroud)

(你也可以将它放在一个包含其他任务的公共文件中,甚至可以直接嵌入)

然后,在您要用于签名的任何目标中:

<SignTool  SignFiles="file1.exe;file2.exe" 
   PfxFile="cert.pfx" 
   PfxPassword="$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\1 Company Dev@CodeSigningCertPassword)"
   TimestampServer="http://timestamp.comodoca.com/authenticode;http://timestamp.verisign.com/scripts/timstamp.dll" />
Run Code Online (Sandbox Code Playgroud)

到目前为止,这很有效.

  • 如果您在Windows上运行,则可以将证书导入证书存储区.为构建代理提供对私钥的访问权限,指定要通过其名称或指纹使用的证书.您甚至可以将密钥标记为不可导出.现在您只需要保护密码到您的构建过程正在运行的用户帐户(无论如何您应该这样做) (4认同)