深色模式
供应链安全与镜像签名
摘要:本文面向需要保证"进集群的镜像确实来自可信来源、未被篡改"的平台工程师。覆盖 sigstore/cosign 的签名与验证(keyless 与密钥)、SBOM 关联,以及在准入阶段强制校验签名的几种方案。适用版本:cosign v2.x(CLI)、Kubernetes v1.28+。
适用版本与前提
- Kubernetes:v1.28+;cosign v2.x;需镜像仓库与 OIDC 身份(keyless 签名)
- 已了解 OPA/Gatekeeper 的准入模型(签名验证需借助专门 webhook)
为什么需要镜像签名
未签名镜像面临多种供应链攻击:typosquatting(同名仿冒)、托管站点被篡改、发布后被替换。数字签名让消费方验证:镜像来自预期来源且签名后未被改动。Kubernetes 本身不校验镜像签名——这必须在准入阶段补上,否则"供应链安全"只停在构建侧。
sigstore / cosign 的核心思想
Sigstore 是 OpenSSF 下的开源项目,用身份驱动的短期密钥替代传统长期密钥对:
- Cosign:推荐的签名/验证 CLI。
- Fulcio:短期证书颁发机构(CA),用 OIDC 身份(GitHub/Google/Microsoft)签发与公钥绑定的短期证书。
- Rekor:防篡改的公开透明度日志,记录签名事件(证书+签名+摘要),可公开审计。
签名后私钥即丢弃(ephemeral key),无需管理长期私钥,规避了"私钥泄漏/吊销"难题。
两种签名方式
Keyless(推荐,无需管密钥)
bash
# 登录 OIDC(GitHub 等)后直接签名,私钥用完即弃
cosign sign $IMAGE_URI_DIGEST1
2
2
验证时按身份匹配:
bash
cosign verify $IMAGE_URI_DIGEST \
--certificate-identity=name@example.com \
--certificate-oidc-issuer=https://accounts.example.com1
2
3
2
3
也可放宽用正则(注意放宽会降低安全性):
bash
cosign verify $IMAGE_URI_DIGEST \
--certificate-identity-regexp='.*@example.com' \
--certificate-oidc-issuer-regexp='https://accounts.example.com'1
2
3
2
3
密钥方式(air-gapped / 自管 CA)
无外网 OIDC 的场景用本地密钥对:
bash
# 生成密钥对(生成 cosign.key / cosign.pub)
cosign generate-key-pair
# 用私钥签名
cosign sign --key cosign.key $IMAGE_URI_DIGEST
# 用公钥验证
cosign verify --key cosign.pub $IMAGE_URI_DIGEST1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
密钥方式的密钥管理负担
密钥方式把"私钥安全保管/轮换/吊销"的责任交给你。私钥泄漏等同于签名能力丧失。优先 keyless;仅当无法访问外部 OIDC/Rekor 时(如离线环境)用密钥并配严格密钥管理。[版本相关:离线环境的 Rekor 替代(如私部 sigstore 栈)需单独评估]
签名 + SBOM
Cosign 还能签署 SBOM(软件物料清单),配合 in-toto attestation 在策略系统中增加语义层:
bash
# 生成并签署 SBOM(示例,工具依环境而定)
cosign attest --key cosign.key $IMAGE_URI_DIGEST --predicate sbom.spdx.json --type spdx1
2
2
未实测
SBOM 生成工具(syft 等)与 attestation 的端到端流水线各环境差异较大,本文命令为示意,生产前请结合实际工具链验证 [未实测]。
在 Kubernetes 准入阶段强制验证
镜像签名本身不改变 K8s 行为;必须在准入强制验证,否则未签名镜像仍可运行。常见方案(均非 K8s 内置,需额外部署):
| 方案 | 形态 | 说明 |
|---|---|---|
Kyverno verifyImages | Policy engine | 用 verifyImages 规则在创建时校验 cosign 签名,支持 mutation 改写镜像为 digest |
| Connaisseur | Validating webhook | 专为签名验证设计,校验 cosign/notary 签名 |
| sigstore policy-controller | Validating webhook | sigstore 官方,基于 cosign 验证 + 策略 |
| Gatekeeper + 外部数据 | 需扩展 | 本身不直接验签,可配合外部数据源(见 OPA/Gatekeeper) |
Kyverno verifyImages 示意(概念)
yaml
# Kyverno ClusterPolicy 片段(示意,非本文主战场)
spec:
rules:
- name: verify-signature
match:
resources:
kinds: ["Pod"]
verifyImages:
- imageReferences: ["registry.internal.example.com/*"]
attestors:
- entries:
- cosign:
certificate:
identity: ".*@example.com"
issuer: "https://accounts.example.com"1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
验证 webhook 失败的取舍
与 Gatekeeper 同理,签名验证 webhook 不可用时,按 failurePolicy 决定放行或拒绝。若 Fail,webhook 故障会阻断所有镜像创建;若 Ignore,故障期间未签名镜像可被放行。需结合可用性定级,并对 Ignore 配告警。[版本相关:具体方案与版本兼容性需核对]
生产落地步骤
- 构建侧签名:CI 中用 cosign 对每次推送的镜像签名(keyless 或密钥)。
- 策略侧强制:部署验证 webhook(Kyverno/Connaisseur/policy-controller),先
dryrun/audit观察,再enforce。 - 基线配合:配合 OPA/Gatekeeper 的镜像仓库白名单,双保险(来源 + 签名)。
- 镜像用 digest 而非 tag:准入验证基于 digest,避免 tag 漂移导致签名失效。
回滚与清理
- 验证策略先
dryrun后enforce,回滚即改回dryrun。 - 密钥方式更换密钥需重新签名全部在用镜像,并同步更新验证端公钥——这是密钥方式的主要运维成本。
参考资料
- Sigstore 官方文档 - Overview,访问日期:2026-10-08。
- Sigstore Quickstart with Cosign,访问日期:2026-10-08。
- cosign GitHub 仓库,访问日期:2026-10-08。
- Kyverno 官方文档 - verifyImages,访问日期:2026-10-08。
- Connaisseur 项目,访问日期:2026-10-08。