如何在 CI/CD 流水线中安全地存储和使用签名密钥?
解读
面试官问的不是“怎么签名”,而是“怎么在自动化流程里既能让构建服务器拿到密钥,又不让密钥泄露”。国内场景下,代码仓库往往放在 GitLab-EE 或私有 Gitea,构建节点既跑在阿里云/腾讯云 ECS,也跑在本地机房 KVM;既要对接 fir.im、蒲公英、华为 AppGallery,又要兼容 Google Play AAB。密钥一旦泄漏,不仅攻击者可以伪造升级包,还可能被监管机构认定为“未履行个人信息保护义务”,带来合规风险。因此,回答必须兼顾“技术可行性 + 国内合规 + 成本可控”。
知识点
- 密钥形态:上传密钥(upload key)、发布密钥(release key)、v1/v2/v3/v4 签名方案、PEPK 工具、Google Play App Signing 的“分离密钥”模型。
- 国内合规:GB/T 35273 个人信息安全规范要求“密钥不应明文存储在代码仓库”,等保 2.0 要求“密钥托管在密码产品或硬件模块中”。
- 机密管理方案:
- 云原生:阿里云 KMS、腾讯云 KMS、华为云 KMS、AWS KMS(外企)。
- 私有:HashiCorp Vault 开源版、GitLab CI/CD Variables(文件类型)、Jenkins Credentials + Mask Passwords。
- 构建工具链:Gradle Android Plugin 7.x 支持 signingConfigs {} 从环境变量读取密钥库密码、keyAlias、keyPassword;R8/ProGuard 规则需排除签名相关日志。
- 最小权限原则:CI Runner 仅对“构建阶段”开放 KMS 解密权限,打包完成后立即清理临时文件;使用 tmpfs 挂载 /tmp,防止密钥落盘。
- 审计与轮换:CI 侧记录“哪次 Job 使用了哪个密钥版本”,通过 KMS 自动轮换或手动生成新密钥并上传 PEPK 加密包到 Google Play;国内渠道需同步更新公钥指纹到华为、OPPO、vivo 后台。
- 双轨签名:海外渠道走 Google Play App Signing,国内渠道走“上传密钥”自行管理,降低单点泄漏风险。
答案
国内落地可按“三层防护”实施:
- 密钥生成与拆分:在离线加密机或国密合规的 USBKey 内生成 release.jks,导出加密分片(KMS 加密后的 base64)后删除本地明文;上传密钥与发布密钥分离,上传密钥仅用于 CI,发布密钥由法人保管。
- 机密注入:
- GitLab CI:在“设置-CI/CD-变量”里创建文件类型变量 RELEASE_KEYSTORE,内容填 KMS 加密后的 base64;再创建普通变量 KEYSTORE_PWD、KEY_ALIAS、KEY_PWD,全部开启“隐藏”与“受保护分支”标志。
- Runner 侧:使用阿里云 KMS 的“凭据管家”角色,绑定 RAM 策略仅允许 decrypt 指定密钥 ID;构建脚本先用 aliyun-kms-cli 解密拿到临时 keystore,写入内存盘 /dev/shm/keystore.jks,再执行 ./gradlew assembleRelease。
- 构建与销毁:Gradle 配置 signingConfigs.release 只读环境变量,构建完成后立即 rm -f /dev/shm/keystore.jks,并通过 find /build -name "*.jks" -delete 二次清扫;CI 日志开启“掩码”功能,防止密码被打印。
- 合规审计:在 KMS 侧开启“密钥使用日志”投递到日志服务 SLS,保存 180 天;每次发版 Merge Request 必须附带“密钥版本号 + 审计日志截图”,由安全团队 review。
- 轮换机制:每 90 天触发一次“上传密钥”轮换,使用 Google Play PEPK 工具生成新加密包,同时在华为、小米后台更新指纹;旧版本密钥立即吊销,CI 变量同步更新。
一句话总结:把密钥托管在“云 KMS + 内存盘 + 最小权限 RAM 角色”里,构建时临时解密、用完即毁,配合审计与轮换,就能在 CI/CD 中既安全又合规地使用签名密钥。
拓展思考
- 如果公司完全离线、不能上云,如何用 Vault + PKCS11 硬件密码机在本地 Jenkins 实现同等安全等级?
- 当团队扩大到 200 人、每日 500 次构建,如何基于 Kubernetes CSI 驱动把 KMS 解密挂载为只读 Volume,避免每个 Runner 都调用一次 decrypt 产生费用热点?
- 国内厂商要求“渠道包”使用不同 RSA 密钥,如何设计一条流水线同时输出 30 个渠道包,而只解密一次主密钥,其余使用派生密钥?
- 未来 AOSP 可能强制要求 APK Signature Scheme v4 中的“密钥轮换证明”,CI 侧如何提前集成 Android Keystore Key Attestation 验证,防止上传已被轮转的废密钥?