Skip to content

CI/CD 流水线加固核查清单:从可运行到可证明可信

17 min read

CI/CD 流水线加固核查清单:从可运行到可证明可信

很多团队把流水线安全理解为“在 CI 上再加几个扫描任务”。这种做法通常会在审计时看起来合规,但在真实攻击面前很脆弱。原因很简单:攻击者不会按你的任务分组来行动,他们会沿着权限最松、证据最弱、回滚最慢的路径突破。只要流水线里存在一个可横向移动的薄弱点,前面做过的扫描、审批、告警都会被绕开。

这篇文章的目标不是罗列工具,而是给出一套工程化的硬化核查框架:把 CI/CD 作为“生产系统的一部分”来防护,要求每次发布都能被回答清楚四个问题:谁触发、用什么输入、如何构建、为何可信。只有做到“可运行 + 可追溯 + 可证明”,流水线才算真正进入安全可控状态。

1. 先统一威胁模型:你要防的是整条交付链,不是单点漏洞

CI/CD 的风险并不只在代码仓库,也不只在容器镜像。完整攻击路径通常跨越以下环节:开发者身份、代码入口、构建执行器、依赖下载源、制品仓库、部署控制面、运行时准入。任何一环信任模型错误,都会让后续控制形同虚设。

建议把威胁拆成四类并分别设定控制目标:

  1. 身份滥用:令牌泄露、机器人账号过权、审批身份冒用。目标是短期凭证 + 最小权限 + 可审计授权。
  2. 构建污染:恶意脚本注入、第三方 Action 被劫持、Runner 跨任务污染。目标是隔离执行 + 固定输入 + 可复现构建。
  3. 制品篡改:镜像替换、签名伪造、仓库访问绕过。目标是强制签名 + 多点验签 + 来源证明。
  4. 发布越权:绕过门禁直发生产、紧急通道常态化、回滚能力失效。目标是策略即代码 + 例外闭环 + 演练验证。

很多团队在威胁建模阶段最大的误区是“默认平台可信”。实际上,平台也是资产,也会被攻击。你的控制设计必须假设部分组件可能失守,重点建设“纵深防御 + 证据链完整 + 快速止损”。

2. 目标架构:把控制点串成闭环,而不是碎片化勾选

flowchart TD
    A[代码提交与评审] --> B[CI 触发与身份校验]
    B --> C[隔离 Runner 执行]
    C --> D[依赖拉取与来源校验]
    D --> E[测试与策略门禁]
    E --> F[生成制品与 provenance]
    F --> G[制品签名 Sigstore/cosign]
    G --> H[制品仓库存储]
    H --> I[CD 发布审批与策略引擎]
    I --> J[部署前验签与准入控制]
    J --> K[运行时遥测与异常告警]
    K --> L[审计追溯与应急复盘]

这条链路有三个必须坚持的原则:

  1. 前后双重校验。比如构建时签名通过,不代表部署时可跳过验签;仓库存储阶段仍可能发生替换。
  2. 证据不可后补。构建来源证明、审批记录、策略判定结果都要在执行当下自动落盘,不能靠事后人工补文档。
  3. 失败默认阻断。涉及生产发布、签名验证、来源校验等关键节点,只要证据缺失就要阻断,而不是“先发再说”。

3. 身份与权限硬化:流水线最容易被忽视的高危入口

3.1 全面替换长期密钥,统一短期凭证

把云账号 AK/SK、仓库长期 token、固定部署密码写进 CI 变量,是供应链事故中最常见的“低级高危”问题。正确做法是引入 OIDC 联邦身份,按作业运行时换取短期令牌,并绑定受众、仓库、分支、环境等上下文约束。

落地要点:

  • 令牌 TTL 尽可能短,建议分钟级。
  • 令牌绑定作业身份,禁止跨 job 复用。
  • 对高风险动作(生产部署、密钥读写)追加条件约束,例如必须来自受保护分支且通过审批。
  • 所有临时凭证发放行为必须写入可检索审计日志。

3.2 以 Job 为边界做最小权限,而不是以仓库为边界

同一流水线里不同作业的权限需求差异很大:编译任务通常只读源码,扫描任务只读制品,部署任务需要写入目标环境。若采用“整条流水线一个高权 token”,任何单个 job 被攻破都能横向控制全链路。

建议建立“权限矩阵模板”:

  • build 只读仓库、只读依赖代理、可写临时缓存。
  • scan 只读制品与 SBOM,不可触达部署 API。
  • publish 可写制品仓库,不可改源码。
  • deploy-prod 仅在审批通过且变更窗口内可写生产。

3.3 审批与人机身份分离

审批动作必须是“人”做决定,“机”执行动作。审批账号不可直接用于部署执行,部署机器人不可拥有审批权限。人机混用会让问责和溯源链断裂,事故后难以确认是误操作还是恶意行为。

