saschagrunert/nri-supply-chain
GitHub: saschagrunert/nri-supply-chain
基于 NRI 的容器运行时级供应链证明验证插件,在容器创建阶段强制校验 SLSA、VEX 和 VSA 证明,实现无法被 Kubernetes API 层绕过的镜像来源验证。
Stars: 1 | Forks: 0
# 供应链 NRI Plugin
[](https://github.com/saschagrunert/nri-supply-chain/actions/workflows/ci.yml)
[](https://github.com/saschagrunert/nri-supply-chain/actions/workflows/deploy.yml)
[](https://github.com/saschagrunert/nri-supply-chain/releases/latest)
[](https://codecov.io/gh/saschagrunert/nri-supply-chain)
[](https://pkg.go.dev/github.com/saschagrunert/nri-supply-chain)
一个用于在容器 runtime 级别进行供应链证明验证的 [NRI](https://github.com/containerd/nri) plugin。它会拦截 [CRI-O](https://cri-o.io) 或 [containerd](https://containerd.io) 上的容器创建事件,并在容器被允许运行之前验证 SLSA provenance、VEX 和 VSA 证明。
Runtime 级别的强制执行无法通过配置错误的 admission webhook、被禁用的策略控制器或直接的 kubelet API 调用来绕过。该 plugin 运行在 Kubernetes API 层之下,因此在节点上运行的每个容器都必须通过验证。
- [快速入门](#quickstart)
- [兼容性](#compatibility)
- [架构](#architecture)
- [验证](#verification)
- [配置](#configuration)
- [部署与示例](#deployment-and-examples)
- [运维](#operations)
- [验证发布版本](#verifying-releases)
## 快速入门
1. 从 [发布页面](https://github.com/saschagrunert/nri-supply-chain/releases) 下载最新的发布版二进制文件或容器镜像。
2. 创建一个配置文件 (`config.toml`):
verification = "enforce"
policy_dir = "/etc/nri-supply-chain/policies"
3. 创建一个默认策略 (`/etc/nri-supply-chain/policies/default.json`):
{
"trust": {
"issuers": ["https://token.actions.githubusercontent.com"],
"sanPatterns": ["https://github.com/saschagrunert/nri-supply-chain/**"],
"sources": ["github.com/saschagrunert/*"]
},
"slsa": { "missingPolicy": "deny" },
"vex": { "missingPolicy": "deny" }
}
4. 验证单个镜像以测试配置:
nri-supply-chain --config config.toml \
--verify-image ghcr.io/saschagrunert/nri-supply-chain:0.1.5
输出为包含各项检查详细信息的 JSON:
{
"image": "ghcr.io/saschagrunert/nri-supply-chain:0.1.5",
"digest": "sha256:1a8b39eeff74b8bb3e20c7f9fa773d4a9935241f7cc4e1217067c8186c2cee3c",
"namespace": "default",
"allowed": true,
"checkResults": [
{
"type": "slsa",
"passed": true,
"status": "pass",
"detail": "SLSA provenance verified"
},
{
"type": "vex",
"passed": true,
"status": "pass",
"detail": "VEX verification passed"
}
]
}
要启用 VSA 加速的验证,请添加一个 `trust.verifiers` 条目。受信任的 VSA 会对 SLSA 和 VEX 检查进行短路(跳过后续检查):
{
"trust": {
"issuers": ["https://token.actions.githubusercontent.com"],
"sanPatterns": ["https://github.com/saschagrunert/nri-supply-chain/**"],
"sources": ["github.com/saschagrunert/*"],
"verifiers": [
{
"id": "https://github.com/saschagrunert/nri-supply-chain/.github/workflows/release.yml"
}
]
},
"slsa": { "missingPolicy": "deny" },
"vex": { "missingPolicy": "deny" }
}
使用此策略后,输出变为:
{
"image": "ghcr.io/saschagrunert/nri-supply-chain:0.1.5",
"digest": "sha256:1a8b39eeff74b8bb3e20c7f9fa773d4a9935241f7cc4e1217067c8186c2cee3c",
"namespace": "default",
"allowed": true,
"reason": "VSA verification passed, skipping direct verification",
"checkResults": [
{
"type": "vsa",
"passed": true,
"status": "pass",
"detail": "VSA verification passed"
}
]
}
在 `enforce` 模式下,未通过验证的镜像将被拒绝。使用
`verification = "warn"` 可以在不进行拒绝的情况下观察哪些内容会被阻止。有关完整的验证流程,请参阅 [docs/verification.md](docs/verification.md)。
5. 部署 plugin(有关所有选项,请参阅 [部署](docs/deployment.md)):
kubectl apply -f deploy/kubernetes/
6. 检查日志和指标以观察验证决策。
## 兼容性
| 组件 | 支持版本 |
| ---------- | ------------------- |
| Kubernetes | 1.26+ |
| CRI-O | 1.28+ (启用 NRI) |
| containerd | 1.7+ (启用 NRI) |
| NRI | 0.6+ |
| Go (构建) | 1.26+ |
必须在容器 runtime 配置中启用 NRI。有关详细信息,请参阅 [Runtime 要求](docs/deployment.md#runtime-requirements)。
## 架构
该 plugin 作为一个长期运行的进程运行,通过 NRI 连接到容器 runtime。它暴露 Prometheus 指标,并支持通过 SIGHUP 进行实时的配置重载。
启动时,NRI Synchronize 回调会传递节点上已经运行的 pod 和容器列表。该 plugin 收集它们的镜像引用,并在需要时通过 registry 的 `HEAD` 请求来解析缺失的 digest(例如,在 containerd 中,NRI annotation 可能会省略 digest)。它按 digest 和 namespace 进行去重,然后生成一个后台 goroutine 对每个镜像进行预验证。这会预热缓存,以便在这些容器重启时可以立即获得验证结果,从而避免冷缓存抓取造成的性能损失。
## 验证
该 plugin 验证 SLSA provenance、VEX 和 VSA 证明。它从 CRI-O 或 containerd 的 NRI annotation 中提取镜像引用和 digest,通过 registry 的 HEAD 请求解析缺失的 digest,并应用基于 namespace 的策略。来自受信任验证器的 VSA 可以短路所有其他检查。
有关完整的验证流程、annotation 处理细节以及各类型的检查,请参阅 [docs/verification.md](docs/verification.md)。
## 配置
该 plugin 使用两个配置层:
- **操作配置** (TOML):控制 plugin 的行为(模式、超时、缓存、指标)。有关完整的字段参考和 CLI 标志,请参阅 [docs/config.md](docs/config.md)。
- **策略文件** (JSON):定义每个 namespace 的信任根和验证要求。有关字段参考、模式匹配语义和部署模式,请参阅 [docs/policy.md](docs/policy.md)。
## 部署与示例
有关所有部署选项(DaemonSet、systemd、DEB/RPM、容器镜像、预安装的 NRI plugin)和示例配置(逐步推出、严格的生产环境、VSA 加速),请参阅 [docs/deployment.md](docs/deployment.md)。
请参阅 [`deploy/examples/policies/`](deploy/examples/policies/) 获取开箱即用的策略文件,涵盖无密钥、基于密钥、严格 VEX、VSA 加速以及其他场景。
## 运维
该 plugin 暴露 Prometheus 指标、`/healthz` 和 `/readyz` endpoint,并支持通过 SIGHUP 或文件系统监视进行实时的配置重载。有关指标参考、告警规则、故障排除指南、内部限制和安全注意事项,请参阅 [docs/operations.md](docs/operations.md)。
## 验证发布版本
发布的二进制文件附带了使用 [cosign](https://github.com/sigstore/cosign) 签名的 SHA-256 校验和文件。每个版本都会使用 [syft](https://github.com/anchore/syft) 生成 SBOM (Software Bill of Materials)。构建来源证明是通过 GitHub 的 `actions/attest-build-provenance` action 生成的。容器镜像还包含一个 [VSA](https://slsa.dev/spec/v1.0/verification_summary) 证明,用于记录发布管道的验证结果。
要验证发布版本:
1. 使用 cosign 验证校验和文件的签名:
cosign verify-blob --bundle checksums.txt.sigstore.json checksums.txt
2. 根据校验和文件验证二进制文件:
sha256sum --check checksums.txt
3. 验证容器镜像签名:
cosign verify ghcr.io/saschagrunert/nri-supply-chain:latest \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
--certificate-identity-regexp 'https://github.com/saschagrunert/nri-supply-chain/'
4. 验证构建来源证明:
gh attestation verify nri-supply-chain__linux_amd64 \
--repo saschagrunert/nri-supply-chain
5. 验证容器镜像上的 VSA (Verification Summary Attestation):
cosign verify-attestation ghcr.io/saschagrunert/nri-supply-chain:latest \
--type https://slsa.dev/verification_summary/v1 \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
--certificate-identity-regexp 'https://github.com/saschagrunert/nri-supply-chain/'
6. 检查 SBOM(使用 syft 生成,完整性由步骤 1 中签名的校验和文件覆盖):
cat nri-supply-chain__linux_amd64.sbom.json | jq .
验证流程图
``` flowchart TD Runtime["Container Runtime\n(CRI-O / containerd)"] NRI["NRI Hook\n(CreateContainer)"] Plugin["nri-supply-chain"] Extract["Extract image ref + digest"] Policy["Policy lookup\n(namespace or default)"] Exclude{"Excluded?"} Cache{"Cache hit?"} Fetch["Fetch attestations\n(OCI Referrers API +\ncosign tag fallback)"] VSA{"Trusted VSA?"} Parallel["SLSA + VEX\n(parallel)"] Enforce{"Enforce / Warn"} Allow["Allow container"] Reject["Reject container"] Registry["OCI Registry"] Runtime --> NRI --> Plugin --> Extract --> Policy --> Exclude Exclude -- yes --> Allow Exclude -- no --> Cache Cache -- hit --> Enforce Cache -- miss --> Fetch Fetch <--> Registry Fetch --> VSA VSA -- "PASSED" --> Enforce VSA -- "FAILED" --> Enforce VSA -- "untrusted / stale / missing" --> Parallel Parallel --> Enforce Enforce -- pass --> Allow Enforce -- "fail (enforce mode)" --> Reject Enforce -- "fail (warn mode)" --> Allow ```标签:attestation校验, EVTX分析, Go, NRI插件, Ruby工具, Web截图, 子域名突变, 容器安全, 容器运行时, 日志审计, 自定义请求头