LabHub
学习 学习路径 课程

容器安全

环境变量与文件挂载,差别在哪

在 LabHub 中继续学习

本实验在真正的 VM 中运行

这个环境不是 Pod,而是由 KubeVirt 启动的虚拟机。Linux 内核独立运行,systemd 真正管理服务,docker 是真正的 Docker 引擎。通过 docker run 启动的容器会成为实际进程,docker execdocker logs 均可正常工作。

过去本实验在放弃全部内核权限的 Pod 中运行,无法启动容器,只能绕道解开镜像归档。现在不再需要绕路。

请了解两点:

目标

分别以环境变量和文件挂载传递同一密钥,亲自测量它是否暴露于 docker inspect,以及能否在不重启的情况下轮换,并整理成比较表。最后编写简单的密钥检测脚本。

为什么重要

环境变量不是存储位置,而是传递方式。进程存活期间,/proc/<pid>/environ 始终可读;任何能访问容器守护进程的人都能通过 docker inspect 直接看到容器环境变量。因此,“加载后删除 .env 就安全了”毫无依据。轮换更加重要:环境变量在进程启动时固定,修改必须重启;文件挂载若原地覆盖同一 inode,则无需重启即可看到新值。凭据泄露后,从撤销、替换到恢复服务所需的时间,正体现团队的密钥管理水平。

步骤

  1. 创建 /root/sec3,在 /root/sec3/app.env 中写一行 API_KEY=labhub-env-key-v1,再将权限改为 600
  2. 使用 alpine:3.20 创建 sec3-env 容器,通过 --env-file /root/sec3/app.env 在后台运行。容器中的 API_KEY 必须与文件值相同。
  3. 将通过 docker inspect sec3-env 读取的 API_KEY 值原样保存到 /root/sec3/leak-proof.txt
  4. /root/sec3/secret.txt 中写入 labhub-file-key-v1,把该文件以只读绑定挂载到 sec3-file 容器的 /run/secrets/api_key,并在后台运行。挂载源必须正好是 /root/sec3/secret.txt
  5. sec3-file 容器的环境变量中既不能有 API_KEY,也不能有密钥值本身。
  6. 不重启容器,将 /root/sec3/secret.txt 原地覆盖为 labhub-rotated-v2sec3-file 应看到新值,而 sec3-env 的环境变量仍应保留旧值。在 /root/sec3/rotate.md 中写明哪种方式需要重启(必须包含 재시작restart)。
  7. 编写可执行的 /root/sec3/find-secrets.sh。递归搜索第一个参数指定的目录;若发现以 AKIA 开头的访问密钥或 PRIVATE KEY 块,应以非 0 退出码结束并输出发现它的文件路径;若没有发现,退出码应为 0。
  8. /root/sec3/secrets.md 中比较环境变量和文件挂载,并严格包含以下四行。
    • env_visible_in_inspect=yes
    • mount_visible_in_inspect=no
    • env_needs_restart=yes
    • mount_needs_restart=no

参考

密钥文件与 600 权限

创建 /root/sec3,在 /root/sec3/app.env 中写一行 API_KEY=labhub-env-key-v1,再将权限改为 600

评分重点不仅是值,还有文件权限。只有所有者可以读写,组和其他用户不能有任何权限。请先创建文件,再修改权限。

通过 env-file 注入

使用 alpine:3.20 创建 sec3-env 容器,通过 --env-file /root/sec3/app.env 在后台运行。容器中的 API_KEY 必须与文件值相同。

把值直接写在命令行会留在 Shell 历史和进程列表中。请用从文件读取并注入的选项。评分会比较容器环境变量与文件值,因此容器必须持续运行。

环境变量会直接暴露在 inspect 中

将通过 docker inspect sec3-env 读取的 API_KEY 值原样保存到 /root/sec3/leak-proof.txt

只要能访问守护进程,即使不是容器创建者也能读取该值。不要猜测,请实际通过 docker inspect 提取并原样保存。

以文件方式挂载

/root/sec3/secret.txt 中写入 labhub-file-key-v1,把该文件以只读绑定挂载到 sec3-file 容器的 /run/secrets/api_key,并在后台运行。挂载源必须正好是 /root/sec3/secret.txt

这是把一个主机文件直接挂到容器特定路径的方式。源路径和目标路径都会评分,必须准确;由于是密钥,还必须以只读方式挂载。

不要留在环境变量中

sec3-file 容器的环境变量中既不能有 API_KEY,也不能有密钥值本身。

改用文件挂载后,没有理由再通过环境变量传递同一值。两种方式并用会让密钥再次暴露在 inspect 中。请确认第 4 步容器没有混入环境变量。

无需重启地轮换

不重启容器,将 /root/sec3/secret.txt 原地覆盖为 labhub-rotated-v2sec3-file 应看到新值,而 sec3-env 的环境变量仍应保留旧值。在 /root/sec3/rotate.md 中写明哪种方式需要重启(必须包含 재시작restart)。

绑定挂载跟随 inode。原地覆盖(重定向)后容器会立即看到新值;删除再创建(某些编辑器或 sed -i)会更换 inode,使挂载继续指向旧文件。环境变量绝不能变化,它是本步骤的对照组。

密钥检测脚本

编写可执行的 /root/sec3/find-secrets.sh。递归搜索第一个参数指定的目录;若发现以 AKIA 开头的访问密钥或 PRIVATE KEY 块,应以非 0 退出码结束并输出发现它的文件路径;若没有发现,退出码应为 0。

递归搜索两种模式:以 AKIA 开头的访问密钥和 PRIVATE KEY 块头。干净时返回 0,发现时返回非 0,并输出所在文件路径。也请思考这种规则只擅长识别形态明确的值这一局限。

传递方式比较表

/root/sec3/secrets.md 中比较环境变量和文件挂载,并严格包含以下四行。

四行的值必须与前面亲自确认的结果一致。回顾第 3 步看到了什么、第 5 步没有看到什么,以及第 6 步哪种方式需要重启。正文还必须同时提到环境变量方式和挂载方式。