4. 代码入口控制:在进入构建前就减少攻击面

流水线硬化不是从 Runner 开始,而是从代码入口开始。建议至少做到:

  1. 分支保护强制生效。禁止直接推送主干,必须通过受控 PR 合并。
  2. 关键目录双人评审。.github/workflowsDockerfileinfra/helm/ 等目录应提升审查等级。
  3. 提交签名校验。关键仓库启用签名提交或签名标签验证,降低身份伪造风险。
  4. 机密扫描前置。对明文密钥、私钥片段、云凭证模式做 pre-receive 阻断,而不是仅告警。
  5. 第三方 Action 固定到 commit SHA。禁止使用浮动 tag(如 @v3)承载高风险作业。

真实工程里,很多“CI 被攻破”其实是通过代码入口把恶意配置合并进来。入口管控做不好,后面的再多门禁都只是补课。

5. 构建执行面:可复现、可隔离、可销毁

构建系统的核心目标不是“把包编出来”,而是“在受控条件下稳定地产生可验证产物”。

5.1 Runner 隔离策略

  • 优先使用短生命周期 Runner:任务完成即销毁,避免跨任务残留。
  • 禁止共享宿主目录:尤其是缓存、Docker socket、凭证目录。
  • 关闭不必要特权:避免 privileged 容器和主机网络直通成为逃逸入口。
  • 按敏感级别分池:生产发布 Runner 与普通 CI Runner 分离。

5.2 构建可复现策略

  • 锁定工具链版本(编译器、构建工具、基础镜像)。
  • 锁定依赖版本与哈希,禁止隐式升级。
  • 记录构建参数、环境变量白名单、输入摘要。
  • 定期做“同源重建”抽检,验证哈希一致性。

可复现不是学术指标,而是事故处置效率指标。若无法重建同一产物,调查“污染发生在哪一步”会变得极其困难。

5.3 网络与出口控制

构建阶段对外网完全放开,会扩大依赖投毒与数据外传风险。建议:

  • 对依赖下载域名做白名单。
  • 对未知外联做审计并告警。
  • 对上传行为设置策略,禁止任意外部目标。

6. 依赖治理:从“能装上”升级到“可信可审计”

依赖治理不是单次扫描,而是长期供给侧治理。建议构建三层机制:

  1. 来源准入层:只允许受控镜像源或私有代理仓;对新源引入走审批。
  2. 版本策略层:关键依赖使用锁文件;高风险库设置升级窗口和兼容验证流程。
  3. 风险闭环层:漏洞发现后必须有 SLA、负责人、修复证据和到期复审。

对于容器生态,还需要补上基础镜像治理:

  • 固定基线镜像并周期重建。
  • 禁止 latest
  • 对镜像层做漏洞与许可证双检查。

没有治理闭环时,漏洞扫描只会变成“报告生产机”。安全债务会越积越多,最后无人愿意再看扫描结果。

7. 制品可信:签名、provenance、SBOM 三件套缺一不可

7.1 签名不是可选项,而是发布前置条件

建议采用 Sigstore/cosign 为关键制品(容器镜像、二进制包、Helm Chart)签名。签名成功后应立即验证并写入结果,不要把验签延后到事故发生后。

7.2 provenance 让“谁构建的”可验证

按照 SLSA 思路,为每次构建生成 provenance,至少包含:源码引用、构建身份、构建命令、依赖输入、产物摘要、时间戳。部署系统应验证 provenance 是否满足策略,比如必须来自受信构建器、必须由受保护分支触发。

7.3 SBOM 让“用了什么组件”可快速检索

SBOM 不应只是归档文件,而应进入可查询系统,支持按组件、版本、环境、服务维度检索。这样上游披露漏洞时,才能在小时级给出影响面,而不是靠人工全仓库搜索。

8. 发布门禁:把安全决策从“人治”变成“机治”

发布阶段要避免两种常见失败:

  • 一切靠口头审批,审计无法还原。
  • 门禁可被轻易手工绕过,例外没有闭环。

建议引入策略即代码(Policy as Code),把关键规则固化为机器判定:

  • 未签名或验签失败禁止部署。
  • provenance 不满足来源策略禁止部署。
  • 高危漏洞超阈值禁止部署。
  • 非变更窗口或无审批记录禁止部署生产。

同时设计“紧急通道”但要满足三点:

  1. 必须有双人授权。
  2. 必须自动留痕并触发复审。
  3. 必须有时效,过期自动恢复默认门禁。

9. 运行时闭环:上线不是终点,验证才是终点

