2. 镜像供应链基础:容器镜像的组成、镜像层与基础镜像、镜像仓库与分发机制
2.1 容器镜像的组成结构
容器镜像本质上是一个只读的、分层的文件系统集合,外加一份描述其运行配置的元数据。理解镜像的内部组成是构建信任边界的第一步。
| 组成部分 | 说明 | 信任关注点 |
|---|---|---|
| 镜像层(Layer) | 每一层代表 Dockerfile 中一条指令(如 RUN、COPY)产生的文件系统变更。 | 层的内容是否被篡改?来源是否可信? |
| 镜像清单(Manifest) | JSON 文件,描述镜像的层列表、架构、操作系统及配置。 | 清单签名是否有效?是否匹配实际层摘要? |
| 镜像索引(Index) | 多架构镜像的入口,指向不同平台对应的 Manifest。 | 索引是否被替换指向恶意镜像? |
| 配置对象(Config) | JSON 对象,包含环境变量、入口点、默认命令、暴露端口等。 | 配置是否被注入后门参数? |
关键概念:镜像的不可变标识是
digest(SHA256 摘要),而非标签(tag)。标签可变,digest 不可变。供应链安全的第一原则:始终使用 digest 引用镜像。
2.2 镜像层与基础镜像
镜像层采用 UnionFS(联合文件系统) 技术堆叠。每一层只记录与上一层的差异(增量)。基础镜像位于最底层,是所有上层变更的起点。
2.2.1 基础镜像的选择策略
- 官方镜像(Official Images): 由 Docker 官方或上游社区维护,经过安全扫描,但需注意版本更新频率。
- 最小化镜像(Distroless / Alpine): 仅包含运行时依赖,无 shell 和包管理器,攻击面显著减小。
- 签名镜像(Notation / Cosign): 使用 OCI 标准签名验证镜像发布者身份,防止中间人替换。
- 固定摘要(Pin by Digest): 避免使用
latest或可变标签,强制锁定基础镜像版本。
⚠ 常见陷阱: 使用
FROM ubuntu:latest 会导致每次构建拉取不同版本的基础镜像,破坏可复现性,且可能意外引入漏洞。应始终使用 FROM ubuntu:22.04@sha256:abc123...。
2.3 镜像仓库与分发机制
镜像仓库(Registry)是镜像供应链的中枢。从开发者推送镜像到生产环境拉取,整个分发链路存在多个信任风险点。
2.3.1 仓库类型对比
| 类型 | 示例 | 信任控制 | 适用场景 |
|---|---|---|---|
| 公共仓库 | Docker Hub, GitHub Container Registry | 依赖平台安全 + 镜像签名验证 | 开源项目、基础镜像获取 |
| 私有仓库 | Harbor, AWS ECR, Azure ACR | 访问控制 + 漏洞扫描 + 策略引擎 | 企业内部分发、生产部署 |
| 代理缓存仓库 | Harbor Proxy, Docker Registry Mirror | 缓存上游镜像 + 内容过滤 + 速率限制 | 离线环境、加速拉取、安全审计 |
2.3.2 分发协议与信任链
OCI Distribution Spec 定义了镜像的推送和拉取流程。信任链的核心环节包括:
- 身份认证: 客户端与仓库之间的 TLS 双向认证或 Bearer 认证。
- 摘要验证: 拉取时客户端计算层摘要并与 Manifest 中的 digest 比对。
- 签名验证: 使用 Cosign / Notation 验证镜像签名是否由可信发布者签发。
- 策略执行: 在仓库端(如 Harbor)配置策略,阻止未签名或包含高危漏洞的镜像被部署。
2.4 镜像供应链信任边界总结
💡 核心原则: 信任不应隐式传递。每一层、每一次分发、每一个仓库交互都应显式验证。将“零信任”思想引入镜像供应链——验证一切,信任无物。
- 镜像层: 每一层都应记录来源(FROM 层 + 构建上下文),并通过摘要锁定。
- 基础镜像: 选择最小化、官方签名、固定摘要的基础镜像,定期更新。
- 仓库: 私有仓库启用访问控制、漏洞扫描、签名策略和审计日志。
- 分发: 客户端强制验证 digest 和签名,拒绝未经验证的镜像。