6.5. 供应链安全:SBOM、签名与准入
供应链安全要回答三个问题:这个镜像从哪来、里面有什么、能不能证明它没被篡改。答案分别是 provenance(来源)、SBOM(物料清单) 和 签名(Sigstore/Cosign),最后由准入控制器验证。
- 层级:
L4 · 实战
- 难度:
进阶
- 预计:
45 分钟
- 前置:
CI/CD、镜像仓库、Kubernetes 准入
6.5.1. 一条可验证的链路
源码 commit → CI 构建 → SBOM → 扫描 → 签名 → 推送 → 准入校验 → 部署
每一步都要留下可追溯的证据:
证据 |
工具 |
作用 |
|---|---|---|
commit |
Git |
代码来源 |
SBOM |
Syft/Trivy |
依赖与版本 |
漏洞报告 |
Trivy/Grype |
已知风险 |
签名 |
Cosign/Sigstore |
完整性与发布者 |
证明 |
SLSA provenance |
构建过程可信 |
准入 |
Kyverno/Gatekeeper |
拒绝不合规镜像 |
6.5.2. SBOM 与扫描
syft ghcr.io/example/demoapp:v1.0 -o spdx-json > sbom.spdx.json
trivy image --format cyclonedx --output sbom.cdx.json ghcr.io/example/demoapp:v1.0
trivy image --severity HIGH,CRITICAL --exit-code 1 ghcr.io/example/demoapp:v1.0
SBOM 要归档到制品仓库或 OCI Artifact,并与 digest 绑定。扫描策略要明确:哪些漏洞阻断、哪些可豁免、豁免多久复审。
6.5.3. 签名与验证
cosign generate-key-pair
cosign sign --key cosign.key ghcr.io/example/demoapp@sha256:<digest>
cosign verify --key cosign.pub ghcr.io/example/demoapp@sha256:<digest>
生产建议用 keyless(OIDC + Fulcio + Rekor)或 KMS 托管密钥;私钥不要放在 CI 变量里。签名对象是 digest,不是 tag;tag 可变,digest 不可变。
6.5.4. 准入校验
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: verify-image-signature
spec:
validationFailureAction: Enforce
rules:
- name: verify-cosign
match:
any:
- resources:
kinds: [Pod]
verifyImages:
- imageReferences:
- "ghcr.io/example/*"
attestors:
- entries:
- keys:
publicKeys: |-
-----BEGIN PUBLIC KEY-----
...
-----END PUBLIC KEY-----
准入控制器要能访问 Rekor/Fulcio 或公钥;离线环境要提前同步。策略先 Audit,确认镜像覆盖率后再 Enforce,避免把存量应用全部拒绝。
6.5.5. SLSA 与 provenance
SLSA 等级描述构建过程的防篡改能力:
L1:构建脚本有文档,产出 provenance。
L2:托管构建服务,签名 provenance。
L3:隔离、不可变构建环境,强 provenance。
多数团队先做到 L2:CI 生成 provenance,Cosign 签名,准入验证。不要为了等级而等级;先保证「能追溯、能验证、能阻断」。
6.5.6. 镜像仓库与保留
使用 Harbor/云仓库,开启不可变 tag、漏洞扫描、复制策略。
只保留可部署的 digest 与 SBOM,定期清理旧 tag。
生产部署用 digest;回滚用旧 digest,不重新构建。
仓库凭证用 robot account/短期 token,最小权限。
6.5.7. 实验:从构建到准入
构建镜像,生成 SBOM 并扫描。
用 Cosign 签名 digest。
在 kind 集群安装 Kyverno,配置验签策略。
部署已签名镜像 → 通过;部署未签名镜像 → 拒绝。
查看拒绝事件与策略报告。
6.5.8. 验证清单
每个生产镜像有 digest、SBOM、扫描报告、签名。
CI 对 HIGH/CRITICAL 漏洞有明确阻断/豁免策略。
准入控制器验证签名,未签名镜像被拒绝。
私钥不在 Git/CI 明文变量中。
镜像仓库开启不可变 tag 与漏洞扫描。
回滚使用旧 digest,不重新构建。
6.5.9. 排错表
现象 |
原因 |
处理 |
|---|---|---|
验签失败 |
签的是 tag/digest 不一致 |
用 digest 重新签/部署 |
准入拒绝所有 Pod |
策略范围过宽 |
先 Audit,限定镜像前缀/命名空间 |
Kyverno 无法访问 Rekor |
网络/证书 |
配置代理或离线公钥 |
扫描结果差异大 |
数据库未更新/扫描器不同 |
固定 DB 更新时间与工具版本 |
镜像被覆盖 |
tag 可变 |
开启 immutable tag,使用 digest |
6.5.10. 进阶挑战
用 Cosign keyless 签名并在 Kyverno 验签。
生成 SLSA provenance 并归档到 OCI Artifact。
给漏洞豁免加过期时间与审批。
把「未签名镜像」加入 CI 门禁。
6.5.11. 小结
供应链安全的核心是「来源可追溯、内容可验证、部署可阻断」。
SBOM、签名、provenance 要与 digest 绑定。
准入策略先 Audit 后 Enforce,避免误伤存量。
没有签名的镜像不应该进入生产。