环境变量是一种传递方式,不是安全等级
把密码从代码移到 .env 是进步,但不代表它自动安全。文件可能进入 Git、备份、镜像构建上下文、进程环境或调试日志。先把信息分三类:公开配置、内部但不敏感的配置、泄露后必须立即轮换的秘密。只有第三类需要按密钥管理。 典型秘密包括数据库密码、会话签名密钥、第三方 API token、SMTP 密码和私钥。域名、日志级别、公开站点 URL 通常不是秘密,不必把所有配置都藏起来增加排错困难。
建一份不包含值的密钥清单
清单记录名称、用途、使用服务、负责人、来源、创建时间、轮换周期和撤销方式,不记录真实值。这样能回答某个 API token 泄露后会影响哪些进程,也能发现早已不用却仍有效的凭证。 为开发、测试和生产使用不同凭证。不要把个人账户生成的长期密钥当成服务器永久资产;能使用服务账号和最小权限就不要使用全权管理员密钥。
文件位置和权限要有明确规则
systemd 可用 /etc/myapp/myapp.env,通过 EnvironmentFile 读取;文件由 root 管理,应用组只读。Compose 的 env_file 同样应放在部署目录之外或严格限制权限,并加入 .gitignore 与构建忽略。
sudo install -d -m 750 -o root -g myapp /etc/myapp
sudo install -m 640 -o root -g myapp /private/path/myapp.env /etc/myapp/myapp.env
sudo -u myapp test -r /etc/myapp/myapp.env不要在共享聊天、命令历史和截图中直接粘贴值。编辑时使用权限受控的方式;完成后检查 shell history 和临时文件。备份如果包含密钥,备份本身也要加密并限制访问。
容器环境需要额外检查
不要在 Dockerfile 用 ARG 或 ENV 烘焙生产秘密,它们可能留在镜像层和构建记录。Compose 环境变量适合一般配置;对高敏感内容,考虑文件挂载或平台提供的 secrets 机制,让应用从受限文件读取。无论哪种方式,容器内拥有相应权限的进程仍可能读取,最小权限和进程隔离不能省。 执行 docker compose config 时可能展开变量,输出不要上传公开日志。健康检查和错误处理也不能把完整连接串回显。
轮换要设计成两把钥匙短暂共存
直接替换数据库密码或签名密钥,可能让旧进程立刻断开或所有用户退出。能双密钥验证的系统先加入新密钥、部署并验证,再撤销旧密钥;不能双持时安排窗口,先备份、更新服务端、逐个重启消费者,最后验证旧密钥已失效。 会话签名密钥轮换可能使现有登录失效,要提前接受这个影响。数据库用户可以创建新账号并切换连接,确认无旧连接后再删除旧账号。轮换完成要更新清单日期,而不是只改文件。
怀疑泄露时先撤销,不先追究是谁
处理顺序是:限制影响范围、撤销或轮换、检查异常使用、修复泄露路径、再复盘。仅从 Git 历史删除字符串不够,因为旧提交和克隆仍可能保存;真实密钥必须视为已经暴露。 保留时间线:何时发现、哪些服务使用、何时撤销、日志是否出现异常。审计时避免把秘密再次复制到报告。对公开仓库、CI 日志和镜像仓库都要检查。
完成标准
仓库和镜像不含生产秘密,服务以最小权限读取受控文件,开发与生产凭证分开,日志不回显值,每个秘密都有负责人和撤销方式,并完成过至少一次轮换演练。下一篇进入最能检验架构是否真实可恢复的环节:数据库备份与恢复演练。