每当你分享 Compose 文件,实际上都有两份产物:你写的那一份,以及工具替换变量后渲染出的那一份。后者往往比前者更敏感,而人们常常看都不看就把它贴进问题报告。只检查源文件,等于检查了错误的文档。

在决定删除什么之前,先比较两份副本各自可能包含什么。

渲染后的模型是另一份文档

Compose 会解析环境变量、合并覆盖文件,生成一份读者再也分不清哪些是手写值的有效配置。源码里像变量名这样的引用,在输出里就变成了账户令牌本身。让文件可用于诊断的结构在转换后依然存在;本来就不该出现的东西也一并保留了下来。

附上之前请自己先渲染一遍,并把那份输出当作要审阅的产物。如果无法渲染,你就无从知道即将发布什么。

秘密所处的位置远不止密钥字段

从最明显的开始:私钥、预共享密钥、令牌、密码,以及内嵌凭据的连接 URL。接着看文件指向的一切,因为引用并不等于删除。挂载进服务的 env 文件、从宿主机绑定挂载的配置文件、携带令牌的标签,以及含密码的命令参数,即便 YAML 看起来很干净,也会随部署一起流失。贴在名字令人安心的变量里的密钥,仍然是密钥。

宿主机路径和服务名会泄露另一类信息。主目录名、内部主机名或网段,不含任何凭据也能指认某个人或某个组织,这类上下文同样值得删除。

声明秘密并不等于秘密本身

Compose 的 secret 对象把声明和材料分开:服务拿到的是路径或目标,内容存放在别处。保留声明、替换材料通常才是正确的取舍,因为审阅者需要看到秘密确实存在、以及它是如何挂载的。真正不该留下来的,是内容本身。

标签和注释也应同样处理。说明哪个 vault 路径存放生产密钥的注释,即使不含密钥,也在告诉攻击者该往哪里看。

保留形态,文件才能继续用于诊断

如果抹掉网络模式、镜像版本或能力设置,得到的文件谁也无法调试。只替换敏感值,保留彼此关系:哪个服务挂载了什么、加入哪个网络、需要哪个设备。这正是读者用来解释路由缺失或设备不可用的那部分。同行也能拿它和各自可用的部署做对比。

docker compose -f compose.yaml config > rendered.yaml
grep -nE 'PRIVATE_KEY|PASSWORD|TOKEN|PSK|PrivateKey|passphrase' rendered.yaml
wc -l rendered.yaml

不要把抹过的副本当作可用的原件去部署。它只是一份描述,而为了显得安全而被编辑过的描述,会以看似配置错误的方式失败。

如果材料已经暴露,就替换它

移除附件并不能移除别人已经做过的副本,镜像与缓存也各留一份。对已泄露的一切走签发方的吊销与替换流程,然后再更新部署。顺序很重要,因为先替换后吊销会留下一段同时存在两套有效凭据的窗口。

在求助帖里,先说确切的报错、镜像版本、网络模式,以及那一个真正重要的非秘密设置。相比密钥,这个组合更能解释设备缺失或路由故障。

相关文章