供应链风险会在运行阶段暴露,因此需要把 CI/CD 与运行时治理打通:

  • Kubernetes 等平台启用准入控制,只允许符合签名和来源策略的镜像运行。
  • 采集运行时镜像摘要,与发布记录进行比对,发现漂移立即告警。
  • 对异常进程行为、异常出网、可疑下载行为做实时检测。
  • 将部署事件、验签结果、策略决策与业务监控统一关联,便于故障定位。

很多团队的痛点是“发布记录在 CI,运行事件在集群,安全告警在另一个系统”。当数据孤岛存在时,取证会慢且容易误判。统一事件模型是必须投入的基础设施能力。

10. 应急与恢复:把最坏情况设计进日常流程

真正的硬化体系必须回答:一旦凭证泄露、制品污染、构建器失陷,团队能多快止损?

建议每季度至少一次联合演练,覆盖三类场景:

  1. 凭证疑似泄露:吊销凭证、轮换密钥、冻结高风险发布、回溯影响作业。
  2. 制品疑似篡改:封禁仓库标签、按摘要筛查部署、强制回滚到可信版本。
  3. 构建器疑似失陷:隔离 Runner 池、切换备用构建集群、重建信任根。

演练验收标准建议量化:

  • 30 分钟内完成首轮影响范围识别。
  • 60 分钟内阻断新增风险发布。
  • 4 小时内完成关键业务恢复路径验证。

11. 度量体系:没有指标就没有治理

建议建立面向平台、应用、安全三方共享的指标看板:

  • 身份维度:长期密钥存量、OIDC 覆盖率、过权账号数量。
  • 构建维度:一次性 Runner 覆盖率、可复现抽检通过率、异常外联次数。
  • 制品维度:签名覆盖率、部署前验签通过率、provenance 完整率。
  • 风险维度:高危漏洞修复时长、例外项超期率、门禁绕过次数。
  • 响应维度:告警到阻断时延、回滚成功率、取证耗时。

这些指标要进入周会而不是只在审计前更新。若指标长期无人消费,流程会迅速回退到“有制度没执行”。

12. 30/60/90/180 天落地路线图

前 30 天:先清理高危暴露面

  • 盘点并替换长期静态密钥。
  • 收敛默认高权权限,按 job 切分权限。
  • 固定第三方 Action 到 commit SHA。
  • 对关键目录启用强制双人评审。

31-60 天:打通可信发布链

  • 为关键制品接入签名和部署前验签。
  • 建立 SBOM 生成、归档、检索能力。
  • 为关键构建输出 provenance 并接入策略校验。

61-90 天:系统化门禁与例外治理

  • 策略即代码全面接入发布流程。
  • 建立例外审批模板、到期复审和补偿控制。
  • 建立联合告警面板,打通 CI/CD 与运行时事件。

91-180 天:组织级运营与持续优化

  • 将关键指标纳入平台与业务团队目标。
  • 定期执行攻防演练与故障复盘。
  • 对高风险链路实施红队验证与外部评估。

13. CI/CD 加固核查清单(可直接对照执行)

A. 身份与权限

  • 生产相关操作已全面使用短期凭证,无长期静态密钥。
  • 权限按 job 切分,默认拒绝,禁止跨环境复用 token。
  • 审批人身份与执行机器人身份分离。
  • 审批、授权、访问行为可追溯并可检索。

B. 代码与配置入口

  • 主干分支启用强制评审与状态检查。
  • CI/CD 配置目录启用更高评审等级。
  • 第三方 Action/插件固定到不可变版本。
  • 机密扫描可阻断,不仅告警。

C. 构建执行与环境

  • Runner 为短生命周期,任务结束后销毁。
  • 构建环境隔离,避免跨任务污染。
  • 工具链与依赖版本锁定,可复现抽检可执行。
  • 外网访问受控并有异常告警。

D. 制品与发布

  • 关键制品全部签名,签名证据可追溯。
  • CD 前强制验签与来源校验。
  • SBOM 与 provenance 与发布版本强绑定。
  • 策略即代码覆盖生产发布,失败默认阻断。

E. 运行时与响应

  • 准入控制能拒绝不可信制品。
  • 运行时镜像摘要与发布记录可自动比对。
  • 供应链应急演练至少季度执行一次。
  • 演练结果能反哺策略与流程。

14. 常见反模式与纠偏建议

反模式一:把安全能力“外挂”在流水线末尾。纠偏:前置入口控制与身份治理,后置只做复核。

反模式二:签名做了但部署不验签。纠偏:把验签作为准入必经路径,失败默认拒绝。

反模式三:例外审批没有时效。纠偏:所有例外必须带到期日、责任人、补偿措施。

反模式四:所有门禁一刀切。纠偏:按业务关键性分层策略,高风险链路严格、低风险链路可渐进。

反模式五:只追求工具数量。纠偏:以“证据链完整”和“响应时效”评估能力,不以工具清单评估成熟度。

15. 结语

