第56章|GitOps 安全:签名验证、策略控制与多团队协作

GitOps 把“要部署什么”写进仓库,但安全问题不会因为换了工具就自动消失。 更现实的世界是:有人可以提交恶意变更,有人可以篡改镜像,有人可以绕过流程在集群里改字段。 本章给你一套工程化的答案:用签名(signing)证明“是谁做的”,用策略(policy)证明“允许什么”, 再用多团队边界让协作既快又稳。你会把风险从“不可见的黑洞”变成“可拒绝、可解释、可审计”的机制。 安全不靠祈祷,靠可验证的流程。

Trust

Sign what matters

  • commits / tags
  • container images
  • config bundles
Policy

Allow with rules

  • OPA / Gatekeeper
  • admission control
  • deny with reasons
Operate

Collaborate safely

  • team boundaries
  • promotion workflow
  • audit & incident

1. 威胁模型:GitOps 不是“更安全”,而是“更可治理”

在开始堆砌工具前,先把黑箱打开。典型威胁包括: 仓库侧攻击(恶意 commit、供应链依赖被投毒、PR 规则被绕过); 交付侧攻击(manifest / Helm values 被篡改、镜像被替换); 集群侧攻击(kubectl 直连导致的 drift、越权写入、凭据泄露)。 GitOps 的优势在于:你能把“期望状态”固定在 Git,并且在应用前后插入校验与拒绝逻辑。 安全的目标就是:让非法变更无法到达数据面(data plane),并且让拒绝可解释、可审计。

威胁点 常见后果 GitOps 可插入的控制
Malicious commit 不该部署的变更上生产 commit signing + PR policy + required reviews
Image supply chain 镜像替换、依赖投毒 cosign verification + SBOM attestations + allowlist
Cluster tampering drift、越权写入 admission control + selfHeal / prune + audit logs
GitOps Security: sign → verify → policy admit → reconcile → audit Developer commit signing / PR reviews sign commit & tag include identity CI / Signing services cosign sign images · attest SBOM · verify refs artifact signature + transparency log rekor / certificate policy publish verified outputs Admission / Policy OPA Gatekeeper or validating webhook verify signatures & allow rules deny with reason Reconcile controller applies only when policy allows Audit logs show signatures, rules, decisions
图 1:真正的安全,是把“签名证明身份”与“策略证明允许”绑定到同一条可追溯链路。

2. 签名(Signing):把“可信”写进证据链

GitOps 的签名可以有多层。你不必一口气全部启用,但要形成“最小可用集合(minimum viable trust)”: 提交签名(commit/tag signing)用于证明 Git 历史的身份可信; 镜像签名(container signing)用于证明运行时制品的来源; 配置/打包签名(config bundles / chart provenance)用于证明交付产物未被篡改。 当这些证据进入 admission/policy,系统就能在 apply 前拒绝非法输入。

Layered trust: commit → config → image → admission decision Commit / Tag who authored the change signature + identity Config bundle provenance for manifests signed chart / values Image runtime executable identity cosign signature Admission allow / deny decision verify evidence and apply policy
图 2:信任不是一个开关,而是一叠“证据”在 admission 处交汇。

3. 验证(Verification):把 cosign 的结果变成可拒绝的信号

签名验证最好发生在两个层级:一是 CI(快速失败、早期反馈),二是 admission(真正阻断)。 以 cosign 为例,你会校验证书身份、仓库/镜像引用、以及是否存在不可变的透明度记录。 当验证失败,策略引擎应返回明确原因:缺签名、签名身份不匹配、证书已吊销、或证据不在 allowlist 内。

# Illustrative cosign verification commands (adjust for your policies)
cosign verify \
  --key k8s://cosign-public-key/production \
  registry.example.com/payments-api:v1.2.3

# Verify with identity constraints (example)
cosign verify \
  --certificate-identity "builds@company.com" \
  --certificate-issuer "https://token.actions.githubusercontent.com" \
  registry.example.com/payments-api:v1.2.3
