Appearance
镜像安全
镜像安全覆盖基础镜像来源、漏洞扫描、敏感信息、构建过程、签名、SBOM 和仓库权限。容器运行时的隔离不能弥补镜像本身的问题:镜像里带了高危漏洞、私钥、后门脚本,运行起来后风险已经进入环境。
镜像是 CI/CD 和 Kubernetes 的交付制品。一次发布最终落到集群里的往往不是代码仓库某个 commit,而是某个镜像 tag 或 digest。镜像安全做得清楚,后面排查“这个版本到底是什么构建出来的”会轻很多。
一、基础镜像来源
基础镜像通常分三类:
| 类型 | 说明 |
|---|---|
| 官方镜像 | Docker Hub 官方维护或语言社区维护 |
| 发行版镜像 | Ubuntu、Debian、Alpine、Rocky 等基础系统 |
| 公司基础镜像 | 内部统一加固、统一 CA、统一时区和基础工具 |
正式服务更适合用固定版本:
dockerfile
FROM python:3.12.4-slim-bookwormlatest 会随时间变化,构建结果不可追溯。alpine 镜像很小,但 musl libc 和 glibc 行为不同,某些 Python、Node.js、Java 原生依赖可能遇到兼容问题。镜像瘦身要和排错便利、兼容性一起权衡。
二、漏洞扫描
常见扫描工具:
| 工具 | 说明 |
|---|---|
| Trivy | 常用镜像漏洞、配置、Secret、SBOM 扫描工具 |
| Grype | Anchore 生态漏洞扫描 |
| Harbor Scanner | Harbor 内置扫描入口,常接 Trivy |
| 云厂商扫描 | 和云镜像仓库、准入策略集成 |
Trivy 示例:
bash
# 扫描镜像里的系统包和语言依赖漏洞
trivy image registry.example.com/ops/web:1.0.0
# 只显示 HIGH 和 CRITICAL 级别
trivy image --severity HIGH,CRITICAL registry.example.com/ops/web:1.0.0漏洞扫描结果要结合实际暴露面判断。基础镜像里某个库有 CVE,但应用没有调用对应功能,风险和修复优先级不同;反过来,公网入口服务里的高危远程执行漏洞,就不能只因为“容器隔离”而放过。
三、敏感信息
镜像层是可追溯的。Dockerfile 里 COPY 进去又删除的密钥,仍可能留在历史层里。
风险写法:
dockerfile
COPY id_rsa /root/.ssh/id_rsa
RUN git clone git@example.com:ops/private-repo.git && rm -f /root/.ssh/id_rsa更合适的方向是使用 BuildKit secret 或 SSH mount:
dockerfile
# syntax=docker/dockerfile:1.7
RUN --mount=type=ssh git clone git@example.com:ops/private-repo.git /src构建时传入:
bash
# 使用本机 SSH agent,不把私钥写入镜像层
DOCKER_BUILDKIT=1 docker build --ssh default -t app:1.0 ..env、私钥、云 AK/SK、数据库密码、NPM token 都不应该进入镜像。.dockerignore 是第一道门槛。
四、SBOM
SBOM(Software Bill of Materials)是软件物料清单,记录镜像里包含哪些系统包、语言依赖和版本。发生供应链漏洞时,SBOM 能快速回答“哪些镜像包含这个组件”。
生成 SBOM:
bash
trivy image --format cyclonedx \
--output web-sbom.json \
registry.example.com/ops/web:1.0.0SBOM 可以作为 CI 产物保存,也可以推送到支持 OCI artifact 的仓库。Harbor、Trivy、Syft/Grype、Cosign 这些工具都能参与这条链路。
五、签名和 digest
tag 是可变引用,digest 是内容地址。镜像 digest 形如:
text
registry.example.com/ops/web@sha256:1b2c3d...部署系统记录 digest,可以确认运行的镜像内容没有被同名 tag 替换。签名工具常见 Cosign:
bash
# 给镜像签名,真实环境里通常接 KMS 或 OIDC 身份
cosign sign registry.example.com/ops/web:1.0.0
# 验证签名
cosign verify registry.example.com/ops/web:1.0.0签名的价值在准入阶段更明显。Kubernetes 准入策略可以要求镜像来自内部仓库、通过扫描、带签名后才能运行。
六、Harbor 权限和保留
Harbor 里至少区分几个项目:
| 项目 | 说明 |
|---|---|
base | 公司基础镜像 |
ops | 运维平台和工具镜像 |
app | 业务应用镜像 |
ci | 临时构建和测试镜像 |
CI/CD 推镜像使用 Robot Account,不使用个人管理员账号。正式镜像 tag 设置不可变,避免同一个 1.0.0 被重复覆盖。临时构建 tag 设置保留策略,避免仓库磁盘被短期构建撑满。
七、上线前检查
| 检查项 | 说明 |
|---|---|
| 基础镜像 | 来源可信、版本固定、维护状态正常 |
| 构建上下文 | .dockerignore 排除 .git、缓存、密钥和本地配置 |
| 漏洞扫描 | 高危和严重漏洞有处理结论 |
| 敏感信息 | 镜像层里不含私钥、token、密码 |
| 用户权限 | 尽量非 root 运行,必要 capabilities 明确 |
| 标签和 digest | 版本可追溯,正式 tag 不覆盖 |
| 签名 / SBOM | 关键服务保留供应链证据 |
镜像安全不是发布最后点一下扫描按钮。基础镜像选型、Dockerfile 写法、CI 构建凭据、Harbor 权限、Kubernetes 准入策略是一条链,断在哪一段都可能把风险带进运行环境。