介绍
从容器镜像中移除的文件,仍可能存在于更早的镜像层中。Git 忽略规则也不控制 Docker 在构建时接收哪些内容。
你将调查一个预置镜像,限制其构建输入,并验证新镜像的每一层。工作程序和 Docker 工作流程沿用上一个实验。所有凭据均为虚构的本地测试数据;缓存基础镜像和检查辅助程序均已准备好。
检查预置构建输入
在本步骤中,你将区分版本控制忽略规则与 Docker 构建输入。
cd /home/labex/project/ticket-image
ls -a
ls -a 包括以点开头的文件。本项目包含工作程序、公开配置、输入/输出目录、private.env 和 debug.txt。最后两个是本地私密输入,不是交付文件。
cat .gitignore
Git 忽略这两个私密文件名。这影响 Git 的跟踪流程,而非 Docker 的构建上下文。
cat .dockerignore
该文件目前为空。**.dockerignore** 控制 Docker 接收构建上下文时排除哪些路径。被 Git 忽略的文件仍可能被发送给 Docker 构建。
cat Dockerfile
COPY . /app/ 复制整个可用上下文。后面的 RUN rm ... 从最终文件系统中移除私密文件,但不会撤销更早的镜像层。
找出隐藏的镜像层副本
在本步骤中,你将比较最终文件系统与保存的镜像层。
预置旧标签 ticket-image:legacy 使用这个 Dockerfile 构建。运行一次性检查容器。--rm 在 ls 完成后自动移除临时容器;这里的命令覆盖镜像默认的工作程序启动命令:
sudo docker run --rm ticket-image:legacy ls -a /app
最终的 /app 应不再列出 private.env 或 debug.txt。其中仍包含工作程序和公开配置。
docker history 显示镜像构建指令。--no-trunc 保留完整指令文本:
sudo docker history --no-trunc ticket-image:legacy
找到先大范围复制、再删除的指令。历史说明了执行顺序,却不显示每个文件的内容。预置 course-image-scan 辅助程序保存这个实际镜像,并读取每一个保存的镜像层和镜像配置:
sudo course-image-scan ticket-image:legacy
预期发现更早镜像层中的私密文件名,以及一个已脱敏的目标练习凭据。退出状态 1 表示有发现;2 或 CHECK ERROR 表示检查失败。辅助程序的固定范围是这些列出的私密文件名和这个虚构凭据,并非完整的生产环境机密扫描器。
后续镜像层中的删除操作不会抹去更早的字节。因此,仅通过最终文件系统的 ls 检查并不够。
排除私密构建输入
在本步骤中,你将保留本地私密文件,同时将它们排除在 Docker 上下文之外。
nano .dockerignore
使用以下完整文件:
private.env
debug.txt
input/
output/
每行是一个要排除的路径或目录。这些模式从构建输入中移除私密配置、调试材料和运行时数据;工作程序和 config.public 仍然可用。
使用 Ctrl+O、Enter 保存,使用 Ctrl+X 退出。不要删除本地私密文件。忽略路径应限制其被包含的范围,而非销毁本地配置。
限制 Dockerfile 的复制范围
在本步骤中,你将明确列出镜像必需的输入。
旧删除指令现在已不需要,而且会因排除后的文件不可用而失败。打开 Dockerfile:
nano Dockerfile
使用以下完整文件:
FROM desklite-base:1.37.0
WORKDIR /app
COPY worker.sh config.public /app/
USER nobody
CMD ["sh", "/app/worker.sh"]
COPY worker.sh config.public /app/ 仅列出两个必需业务文件。保留上一实验中的 USER nobody 和原始启动命令。使用 Ctrl+O、Enter、Ctrl+X 保存并退出。
两项控制相互配合:.dockerignore 限制可用构建输入,明确列出的 COPY 限制本镜像包含的内容。二者都不依赖机密信息进入镜像层后再将其删除。
构建并检查新产物
在本步骤中,你将检查新构建的交付镜像,而不是改变旧证据的含义。
sudo docker build -t ticket-image:delivery .
预期本地构建成功。新标签与 ticket-image:legacy 不同。
sudo course-image-scan ticket-image:delivery
预期每个保存的镜像层及镜像配置都得到 PASS。这一针对特定目标的结果,并不意味着已检测所有潜在机密信息或漏洞。
现在独立检查上下文:
sudo course-context-check .
预置辅助程序使用固定的 COPY . 探针构建临时镜像,应用相同的实际镜像层检查,然后移除临时镜像。预期为 PASS。这证明私密文件已从上下文排除,而不只是被较窄范围的交付 COPY 省略。
旧镜像中仍可能存在原始发现。重新构建干净的交付产物,不会重写先前分发的镜像,也不会撤销已泄漏凭据。真实泄漏需要前面学过的凭据替换流程,并适当清理旧副本。这里的目标令牌是有意虚构的,验收针对新交付镜像。
使用新镜像运行原始报告任务
在本步骤中,你将证明移除私密构建输入后,工作程序必需文件和行为仍得到保留。
输出目录已由 UID 65534 拥有,具有受限的可写访问权限。复用上一实验的非 root 工作程序和绑定挂载工作流程:
sudo docker run -d --name ticket-image-worker --network none --mount type=bind,src=/home/labex/project/ticket-image/input,dst=/data/input,readonly --mount type=bind,src=/home/labex/project/ticket-image/output,dst=/data/output ticket-image:delivery
sudo docker exec ticket-image-worker id -u
预期为 65534。
sudo docker logs ticket-image-worker
预期显示 mode=report 和 tickets=2。第一行来自必需的公开配置;第二行来自读取原始输入并写入实际报告。
sudo docker exec ticket-image-worker cat /data/output/report.txt
预期为 tickets=2。工作程序仍具有只读输入和可写输出,无需在镜像内包含私密配置。
确认本地源文件和交付证据
在本步骤中,你将以本地私密输入和安全交付产物均保持完整的状态结束练习。
列出私密源文件,不打印其内容:
ls -l private.env debug.txt
二者必须仍在本地存在。删除它们会绕过本练习所要求的构建边界。
sudo course-image-scan ticket-image:delivery
sudo docker ps
交付扫描应通过,ticket-image-worker 应处于运行状态。课程检查还会探测真实构建上下文、检查运行镜像 ID,并验证原始报告。无需单独提交书面调查文件。
总结
你限制了实际 Docker 构建输入,只复制必需业务文件,检查了全部保存的镜像层及镜像配置,并保留原始非 root 工作程序。仅有干净的最终文件系统不足以确立这一边界。



