run指令本身不被直接检查,真正被审查的是其执行后残留的缓存、root权限操作、硬编码密钥及非最小化安装等安全风险,需通过dockle、trivy等工具结合静态检查与运行时验证进行合规管控。

RUN 指令本身不会直接“被查”,真正被检查的是它执行后留下的结果:比如是否残留缓存包、是否以 root 权限安装了不必要工具、是否硬编码敏感信息,或是否违反最小安装原则。合规检查关注的不是语法对错,而是行为后果是否符合安全基线(如 CIS Docker Benchmark)和企业策略。
重点查 RUN 产生的实际影响
RUN 指令在构建过程中会创建新镜像层,每条 RUN 命令的执行效果都会固化进该层。检查核心是验证这些操作是否引入风险:
-
残留构建依赖:例如
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*中若漏掉rm -rf /var/lib/apt/lists/*,就会把数 MB 缓存打包进镜像,增大攻击面且违反“最小镜像”原则 -
隐式 root 权限操作:RUN 默认以 root 执行,若在里面下载并运行未知脚本(如
curl https://xxx.sh | sh),等于赋予远程代码 root 权限 -
密钥或凭证泄露:RUN 过程中若用
git clone https://user:token@github.com/...或echo "secret=xxx" > .env,密钥会留在该层中,即使后续RUN rm .env也无法彻底删除(历史层仍可提取) - 基础镜像污染:比如在 Alpine 镜像里用 RUN 安装 glibc 兼容层,破坏了轻量初衷,也增加 CVE 暴露面
用 Dockle 和 Trivy 实际识别 RUN 问题
Dockle 会直接报告由 RUN 引发的典型违规,例如:
-
DLCO0001:未清理包管理器缓存(apt/yum/apk) -
DLCO0002:使用ADD下载远程文件(应改用RUN curl | tar+ 显式清理) -
DLCO0004:镜像中存在私钥文件(常因 RUN 中生成或复制导致) -
DLCO0006:HEALTHCHECK 缺失 —— 虽非 RUN 直接导致,但很多团队在 RUN 安装完服务后忘记补健康检查
Trivy 则从另一角度切入:RUN 安装的软件包(如 openssl、nginx、python-pip)一旦含已知 CVE,就会在漏洞扫描报告中标出具体版本和修复建议,帮你定位是哪条 RUN 引入了风险组件。
静态检查与编写规范提前拦截
靠构建后扫描是补救,更高效的是在写 Dockerfile 阶段就规避问题:
- 合并多个 RUN 为一条,减少层数同时便于清理:
RUN apt-get update \&& apt-get install -y nginx \&& rm -rf /var/lib/apt/lists/* - 避免在 RUN 中处理敏感数据;密钥应通过构建参数(
--build-arg)或 secrets(Docker 18.09+)注入,而非写死命令行 - 用 hadolint 静态检查:它能发现
RUN pip install --upgrade pip这类无版本锁定的危险操作,并提示应写成RUN pip install pip==23.3.1 - 禁止在 RUN 中执行
curl | sh类模式,强制要求先COPY脚本再RUN ./script.sh,确保可审计、可签名
手动验证 RUN 层内容是否干净
如果需要快速确认某条 RUN 是否留下不该有的东西,可用以下方式检查对应层:
- 运行
docker history <image></image>找到目标 RUN 对应的层 ID - 启动临时容器挂载该层:
docker run --rm -it --entrypoint sh <image> -c "ls -la /usr/bin/"</image>(观察是否多出意外二进制) - 或导出层并查看文件列表:
docker save <image> | tar -t | grep -E "(\.pem|\.key|secrets)"</image>