底线:不要只做“CI 里绿了就行”。一旦出现绕过(例如分支规则漏洞、工具逃逸),admission 才是最后防线。 并且拒绝必须“可解释”,否则安全会被当成玄学,团队会集体绕开它。

4. 策略控制(Policy):用 OPA / Gatekeeper 写“允许什么”

政策引擎的职责是把安全目标翻译成可判定的规则。建议你把策略按层级拆分: Repository & scope:限制 Application 指向哪些仓库、哪些命名空间; Workload rules:限制使用哪些镜像来源、是否必须存在签名/注释; Admission blocking:在无法验证时直接 deny。 OPA(Rego)让规则可读、可测;Gatekeeper 或其他 webhook 负责把规则执行嵌入集群。

OPA decision flow: evaluate → reason → allow/deny Input manifest + signatures + namespace Evaluate rego rules (identity, allowlist, SBOM) Result allow or deny with reason signature required? if missing → deny identity match? else → deny reason allow → admit request policy satisfied?
图 3:策略不是“让你心里踏实”,而是要给出可操作的 deny reason。
# Illustrative Rego policy snippet (deny unsigned images)
package gitops.security

deny[msg] {
  input.request.operation == "CREATE"
  some c
  c := input.review.object.spec.containers[_]

  image := c.image
  not has_valid_signature(image)
  msg := sprintf("image %v is missing a valid signature", [image])
}

# Placeholder for your integration (cosign verifier / signature store)
has_valid_signature(image) {
  # Implement lookup against your verification service or attestation store
  true
}

5. 多团队协作:边界、升级与“可解释的审批”

真正让团队在速度与安全之间不打架的,是协作模型。你需要三件事: 边界(谁能指向哪些仓库/集群/命名空间); 升级链路(dev → staging → prod 的 promotion workflow); 审批与审计(审批由什么触发、审批的理由如何固化进证据)。 对 Argo CD 来说,AppProject 的范围限制就是边界;对 Flux 来说,依赖图 + 多层 Kustomization 也是边界。 无论选哪个系统,多团队的基本做法都是:每个团队拥有自己的仓库与环境覆盖面,平台团队提供“受控的平台 root”。

Multi-team governance: boundaries + promotion + audit evidence Platform team CRDs · policy · admission · monitoring root patterns AppProject/Kustomization Team A repo: payments · namespace: team-a-payments PR review + signed commit required checks promote to staging/prod Team B repo: orders · namespace: team-b-orders image signatures & SBOM attestations enforced by admission audit trail in deny/allow logs
图 4:多团队的安全边界来自“受控的能力”,不是靠所有人自觉。

6. 运维要点:密钥轮转、吊销与事故响应

一旦进入签名验证与策略阻断,你就需要把“密钥生命周期”写进日常: 密钥轮转要考虑兼容窗口(dual trust), 吊销要能快速传播到验证服务或证据存储, 事故响应要能解释为何拒绝了某些变更、哪些证据缺失或失效。 最后别忘了:策略引擎与验证服务自身也要有审计与可观测性。

Key lifecycle: rotate with dual trust, revoke with fast propagation Key A active normal verification Dual trust window accept A + B signatures for safe rotation Revoke & replace deny invalid evidence quickly
图 5:密钥轮转必须“兼容”,吊销必须“快且可解释”。

7. 本章清单

  1. 能描述至少三类 GitOps 威胁:仓库侧、交付侧、集群侧,并知道对应控制点。
  2. 理解多层签名:commit/tag、config bundles、container images,并知道它们如何进入验证链路。
  3. 能写出可落地的 verification 规则:CI 快速失败 + admission 最终阻断。
  4. 会用 OPA(Rego)表达 allow/deny 逻辑,并保证 deny 返回可解释 reason。
  5. 能为多团队设计边界与 promotion:仓库分层、namespace 隔离、必要的审批与审计证据固化。
  6. 知道密钥轮转与吊销的运维策略:dual trust、快速传播、事故可追溯。
  7. 预告下一章:进入 Spinnaker 入门,对比 GitOps 与经典 CD 平台的编排方式。
← 上一章:Flux 入门 下一章:Spinnaker 入门 →