生产环境禁用os.environ['KEY']直接读密钥,因其会明文暴露在进程环境块中,被ps aux或/proc/$PID/environ轻易获取;Docker下更危险,应改用Docker Secrets挂载文件+FileAwareEnv进程外读取,实现物理隔离与最小暴露面。

生产环境不能靠 .env 文件直接加载敏感密钥——它只是文本,没加密、没权限控制、易误提交。真正安全的注入方式,是让密钥“不进进程环境块”,也不落地为可读文件。
为什么 os.environ['KEY'] 在生产里必须禁用
直接从 os.environ 读取密钥,意味着密钥会出现在进程的环境块中。任意用户执行 ps aux | grep python 或 cat /proc/$PID/environ 都可能看到明文密钥。Docker 容器内更危险:同一宿主机上其他容器或 root 用户可轻易获取。
-
os.environ['SECRET_KEY']会把密钥暴露在进程元数据里,不符合最小暴露面原则 -
os.getenv('SECRET_KEY')更糟:返回None时可能被下游库静默转成空字符串,导致认证绕过或连接失败但无报错 - 哪怕你加了
.gitignore和chmod 600,只要密钥进了os.environ,就已脱离可控边界
Docker Secrets + FileAwareEnv 是目前最稳妥的组合
Docker Secrets 把密钥以临时文件形式挂载进容器(路径如 /run/secrets/secret_key),只对目标容器可读,且不存于镜像层或宿主机磁盘。关键是要避免把它再“读进” os.environ。
- 用
FileAwareEnv(来自python-decouple0.9+)直接从文件读取:config('SECRET_KEY_FILE', cast=FileAwareEnv) - 不要用
load_dotenv('/run/secrets/.env')—— Secrets 不是 .env 格式,强行解析会出错 - 挂载时指定 uid/gid,确保只有应用用户可读:
--secret source=prod_secret_key,target=/run/secrets/secret_key,uid=1001,gid=1001,mode=400 - 验证是否生效:
docker exec -it myapp cat /run/secrets/secret_key应能读出内容;docker exec -it myapp ps aux | grep python不应含密钥字符串
SECRET_KEY 和 ENCRYPTION_KEY 必须物理隔离
这两个密钥用途完全不同,复用等于单点击穿。Django 的 SECRET_KEY 用于 session 签名、CSRF token 生成;而 ENCRYPTION_KEY(如给 django-fernet-encrypted-fields 用)专用于字段级加密解密。轮换策略、泄露影响面、存储位置都该分开。
立即学习“Python免费学习笔记(深入)”;
-
SECRET_KEY推荐从/run/secrets/secret_key读取,由FileAwareEnv加载 -
ENCRYPTION_KEY必须另起一个 Secret,比如/run/secrets/encryption_key,且不能用SECRET_KEY衍生(如hashlib.sha256(SECRET_KEY).digest()) - CI/CD 中注入时,GitHub Secrets 或 GitLab CI Variables 要分两个独立变量,命名明确区分:
DJANGO_SECRET_KEYvsDJANGO_ENCRYPTION_KEY - 部署后立即运行
python manage.py diffsettings | grep -E '(SECRET|ENCRYPTION)_KEY',确认两者值不同、来源路径不同
最容易被忽略的是:密钥一旦进入 os.environ,就等于放弃了访问控制权。真正的安全不是“怎么读得出来”,而是“谁根本读不到”。文件挂载 + 进程外读取 + 物理隔离,这三步缺一不可。


