CI/CD 安全不是“某次整改项目”,而是持续交付体系的基础能力。真正可用的硬化方案必须同时具备三种属性:可执行、可验证、可复盘。可执行意味着工程团队愿意每天使用;可验证意味着每次发布都能给出机器可读证据;可复盘意味着事故发生后能在最短时间内还原事实并阻断扩散。

当你把这套核查清单落地为平台默认能力,而不是零散脚本和口头约定时,流水线才会从“高价值攻击入口”转变为“可控可信的交付引擎”。这也是 DevSecOps 真正的分水岭。

16. 审计与取证实操模板:保证事故后能还原“完整时间线”

很多组织在平时认为“日志已经很多”,但一旦发生事件,最先暴露的往往是日志不可拼接、字段不一致、时间戳不统一。CI/CD 场景里,审计与取证能力至少要覆盖四条链路:代码事件链、流水线执行链、制品变更链、部署与运行链。四条链路缺任意一条,事故复盘都可能出现关键空洞。

建议定义统一事件模型,至少包含这些字段:事件时间、事件来源系统、操作者身份、目标资源、动作类型、上下文标识(仓库、分支、工作流、构建号、制品摘要、环境)。其中“上下文标识”尤其关键,它决定了你能否把多系统日志串成同一次发布行为。

实际落地时可以采用“事件归一 + 关联键查询”的方法:
第一步,把代码平台、CI 系统、制品仓库、集群平台的关键事件同步到统一审计平台。
第二步,定义关联键,如 commit_shaworkflow_run_idartifact_digestdeployment_id
第三步,为值班团队预置查询模板,例如“按镜像摘要反查触发人和审批人”“按审批单反查发布版本和运行实例”。

只有当查询模板在演练中可用,才说明审计能力真的可落地。否则日志再全,也只是原始材料。

此外,审计日志本身也要做防篡改设计:

  • 关键日志写入后不可修改;
  • 审计存储与业务系统权限隔离;
  • 保留策略覆盖合规要求和故障回溯周期;
  • 对审计系统访问行为进行二次审计。

这套机制的目标不是“满足检查”,而是让团队在高压窗口下也能在分钟级还原事实,避免因为信息不完整导致错误决策。

17. 多平台流水线统一治理:避免“每个仓库一套安全规则”

随着组织规模增长,常见局面是 GitHub Actions、GitLab CI、Jenkins、云厂商流水线并存。若没有统一治理框架,不同平台会出现权限模型、签名流程、门禁阈值、审计字段都不一致的问题。结果是同样级别的系统风险,在不同仓库得到完全不同的防护强度。

建议采用“统一基线 + 平台适配层”的治理方法:

  1. 统一基线层:定义组织不可变控制项,例如短期凭证、关键制品签名、部署前验签、例外到期复审。
  2. 平台适配层:把基线映射到不同 CI 平台实现细节,例如不同的身份联邦配置、不同的策略引擎接入方式。
  3. 服务模板层:为应用团队提供开箱即用模板,减少手工拼装导致的偏差。

治理重点不是“让所有平台长得一样”,而是“让关键控制项效果一致”。评估时应看结果指标而不是配置表面一致性,例如:各平台的签名覆盖率是否接近、验签阻断是否同样严格、例外项是否同样受时效约束。

在组织级推进时,推荐建立“平台治理委员会”或“交付安全例会”,由平台负责人、安全负责人和核心业务负责人共同评审:

  • 基线版本升级计划;
  • 重点风险链路整改状态;
  • 例外项超期清理计划;
  • 重大变更窗口的发布策略。

这种机制能把“平台自说自话”变成“跨团队共同决策”,显著降低治理碎片化。

18. 高压业务窗口策略:在大促、发版季、节假日前如何不失控

业务高峰期最容易触发“先保上线、后补流程”的冲动。若没有提前定义策略,紧急措施会变成长期后门。建议在高压窗口执行分级发布策略:

  • 变更分级:将发布拆为低风险配置变更、中风险逻辑变更、高风险架构变更,分别对应不同审批和门禁强度。
  • 风险预算:提前定义当日允许的高风险变更额度,超额自动冻结。
  • 快速回滚:确保每次发布都有可验证回滚路径,并在发布前完成预演。
  • 值班联动:平台、安全、业务三方进入联合值班,遇到异常直接按剧本处理。

高压窗口并不意味着放松安全,而是要把“默认控制 + 快速响应”做得更严格。成熟团队在大促期间往往更强调门禁自动化,因为人工判断在压力环境下更容易出错。

如果必须启用紧急发布通道,应满足四个约束:

  1. 仅允许受控范围内的最小变更;
  2. 双人审批且审批理由结构化记录;
  3. 发布后自动触发增强监控与回归检查;
  4. 窗口结束自动回收紧急权限。

这四点能把“短期例外”锁在可控范围内,避免被长期滥用。