CI/CD 与构建工具
sslTrus 远程代码签名服务可以集成到 CI/CD、应用构建和安装包制作流程中,在编译或打包完成后自动对发布产物执行代码签名。
当前支持的典型集成场景包括:
- GitHub Actions
- Electron Builder
- Advanced Installer
根据构建工具的能力,可以直接使用 sslTrus GitHub Action、调用 SignTool CLI,或通过构建工具提供的自定义签名接口完成集成。
GitHub Actions
sslTrus 提供官方 GitHub Action:
ssltrus-official/code-sign-action
可以直接在 GitHub Actions Workflow 中对构建产物执行远程代码签名。
Action 会调用 sslTrus 远程代码签名服务完成签名,并直接更新指定文件,适用于 Linux、macOS 和 Windows Runner。
准备 GitHub Secrets
建议将远程代码签名凭证保存到 GitHub Actions Secrets:
SSLTRUS_ACCESS_KEY
SSLTRUS_ACCESS_SECRET
SSLTRUS_CERT_CODE
不要将 Access Secret 直接写入 Workflow 文件。
基础配置
- name: Sign files
uses: ssltrus-official/code-sign-action@v1
with:
access-key: ${{ secrets.SSLTRUS_ACCESS_KEY }}
access-secret: ${{ secrets.SSLTRUS_ACCESS_SECRET }}
cert-code: ${{ secrets.SSLTRUS_CERT_CODE }}
files: build/app.exe
签名成功后,build/app.exe 会被签名后的文件直接替换。
签名多个文件
files 支持使用多行配置多个文件:
- name: Sign files
uses: ssltrus-official/code-sign-action@v1
with:
access-key: ${{ secrets.SSLTRUS_ACCESS_KEY }}
access-secret: ${{ secrets.SSLTRUS_ACCESS_SECRET }}
cert-code: ${{ secrets.SSLTRUS_CERT_CODE }}
files: |
build/app.exe
build/library.dll
build/installer.msi
也可以使用逗号分隔文件路径。
重复的文件路径只会处理一次。
完整配置
- name: Sign files
uses: ssltrus-official/code-sign-action@v1
with:
access-key: ${{ secrets.SSLTRUS_ACCESS_KEY }}
access-secret: ${{ secrets.SSLTRUS_ACCESS_SECRET }}
cert-code: ${{ secrets.SSLTRUS_CERT_CODE }}
files: |
build/app.exe
build/library.dll
build/installer.msi
dry-run: false
timestamp-rfc3161: http://timestamp.acs.microsoft.com
description: Example Application
description-url: https://example.com
主要参数:
| 参数 | 必填 | 默认值 | 说明 |
|---|---|---|---|
access-key | 是 | - | sslTrus Access Key |
access-secret | 是 | - | sslTrus Access Secret |
cert-code | 是 | - | 代码签名证书编号 |
files | 是 | - | 需要签名的文件路径 |
nicsrs | 否 | false | 是否使用 NICSRS 服务 |
dry-run | 否 | false | 使用本地测试证书执行测试签名 |
timestamp-rfc3161 | 否 | auto | RFC 3161 时间戳服务器 |
description | 否 | - | 写入 Authenticode 签名的程序描述 |
description-url | 否 | - | 写入 Authenticode 签名的程序 URL |
完整 Workflow 示例
下面是在 Windows Runner 中编译、签名并上传构建产物的示例:
name: Build and Sign
on:
workflow_dispatch:
permissions:
contents: read
jobs:
build:
runs-on: windows-latest
steps:
- name: Check out repository
uses: actions/checkout@v7
- name: Build
run: |
# 在这里执行实际构建命令
- name: Sign files
uses: ssltrus-official/code-sign-action@v1
with:
access-key: ${{ secrets.SSLTRUS_ACCESS_KEY }}
access-secret: ${{ secrets.SSLTRUS_ACCESS_SECRET }}
cert-code: ${{ secrets.SSLTRUS_CERT_CODE }}
files: |
build/app.exe
build/library.dll
timestamp-rfc3161: http://timestamp.acs.microsoft.com
- name: Upload signed files
uses: actions/upload-artifact@v7
with:
name: signed-files
path: |
build/app.exe
build/library.dll
建议将签名步骤放在:
编译 → 打包 → 代码签名 → 发布
流程中的发布步骤之前。
多平台 Runner
GitHub Action 可以在不同 Runner 中调用:
strategy:
matrix:
os:
- ubuntu-latest
- macos-latest
- windows-latest
runs-on: ${{ matrix.os }}
因此,即使构建任务运行在 Linux 或 macOS,也可以使用相同 Action 完成受支持文件的远程签名。
Dry Run
如果需要验证 Workflow 和文件处理逻辑,可以启用:
dry-run: true
此模式使用本地测试证书,不调用远程代码签名服务。
例如:
- name: Test signing
uses: ssltrus-official/code-sign-action@v1
with:
access-key: dummy
access-secret: dummy
cert-code: dummy
files: build/app.exe
dry-run: true
dry-run 仍会修改目标文件,因此不要将其理解为完全不修改文件的预览模式。
Electron Builder
Electron Builder 可以通过自定义签名函数调用 sslTrus SignTool CLI,从而在 Electron 应用构建过程中自动完成 Windows 可执行文件和安装包签名。
典型流程:
Electron Builder
↓
customSign
↓
SignTool CLI
↓
sslTrus 远程代码签名服务
↓
云端 HSM
前提条件
开始前需要:
- 已有可用的 sslTrus 远程代码签名服务。
- 已获得 Access Key 和 Access Secret。
- 已获得代码签名证书编号。
- Electron 项目使用
electron-builder构建。 - 构建环境能够执行 sslTrus SignTool CLI,可从 sslTrus 客户端发布页 下载。
配置凭证
可以通过环境变量将凭证传递给构建脚本:
Linux 和 macOS:
export SIGNTOOL_ACCESS_KEY="YOUR_ACCESS_KEY"
export SIGNTOOL_ACCESS_SECRET="YOUR_ACCESS_SECRET"
export SIGNTOOL_CERT_CODE="YOUR_CERT_CODE"
Windows PowerShell:
$env:SIGNTOOL_ACCESS_KEY = "YOUR_ACCESS_KEY"
$env:SIGNTOOL_ACCESS_SECRET = "YOUR_ACCESS_SECRET"
$env:SIGNTOOL_CERT_CODE = "YOUR_CERT_CODE"
这些变量由 Electron 自定义签名脚本读取,再传递给 SignTool CLI。
配置 Electron Builder
在:
electron-builder.mjs
或者项目实际使用的 Electron Builder 配置文件中,为 Windows 设置自定义签名函数:
export default {
win: {
target: [
{
target: 'nsis',
arch: ['x64'],
},
],
sign: customSign,
signingHashAlgorithms: ['sha256'],
},
};
其中 win.sign 是 Electron Builder 官方提供的自定义签名入口,详细说明请参阅 Electron Builder Windows 代码签名文档。
customSign
负责调用 sslTrus SignTool CLI。
自定义签名函数
示例:
import { execFileSync } from 'node:child_process';
async function customSign(configuration) {
const {
SIGNTOOL_ACCESS_KEY,
SIGNTOOL_ACCESS_SECRET,
SIGNTOOL_CERT_CODE,
} = process.env;
if (
!SIGNTOOL_ACCESS_KEY ||
!SIGNTOOL_ACCESS_SECRET ||
!SIGNTOOL_CERT_CODE
) {
throw new Error('Missing sslTrus signing credentials');
}
execFileSync(
'./signtool',
[
'sign',
'--access-key',
SIGNTOOL_ACCESS_KEY,
'--access-secret',
SIGNTOOL_ACCESS_SECRET,
'--cert-code',
SIGNTOOL_CERT_CODE,
'--file',
configuration.path,
'--override=true',
'--sha1=false',
'--sha2=true',
'--timestamp-rfc3161=http://timestamp.acs.microsoft.com',
],
{
stdio: 'inherit',
},
);
}
建议使用参数数组调用子进程,而不是拼接完整 Shell 命令,以减少路径转义和特殊字符处理问题。
Electron Builder 会按照 signingHashAlgorithms 中的每个哈希算法分别调用一次签名函数。上面的示例只启用 SHA-256,因此每个文件调用一次。
执行构建
配置完成后,正常执行 Electron Builder:
npx electron-builder build \
--config electron-builder.mjs \
--win \
--x64
Electron Builder 在需要对文件执行签名时,会自动调用 customSign。
一次 Electron 构建可能签名多个文件,例如:
MyApp.exe
helper.dll
update.exe
uninstall.exe
MyApp Setup.exe
因此,不应简单理解为“一次 Electron 打包只产生一次签名”。
实际签名次数取决于构建过程中有多少文件执行了远程签名。
Advanced Installer
Advanced Installer 是基于 Windows Installer 技术的安装包制作工具。
可以通过 Advanced Installer 的自定义签名工具功能调用 sslTrus SignTool CLI,使 MSI、EXE、CAB 等构建产物在打包过程中自动完成远程代码签名。
前提条件
需要准备:
- sslTrus SignTool CLI,可从 sslTrus 客户端发布页 下载。
- Access Key。
- Access Secret。
- 证书编号。
- 已配置完成的 Advanced Installer 项目。
配置自定义签名工具
打开 Advanced Installer 项目的:
Digital Signature
配置页面。
启用代码签名后,将签名工具选择为:
Custom
签名工具路径设置为 sslTrus SignTool CLI 可执行文件。
例如:
C:\Tools\sslTrus\signtool.exe
自定义参数需要调用:
sign
子命令,并向客户端传入:
- Access Key
- Access Secret
- Cert Code
- SHA-2 签名设置
- 时间戳服务器
- 文件路径
建议优先通过安全方式提供 Access Key 和 Access Secret,避免将长期有效的 Access Secret 明文保存到可公开获取的项目文件中。
SignTool 参数示例
对应的签名逻辑类似:
signtool.exe sign ^
--access-key="YOUR_ACCESS_KEY" ^
--access-secret="YOUR_ACCESS_SECRET" ^
--cert-code="YOUR_CERT_CODE" ^
--nest=true ^
--sha1=false ^
--sha2=true ^
--timestamp-rfc3161=http://timestamp.acs.microsoft.com ^
--desc="Example Application" ^
--override=true ^
--file "app.exe"
在 Advanced Installer 中,实际文件路径应由其自定义签名工具机制传入,不要固定为示例中的 app.exe。
构建配置
如果使用 Advanced Installer 自动签名安装包内部文件,需要同时检查构建和压缩方式。
根据项目实际配置,某些 CAB 归档方式可能会影响自定义签名流程,应确认最终需要签名的文件能够在对应阶段被调用。
配置完成后,可以在 Advanced Installer 的数字签名页面检查:
Files configured for signing
从而确认哪些文件将在构建过程中执行签名。
签名次数
Advanced Installer 可能在一次安装包构建过程中对多个文件分别执行签名。
例如:
| 文件 | 签名 |
|---|---|
app.exe | 1 次 |
helper.dll | 1 次 |
uninstall.exe | 1 次 |
installer.msi | 1 次 |
| 合计 | 4 次 |
因此:
一次构建 ≠ 一次签名
应根据实际完成远程签名的文件或签名动作数量计算。
签名次数
CI/CD 与构建工具通常会自动处理多个产物,因此签名次数需要特别关注。
基本原则:
签名次数 = 实际成功完成的签名动作数量
例如:
app.exe → 1 次
library.dll → 1 次
installer.msi → 1 次
如果三个文件都成功签名:
合计 = 3 次
Electron Builder 和 Advanced Installer 等构建工具还可能自动生成并签名:
- 主程序。
- DLL。
- 更新程序。
- 卸载程序。
- MSI。
- EXE 安装包。
- 其他辅助可执行文件。
因此,应根据构建日志和实际签名产物确认签名次数,而不是按照 Pipeline 或 Build 的执行次数估算。
更多规则请参阅 参考资料。
时间戳
正式发布的软件通常建议添加可信时间戳。
GitHub Actions、Electron Builder 和 Advanced Installer 集成均可以使用 RFC 3161 时间戳,例如:
http://timestamp.acs.microsoft.com
时间戳不属于新的代码签名操作,不单独增加代码签名次数。
不同 TSA 的协议支持和使用限制请参阅 参考资料。
凭证安全
自动化环境中应特别保护:
Access Key
Access Secret
Cert Code
其中 Access Secret 应作为 Secret 管理,不应:
- 提交到 Git 仓库。
- 明文写入公开 Workflow。
- 输出到构建日志。
- 写入公开 Docker 镜像。
- 通过不安全的方式传递给第三方构建系统。
GitHub Actions 建议使用:
GitHub Actions Secrets
其他 CI/CD 系统则应使用其对应的 Secret、Credential 或 Variable 管理机制。
如何选择
| 场景 | 推荐方式 |
|---|---|
| GitHub Actions Workflow | GitHub Actions |
| Electron 应用构建 | Electron Builder |
| MSI / EXE 安装包制作 | Advanced Installer |
| 普通 Shell / PowerShell 自动化 | SignTool CLI |
| Windows 软件原生支持 KSP | Windows Provider |
| 自行开发签名流程 | API 集成 |
如果构建系统能够直接调用命令行程序,可以使用 SignTool CLI;如果工具已经提供标准的 Windows KSP/CSP 接口,则优先使用对应的 Windows Provider 集成方式。