阅读时间 4 分钟

API Key 不应该放在 shell 配置文件里

API Key 不应该放在 shell 配置文件里。这是很多开发者都有的习惯,图省事,但风险被长期低估。

最近一次操作失误让我意识到这个问题:一条命令找不到目标文件,fallback 执行了 env,把整个终端环境变量打印出来,十几个 API key 直接进了 AI 对话的上下文,不得不全部轮替。

事故很小,但揭示了一个结构性问题:把 key 放在 shell 配置文件里,意味着它们始终暴露在所有子进程、所有工具的视野里。

为什么 shell 配置文件不适合存 API key

不同的 shell 有不同的配置文件,但都面临同样的问题:

  • zsh~/.zshrc~/.zprofile
  • bash~/.bashrc~/.bash_profile~/.profile
  • fish~/.config/fish/config.fish

在这些文件里写 export API_KEY=xxx,后果是:

  • 每个终端会话启动就自动加载,任何子进程都能读到
  • envprintenv 等命令随时能看到明文
  • AI 工具、日志收集、调试输出都可能意外捕获
  • 一旦配置文件被同步到 dotfiles 仓库,直接公开

根本问题是:key 的生命周期远长于它实际被用到的时间

更好的方式

方案一:项目级 .env + 精确注入

最轻量的改进。每个项目只放自己用到的 key,通过脚本精确提取,不污染全局环境。

my-project/
  .env          # 只含这个项目需要的 key,加入 .gitignore
  run.sh        # 精确读取 .env,只注入必要变量
  scripts/
    main.py

run.sh 示例:

#!/bin/sh
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
ENV_FILE="$SCRIPT_DIR/.env"

GHOST_HOST=$(grep '^GHOST_HOST=' "$ENV_FILE" | head -1 | cut -d= -f2-)
GHOST_ADMIN_API_KEY=$(grep '^GHOST_ADMIN_API_KEY=' "$ENV_FILE" | head -1 | cut -d= -f2-)
export GHOST_HOST GHOST_ADMIN_API_KEY

exec "$SCRIPT_DIR/.venv/bin/python" "$SCRIPT_DIR/scripts/main.py" "$@"

优点:简单,无依赖,适用于所有操作系统。

缺点:key 仍然明文存在磁盘。

方案二:macOS Keychain

系统级加密存储。key 加密保存在 Keychain 里,只在被读取的瞬间解密到内存,catgrepenv 全都看不到。

存入:

security add-generic-password -a "$USER" -s "MOONSHOT_API_KEY" -w "sk-your-key-here"

在脚本里读取:

MOONSHOT_API_KEY=$(security find-generic-password -a "$USER" -s "MOONSHOT_API_KEY" -w)
export MOONSHOT_API_KEY

使用体验: 开机登录 Mac 时系统 Keychain 自动解锁,整个会话期间脚本可以直接读取,不需要输密码。第一次访问某个条目时系统会弹一次授权框,点"始终允许"后就再也不会弹了。

这是替代 shell 配置文件存 key 的最直接方案,对工作流几乎没有影响。macOS 独有,Linux 和 Windows 有各自的等效方案(secret-tool、Windows Credential Manager)。

方案三:Bitwarden CLI(私有部署)

如果你有 Bitwarden 实例(包括私有部署的 Vaultwarden),可以用官方 CLI bw 在脚本里动态拉取 key。

配置私有部署地址:

bw config server https://your-bitwarden.example.com

登录并获取 session:

bw login
export BW_SESSION=$(bw unlock --raw)

Session 在当前终端会话内有效,关闭终端后失效,不会持久暴露。

在脚本里读取指定条目:

MOONSHOT_API_KEY=$(bw get password "Moonshot API Key")
export MOONSHOT_API_KEY

bw get password 按条目名称检索,返回该条目的 password 字段。也可以用 bw get notes 获取备注字段,适合存储格式复杂的 key。

适合的场景: 多台设备共用同一套 key,或者需要跨平台(macOS/Linux/Windows 都支持)。key 集中在 Bitwarden 管理,换设备只需重新登录,不用手动迁移 .env 文件。

迁移建议

如果你现在 shell 配置文件里有大量 export KEY=xxx

  1. 按项目整理,每个项目建一个 .env,只放该项目用到的 key
  2. 高价值凭证(数据库密码、支付相关)迁移到 Keychain 或 Bitwarden
  3. 把 shell 配置文件里的 export KEY= 全部删掉
  4. 确认 .env 文件加入了 .gitignore

不需要一次做完。先把最敏感的几个迁走,剩下的项目用到哪个迁哪个。

总结

方案 明文落盘 跨平台 跨设备 依赖
shell 配置文件 ✓(危险) 需手动同步
项目 .env 需手动同步
macOS Keychain 系统内置
Bitwarden CLI bw CLI

没有完美方案,但任何一个都比 shell 配置文件好。最实用的起点是:清空配置文件里的 key,改用项目级 .env,高价值凭证再逐步迁到 Keychain 或 Bitwarden。