容器镜像安全基础:镜像分层原理、镜像漏洞扫描与镜像签名验证
容器镜像的安全性是整个云原生安全体系的基石。本章从镜像的底层结构出发,深入剖析分层原理,并系统讲解镜像漏洞扫描工具(Trivy / Clair)的使用方法,以及基于 Cosign 的镜像签名与验证机制。掌握这些基础,才能在生产环境中构建可信、可审计的容器供应链。
2.1 镜像分层原理
Docker/OCI 镜像由一系列只读层(Layer)堆叠而成,每一层代表 Dockerfile 中的一条指令。层与层之间通过联合文件系统(UnionFS)合并,形成容器的可写视图。分层机制的核心优势在于:层复用——多个镜像可以共享相同的底层(如基础操作系统层),从而节省存储空间并加速分发。
2.2 镜像漏洞扫描(Trivy / Clair)
镜像漏洞扫描是容器安全左移的关键环节。通过扫描工具将镜像层中的软件包版本与公共漏洞数据库(如 NVD、RedHat OVAL、Debian Security Tracker)进行比对,识别已知 CVE。主流工具包括 Trivy(轻量、快速、支持多语言)和 Clair(CoreOS 开源,深度集成于 Quay 和 Harbor)。
2.2.1 扫描工具对比
| 特性 | Trivy | Clair |
|---|---|---|
| 部署方式 | 单二进制,无依赖 | 需运行 Clair 服务 + PostgreSQL |
| 扫描速度 | 极快(秒级) | 中等(分钟级,依赖数据库更新) |
| 漏洞数据库 | 内置更新,离线可用 | 需定期同步,支持自定义 |
| 支持格式 | Docker / OCI / 本地文件系统 | Docker / OCI / AppC |
| CI/CD 集成 | 原生支持,输出 JSON/SARIF | 需通过 API 或 Harbor 集成 |
| 许可证扫描 | 支持 | 不支持 |
2.2.2 Trivy 扫描实战
以下命令演示如何使用 Trivy 扫描本地镜像,并输出 JSON 格式的漏洞报告:
# 安装 Trivy(macOS / Linux)
brew install trivy
# 或使用官方脚本
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh
# 扫描镜像(示例:nginx:1.25)
trivy image --severity CRITICAL,HIGH --format json nginx:1.25 -o nginx-vuln.json
# 仅输出摘要
trivy image --severity CRITICAL nginx:1.25
2.2.3 Clair 集成示例(Harbor)
Clair 通常作为 Harbor 镜像仓库的内置扫描器运行。在 Harbor 中启用 Clair 后,每次推送镜像都会自动触发扫描:
# Harbor 配置文件(harbor.yml)中启用 Clair
clair:
enabled: true
updaters_interval: 12 # 漏洞数据库更新间隔(小时)
# 通过 Harbor API 获取扫描报告
curl -u "admin:password" \
https://harbor.example.com/api/v2.0/projects/library/repositories/nginx/artifacts/latest/scan
2.3 镜像签名与验证(Cosign)
镜像签名用于确保镜像的完整性和来源可信。Cosign 是 Sigstore 项目下的无密钥签名工具,支持使用短生命周期密钥或硬件密钥对镜像进行签名,并将签名存储在 OCI 仓库中。验证时,策略引擎(如 OPA Gatekeeper)可强制要求所有部署的镜像必须附带有效签名。
2.3.1 Cosign 签名流程
- 生成密钥对:使用
cosign generate-key-pair生成私钥(本地保管)和公钥(公开分发)。 - 签名镜像:
cosign sign --key cosign.key <镜像引用>,签名被自动推送至镜像仓库的 OCI 制品中。 - 验证签名:
cosign verify --key cosign.pub <镜像引用>,输出签名元数据。
# 生成密钥对
cosign generate-key-pair
# 对镜像签名(示例:registry.example.com/app:v1)
cosign sign --key cosign.key registry.example.com/app:v1
# 验证签名
cosign verify --key cosign.pub registry.example.com/app:v1
# 输出示例(JSON 格式)
{
"critical": {
"identity": {
"docker-reference": "registry.example.com/app"
},
"image": {
"docker-manifest-digest": "sha256:abc123..."
},
"type": "cosign container image signature"
}
}
2.3.2 签名验证策略(OPA Gatekeeper 集成预览)
在后续章节中,我们将详细实现 OPA Gatekeeper 策略来强制验证签名。以下是一个简化的 Rego 策略片段,用于检查镜像是否包含 Cosign 签名:
package containerimagesignature
violation[{"msg": msg}] {
input.review.object.spec.containers[_].image == img
not cosign_verified(img)
msg := sprintf("镜像 %v 缺少有效 Cosign 签名", [img])
}
cosign_verified(img) {
# 调用外部数据或注解检查签名存在性
data.images[img].signed == true
}
cosign verify 的 --check-claims 选项,验证签名中的身份声明(如 OIDC 发行人)。
2.4 本章小结
- 镜像分层:理解层复用机制,优化 Dockerfile 指令顺序以提升构建效率。
- 漏洞扫描:Trivy 适合快速 CI 集成,Clair 适合企业级仓库深度扫描;务必设置漏洞阻断阈值。
- 签名验证:Cosign 提供无密钥签名能力,是构建软件供应链安全的基础组件。