第42章|GitLab CI 安全与合规:variables、protected branches 与审计

流水线不只是“跑脚本”,它是能触达生产与机密的自动化账户。本章把 GitLab 里的安全旋钮拧成一条清晰链路: 变量分级(谁能看见、何时注入)、保护分支(谁能改、谁能合)、 审计与审批(谁在何时做了什么)。目标很简单:最小权限 + 可追责 + 可复盘——让交付快,但不把钥匙插在门锁上。

Variables

Secrets & scope

  • masked / protected
  • environment scope
  • file & external
Branches

Who moves code

  • protected refs
  • merge & push rules
  • pipeline trust
Compliance

Prove it

  • audit events
  • approvals
  • retention

1. 威胁模型:CI 是“高权限机器人”

Runner 执行你的脚本时,往往持有部署凭证、云 API、数据库连接串。攻击路径包括:恶意 MR 窃取变量、误配的缓存与制品、 被攻破的分支直接推生产脚本、以及内部人员越权操作。治理抓手要同时覆盖身份(谁)引用(哪条分支/tag)执行语境(MR 还是主干)事后证据(审计日志)

Defense in depth (GitLab delivery plane) Each layer reduces blast radius; none replaces code review Identity & role (who can change CI / vars) Protected branches / tags (what refs are sacred) CI/CD variables (masked · protected · scoped) Runner & executor isolation Runtime gate + evidence MR / fork policy Require maintainer to run untrusted pipelines Separate secrets for external contributors Deployments Protected environments · approvals (next chapter deepens) Audit log & compliance exports Variable change · protected branch edit · pipeline job ownership Retention aligned with policy (SOC2 / ISO workflows)
图 1:从身份与引用到机密与执行隔离,最后用审计闭环——纵深防御不是单点产品功能。

2. CI/CD 变量:masked、protected 与作用域

变量可在实例 / 组 / 项目等层级定义,并支持 environment scope(限定到某环境名,如 production)。 Masked:在日志与 UI 中隐藏值(仍要满足格式要求,且不是加密万能药)。 Protected:仅在受保护分支/tag触发的 pipeline 中注入,避免特性分支流水线拿到生产密钥。

# Reference in job (value comes from GitLab UI / API settings)
deploy_stage:
  stage: deploy
  script:
    - deploy --token "$DEPLOY_TOKEN"
  environment:
    name: staging
实践:把生产级机密设为 protected + masked;用 environment scope 把 staging / prod 密钥拆开; 长期方案是接 HashiCorp Vault、云 KMS、OIDC 短时凭证,变量里只放“如何取秘密”的配置而非秘密本体。
标志 意图 典型误用
Masked 减少日志泄露面 以为“已加密”;短字符串无法 mask
Protected 绑定受保护 ref 全设为 unprotected 以“省事”
Environment scope 同名变量在不同环境取值 scope 过宽导致 prod 密钥进错 job

文件型变量与短时凭证

平台支持将文件内容作为变量注入(适用于 kubeconfig、客户端证书等场景),减少把多行 PEM 硬编码进脚本。 中长期仍建议把“长期有效的高权限凭证”迁出 GitLab:OIDC / JWT 对接云厂商 IAM、或 Vault / 云 Secret Manager 在 job 内动态拉取短时 token,缩小泄露窗口。

3. Protected branches & tags:改代码与打标签的阀门

受保护分支定义谁能 push、谁能 merge,常与 Code Owners、required approvals、CI 成功检查一起构成合并门禁。 受保护标签则保护发布标签不被随意挪动——对语义化版本与制品追溯至关重要。 把“能合进 main”与“能在 main 上跑带 protected 变量的流水线”对齐,是变量策略生效的前提。

Protected ref ↔ protected variables feature/* (unprotected ref) Pipeline runs · CI for dev feedback Unprotected variables only (by design) Fork MR: tighten who can run pipelines main / release-* (protected) Merge + tag pipelines · release jobs Protected + masked secrets available Still require human approval for prod deploy (policy)
图 2:受保护引用与受保护变量成对出现;特性分支默认不该继承生产级机密。

4. Fork、外部贡献与流水线信任

公开项目常遇到 fork MR:默认若允许在 upstream 跑流水线,恶意改动可能试图打印变量、发外联请求、挖矿。 GitLab 提供多种项目设置(例如由维护者批准后才运行流水线、限制 fork pipeline 的权限)。平台工程团队应把这项写进贡献指南 + 组织基线

5. 审计、审批与留存

Audit events(具体可用性与许可依 GitLab 版本与 tier 而定)记录关键操作:受保护分支变更、变量增删、成员角色变化等。 运维与合规团队通常把这些事件流导入 SIEM,并设定留存周期满足审计要求。 与 CI 搭配时,还要关注 job 日志、部署记录、制品下载 的访问控制与脱敏。

Evidence pipeline (not the CI YAML kind) GitLab audit settings · group · project vars · refs · members SIEM / log store correlate with cloud & IdP alerts on privilege change Human process ticket · CAB · post-incident review Retention: match legal & customer contracts Map controls to SOC2 CC6 / ISO A.12
图 3:技术事件进日志栈,流程上对接审批与留存——合规是“产品 + 流程”的乘积。

6. 基线清单(可直接当团队规范草案)

  1. 区分 build-timedeploy-time 机密;生产机密默认 protected + scoped。
  2. 梳理 Maintainer/Owner 人数;变量与受保护分支变更走双人复核。
  3. 为 fork / 外部贡献启用维护者批准流水线或等价控制。
  4. 开启并导出审计事件;与 IAM 变更告警联动。
  5. 每季度做秘密轮转与“是否还能缩小变量面”的复盘。
Least privilege rotate · review · measure security is a moving train — re-check each release
图 4:权限与机密不是一次性配置,而是随组织演进的“活”护盾。

7. 与下一章的衔接

受保护环境与 environment 级审批、Review App 的生命周期,将在下一章与 CD 场景结合展开;本章打牢的是谁有权动配置、谁有权触达机密、如何留痕

← 上一章:缓存与制品 下一章:environments 与 review apps →