密钥绝不能硬编码在代码中,必须通过环境变量或密钥管理服务外部注入;开发用python-dotenv加载.env文件(不提交Git),生产由Docker/K8s/云平台注入;os.getenv()安全读取并校验,禁用os.environ直接访问。

为什么不能把密钥写死在代码里
硬编码 API_KEY = "sk-xxx" 是最常见也最危险的做法。一旦代码提交到 GitHub,密钥就等于公开;哪怕加了 .gitignore,本地开发时也容易误传、被日志打印、或在调试中意外暴露。Python 本身不提供运行时密钥隔离机制,必须靠外部注入 + 显式加载。
关键不是“能不能读到”,而是“谁能在什么环节看到”。环境变量只是第一道防线——它让密钥脱离代码体,但依然依赖操作系统层的隔离能力(比如不同用户、不同容器)。
用 os.getenv() 安全读取环境变量
os.getenv() 比直接访问 os.environ 更安全:它允许设默认值且不会因键不存在而抛 KeyError。但默认值绝不能是真实密钥,更不能是空字符串(否则可能静默失败)。
- ✅ 正确做法:
api_key = os.getenv("OPENAI_API_KEY", None),后续显式检查 if not api_key:
- ❌ 危险写法:
api_key = os.environ["OPENAI_API_KEY"] —— 服务启动直接崩,且错误堆栈可能泄露变量名
- ⚠️ 注意:某些框架(如 Flask)会自动从
.env 加载,但它们底层仍调用 os.getenv(),不要混用两套逻辑
用 python-dotenv 管理本地开发环境
python-dotenv 只应在开发/测试环境启用,生产环境必须由系统或容器平台注入环境变量(如 Docker 的 -e、K8s 的 Secret)。它读取 .env 文件,但文件本身不能进 Git。
- 安装:
pip install python-dotenv
- 项目根目录放
.env,内容如:OPENAI_API_KEY=sk-xxx(无引号、无空格)
- 在入口文件(如
main.py 或 app.py)最顶部加:from dotenv import load_dotenv; load_dotenv()
- ⚠️ 坑:如果
.env 文件路径不对(比如不在当前工作目录),load_dotenv() 默认不报错也不提示 —— 可加 verbose=True 调试
生产部署时环境变量必须由外部注入
Docker、云函数、托管平台(如 Vercel、Render)都支持在运行时注入环境变量,这是唯一合规方式。Python 进程启动前,变量已存在于 os.environ 中,os.getenv() 就能直接取到。
- Docker 示例:
docker run -e OPENAI_API_KEY="sk-xxx" myapp
- 云函数(如 AWS Lambda):在控制台配置环境变量,Lambda 自动注入,无需改代码
- ⚠️ 重要:别在 Dockerfile 里用
ENV 写密钥 —— 镜像层会永久保留,任何人拉取镜像都能 docker history 看到
- ⚠️ 更隐蔽的坑:某些 CI/CD 工具(如 GitHub Actions)允许在 Secrets 里定义变量,但需确认是否真正注入到运行时环境(有些只注入到构建阶段)
环境变量不是银弹。它解决的是“密钥不进代码”,但没解决“密钥权限最小化”和“轮换难”的问题。真要上生产,还得配合密钥管理服务(如 HashiCorp Vault、AWS Secrets Manager),而 Python 侧只是多一次 HTTP 请求取值而已。
api_key = os.getenv("OPENAI_API_KEY", None),后续显式检查 if not api_key:
api_key = os.environ["OPENAI_API_KEY"] —— 服务启动直接崩,且错误堆栈可能泄露变量名.env 加载,但它们底层仍调用 os.getenv(),不要混用两套逻辑python-dotenv 管理本地开发环境
python-dotenv 只应在开发/测试环境启用,生产环境必须由系统或容器平台注入环境变量(如 Docker 的 -e、K8s 的 Secret)。它读取 .env 文件,但文件本身不能进 Git。
- 安装:
pip install python-dotenv - 项目根目录放
.env,内容如:OPENAI_API_KEY=sk-xxx(无引号、无空格) - 在入口文件(如
main.py或app.py)最顶部加:from dotenv import load_dotenv; load_dotenv() - ⚠️ 坑:如果
.env文件路径不对(比如不在当前工作目录),load_dotenv()默认不报错也不提示 —— 可加verbose=True调试
生产部署时环境变量必须由外部注入
Docker、云函数、托管平台(如 Vercel、Render)都支持在运行时注入环境变量,这是唯一合规方式。Python 进程启动前,变量已存在于 os.environ 中,os.getenv() 就能直接取到。
- Docker 示例:
docker run -e OPENAI_API_KEY="sk-xxx" myapp
- 云函数(如 AWS Lambda):在控制台配置环境变量,Lambda 自动注入,无需改代码
- ⚠️ 重要:别在 Dockerfile 里用
ENV 写密钥 —— 镜像层会永久保留,任何人拉取镜像都能 docker history 看到
- ⚠️ 更隐蔽的坑:某些 CI/CD 工具(如 GitHub Actions)允许在 Secrets 里定义变量,但需确认是否真正注入到运行时环境(有些只注入到构建阶段)
环境变量不是银弹。它解决的是“密钥不进代码”,但没解决“密钥权限最小化”和“轮换难”的问题。真要上生产,还得配合密钥管理服务(如 HashiCorp Vault、AWS Secrets Manager),而 Python 侧只是多一次 HTTP 请求取值而已。
docker run -e OPENAI_API_KEY="sk-xxx" myapp
ENV 写密钥 —— 镜像层会永久保留,任何人拉取镜像都能 docker history 看到


















