3. 镜像生命周期:构建、存储、分发、部署、运行时各阶段的信任风险
容器镜像的信任风险并非孤立存在于某个环节,而是贯穿其完整的生命周期。从代码提交到生产环境运行,每一个阶段都可能引入新的攻击面或信任断层。理解各阶段的风险特征,是建立有效观测标签体系的前提。
核心观点:镜像供应链的信任边界是动态的。构建阶段决定“初始信任”,存储与分发阶段维护“传输信任”,部署阶段验证“准入信任”,运行时阶段监控“持续信任”。任何一个环节的失效,都会导致整条链路的信任崩塌。
3.1 构建阶段:信任的起点与最大风险源
构建阶段是镜像的“出生”时刻,也是攻击者最常植入恶意载荷的环节。此阶段的风险主要来自基础镜像、依赖项和构建过程本身。
| 风险类别 | 具体风险 | 攻击示例 |
|---|---|---|
| 基础镜像污染 | 使用不可信或过时的基础镜像,包含已知漏洞(CVE)或后门 | 从非官方仓库拉取包含挖矿软件的镜像 |
| 依赖项投毒 | 第三方库或包被篡改,引入恶意代码(如 typosquatting 攻击) | npm 包 event-stream 事件注入恶意代码窃取比特币 |
| 构建缓存污染 | CI/CD 缓存层被篡改,导致后续构建产出恶意镜像 | 攻击者利用缓存 poisoning 在 Docker build 缓存中植入后门 |
| 构建脚本篡改 | Dockerfile 或构建脚本被修改,执行非预期命令 | 在 RUN 指令中嵌入 curl 下载恶意 payload |
| 密钥泄露 | 构建过程中硬编码或泄露敏感信息(、) | Docker history 中暴露数据库密码 |
观测标签建议:在构建阶段,应记录
image.build.base_image_digest、image.build.dependency_scan_status、image.build.ci_pipeline_id 等标签,用于追溯镜像的“出生证明”。
3.2 存储与分发阶段:传输中的信任维护
镜像构建完成后,被推送到镜像仓库,随后被拉取到各个节点。此阶段的核心风险在于镜像的完整性和来源真实性是否得到保障。
- 镜像篡改:镜像在传输过程中或存储于仓库时被中间人替换或修改。
- 仓库配置错误:私有仓库权限配置不当,允许匿名推送或拉取,导致恶意镜像混入。
- 标签可变性:使用可变标签(如
latest)而非不可变摘要(digest),导致拉取的镜像版本与预期不符。 - 镜像签名缺失:未使用 Notary、Cosign 等工具对镜像进行签名,无法验证发布者身份。
常见误区:很多团队认为“内网仓库就是安全的”。实际上,内网仓库同样面临凭证泄露、内部人员恶意操作等风险。必须将仓库视为不可信环境,实施签名验证。
下表对比了不同分发机制下的信任保障能力:
| 分发机制 | 完整性保障 | 来源验证 | 防回滚 |
|---|---|---|---|
| HTTP 拉取(无 TLS) | 无 | 无 | 无 |
| HTTPS + Digest 引用 | 强(TLS + 哈希校验) | 弱(仅验证仓库域名) | 强(digest 不可变) |
| 镜像签名(Cosign) | 强 | 强(公钥/密钥验证) | 强(签名绑定 digest) |
| OCI Artifact + 策略引擎 | 强 | 强(策略即代码) | 强 |
3.3 部署阶段:准入控制的最后防线
当镜像被拉取到 Kubernetes 节点并准备创建 Pod 时,部署阶段是执行信任策略的最后机会。此阶段的风险包括:
- 策略绕过:Kubernetes 准入控制器(Admission Controller)配置不当,允许未签名或包含高危漏洞的镜像运行。
- 镜像拉取策略错误:使用
imagePullPolicy: Always可能导致每次部署都拉取最新标签,引入未预期的版本。 - 节点信任失效:节点本身被攻陷,其 kubelet 可能绕过 API Server 直接拉取恶意镜像。
- 运行时类(RuntimeClass)逃逸:配置了不安全运行时(如
privileged)的 Pod 可能突破容器隔离。
关键观测指标:部署阶段应重点监控
admission_webhook_denied_total、image_pull_error_count、pod_security_policy_violation 等指标,并记录 image.deploy.admission_result、image.deploy.pull_policy 标签。
3.4 运行时阶段:持续信任的挑战
镜像一旦运行,信任风险从“静态验证”转向“动态监控”。运行时阶段的风险最为复杂,因为攻击面从镜像本身扩展到了运行时环境、网络和存储。
| 风险维度 | 具体表现 | 观测标签示例 |
|---|---|---|
| 进程逃逸 | 容器内进程突破 namespace 限制,影响宿主机或其他容器 | container.runtime.seccomp_profile |
| 文件系统篡改 | 容器启动后,镜像层文件被修改(如植入后门脚本) | container.fs.diff_count |
| 网络异常 | 容器发起非预期的出站连接(如连接矿池或 C2 服务器) | container.network.egress_anomaly |
| 特权提升 | 容器通过内核漏洞或配置错误获取宿主机 root 权限 | container.capabilities.added |
| 镜像层泄露 | 通过容器逃逸读取其他容器的镜像层数据 | container.mount.shared |
运行时阶段的信任模型从“一次验证,永远信任”转变为“持续验证,动态信任”。这意味着即使镜像在构建和部署阶段通过了所有安全检查,运行时仍然需要持续监控其行为是否符合预期。
3.5 各阶段信任风险总结与标签映射
下表汇总了镜像生命周期各阶段的核心信任风险,并给出了对应的观测标签建议,为后续章节的标签体系设计奠定基础。
| 生命周期阶段 | 核心信任风险 | 关键观测标签(建议) |
|---|---|---|
| 构建 | 基础镜像污染、依赖投毒、构建缓存篡改 | image.build.base_digestimage.build.dependency_scanimage.build.pipeline_id |
| 存储 | 镜像篡改、仓库配置错误、签名缺失 | image.registry.digestimage.registry.signatureimage.registry.access_control |
| 分发 | 中间人攻击、标签可变性、拉取策略错误 | image.distribution.pull_policyimage.distribution.transport_tlsimage.distribution.tag_mutable |
| 部署 | 准入策略绕过、特权容器、节点信任失效 | image.deploy.admission_resultimage.deploy.security_contextimage.deploy.node_trust |
| 运行时 | 进程逃逸、文件篡改、网络异常、特权提升 | container.runtime.behaviorcontainer.fs.integritycontainer.network.anomaly |
实践建议:在构建阶段就为镜像打上不可变的
digest 标签,并在后续所有阶段使用该 digest 进行引用和验证。这是打破“标签可变性”风险的最有效手段。