
envsec v1.0.0-rc.2
使用原生操作系统凭据存储(macOS Keychain、Linux Secret Service、Windows Credential Manager)管理环境密钥的安全CLI工具
envsec
使用操作系统原生凭据存储进行安全的环境密钥管理。
演示

功能特性
- 将密钥存储在操作系统原生凭据存储中(而非纯文本文件)
- 跨平台:macOS、Linux、Windows
- 按上下文组织密钥(例如
myapp.dev、stripe-api.prod、work.staging) - 通过 SQLite 跟踪密钥元数据(键名、时间戳)
- 使用 glob 模式搜索上下文和密钥
- 运行带有密钥插值的命令
- 使用
cmd保存并重新运行命令(搜索、列出、运行、删除) - 将密钥导出为
.env文件(通过audit进行生成跟踪) - 将密钥导出为 shell 环境变量(
eval $(envsec env)) - 从
.env文件加载密钥(带冲突检测) - 使用 GPG 加密共享密钥给团队成员
- 交互式终端 UI(
envsec tui),无需记忆命令即可管理密钥
包
这是一个包含以下包的 monorepo:
| 包 | 描述 | npm |
|---|---|---|
envsec | 用于管理密钥的 CLI 工具 | |
@envsec/sdk | 用于以编程方式加载密钥的 Node.js / Bun SDK | |
@envsec/core | 核心引擎 — 操作系统凭据存储适配器 + 元数据数据库 | |
@envsec/tui | 用于密钥管理的交互式终端 UI |
SDK 快速开始
如需从 Node.js 或 Bun 以编程方式访问密钥,请使用 @envsec/sdk:
npm install @envsec/sdk
import { loadSecrets } from "@envsec/sdk";
// Load and inject into process.env
await loadSecrets({ context: "myapp.dev", inject: true });
// Or use the client for full control
import { EnvsecClient } from "@envsec/sdk";
const client = await EnvsecClient.create({ context: "myapp.dev" });
const apiKey = await client.get("api.key");
await client.close();
查看完整的 SDK 文档 以了解所有 API、多上下文支持及选项。
环境要求
- Node.js >= 22
macOS
无需额外依赖。通过 security CLI 工具使用内置的钥匙串。
Linux
需要 libsecret-tools(提供 secret-tool 命令),它通过 D-Bus 与 GNOME Keyring、KDE Wallet 或任何 Secret Service API 提供程序通信。
# Debian / Ubuntu
sudo apt install libsecret-tools
# Fedora
sudo dnf install libsecret
# Arch
sudo pacman -S libsecret
必须有一个正在运行的 D-Bus 会话和一个密钥环守护进程(例如 gnome-keyring-daemon)。大多数桌面环境会自动处理这一点。
Windows
无需额外依赖。通过 cmdkey 和 PowerShell 使用内置的 Windows 凭据管理器。
安装
Homebrew(macOS / Linux)
brew tap davidnussio/homebrew-tap
brew install envsec
npm
npm install -g envsec
npx(无需安装)
npx envsec
mise
mise use -g npm:envsec
用法
大多数命令需要通过 --context(或 -c)指定一个上下文。上下文是用于对密钥进行分组的自由格式标签——例如 myapp.dev、stripe-api.prod、work.staging。
全局选项
这些选项在所有命令中均可用:
--context、-c— 上下文名称(例如myapp.dev、stripe-api.prod)。同时读取ENVSEC_CONTEXT环境变量--debug、-d— 启用调试日志--json— 以 JSON 格式输出,便于脚本处理--db— SQLite 数据库文件的路径(默认:~/.envsec/store.sqlite)。同时读取ENVSEC_DB环境变量
自定义数据库路径
默认情况下,元数据存储在 ~/.envsec/store.sqlite。你可以通过 --db 或 ENVSEC_DB 环境变量覆盖此路径:
# Use a project-local database
envsec --db ./local-store.sqlite -c myapp.dev list
# Or via environment variable
export ENVSEC_DB=/shared/team/envsec.sqlite
envsec -c myapp.dev list
--db 标志优先于 ENVSEC_DB。使用场景包括按项目划分的数据库、网络驱动器上的团队共享数据库,以及使用临时存储的 CI/CD。
添加密钥
将密钥存储到操作系统凭据存储中。
<key>— 密钥名称(例如api.key、db.password)--value、-v— 要存储的值(省略则进入交互式掩码输入提示)--expires、-e— 过期时长(例如30m、2h、7d、4w、3mo、1y)
# Store a value inline
envsec -c myapp.dev add api.key --value "sk-abc123"
# Or use the short alias
envsec -c myapp.dev add api.key -v "sk-abc123"
# Omit --value for an interactive masked prompt
envsec -c myapp.dev add api.key
# Set an expiry duration with --expires (-e)
envsec -c myapp.dev add api.key -v "sk-abc123" --expires 30d
# Supported duration units: m (minutes), h (hours), d (days), w (weeks), mo (months), y (years)
# Combinable: 1y6mo, 2w3d, 1d12h
envsec -c myapp.dev add api.key -v "sk-abc123" -e 6mo
获取密钥
从操作系统凭据存储中检索密钥值。
<key>— 要检索的密钥名称--quiet、-q— 仅打印原始值(无警告或额外输出)--json— 以 JSON 格式输出(包含 context、key、value、expires_at)
envsec -c myapp.dev get api.key
# Print only the raw value (no warnings or extra output)
envsec -c myapp.dev get api.key --quiet
envsec -c myapp.dev get api.key -q
删除密钥
从操作系统凭据存储中移除密钥。
<key>— 要删除的密钥名称(如果使用--all则为可选)--yes,-y— 跳过确认提示--all— 删除上下文中的所有密钥
envsec -c myapp.dev delete api.key
# or use the alias
envsec -c myapp.dev del api.key
重命名密钥
在同一上下文中重命名密钥。值和过期元数据将被保留。
<old-key>— 当前密钥名称<new-key>— 新密钥名称--force、-f— 如果目标已存在则覆盖
# Rename a key
envsec -c myapp.dev rename old.key new.key
# Overwrite target if it already exists
envsec -c myapp.dev rename old.key existing.key --force
列出上下文中的所有密钥
列出上下文中的所有密钥键和元数据。
--json— 以 JSON 格式输出
envsec -c myapp.dev list
列出所有上下文
列出所有可用的上下文及其密钥数量。
--json— 以 JSON 格式输出
# Without --context, lists all available contexts with secret counts
envsec list
搜索密钥
使用 glob 模式搜索密钥或上下文。
<pattern>— 要搜索的 glob 模式(例如api.*、myapp.*)--json— 以 JSON 格式输出
# Search secrets within a context
envsec -c myapp.dev search "api.*"
# Search contexts by pattern (without --context)
envsec search "myapp.*"
在上下文之间移动密钥
将密钥从一个上下文移动到另一个上下文。移动后,源密钥将被移除。
<pattern>— 要移动的 Glob 模式或精确密钥(如果使用--all则可选)--to、-t— 要将密钥移动到的目标上下文--all— 从源上下文移动所有密钥--force、-f— 覆盖目标上下文中现有的密钥--yes、-y— 跳过确认提示
# Move a single secret
envsec -c myapp.dev move api.token --to myapp.prod
# Move secrets matching a glob pattern
envsec -c myapp.dev move "redis.*" --to myapp.prod -y
# Move all secrets from one context to another
envsec -c myapp.dev move --all --to myapp.prod -y
# Overwrite existing secrets in the target context
envsec -c myapp.dev move "redis.*" --to myapp.prod --force -y
在上下文之间复制密钥
将密钥从一个上下文复制到另一个上下文。源密钥保持不变。
<pattern>— 要复制的 Glob 模式或精确密钥(如果使用--all则可选)--to、-t— 要将密钥复制到的目标上下文--all— 从源上下文复制所有密钥--force、-f— 覆盖目标上下文中现有的密钥--yes、-y— 跳过确认提示
# Copy a single secret
envsec -c myapp.dev copy api.token --to myapp.staging
# Copy secrets matching a glob pattern
envsec -c myapp.dev copy "redis.*" --to myapp.staging -y
# Copy all secrets from one context to another
envsec -c myapp.dev copy --all --to myapp.staging -y
# Overwrite existing secrets in the target context
envsec -c myapp.dev copy "redis.*" --to myapp.staging --force -y
使用密钥运行命令
执行命令时,通过占位符插值或作为环境变量注入密钥值。
<command>— 要执行的命令。使用{key}占位符进行密钥插值--inject、-i— 将所有上下文密钥作为环境变量注入(KEY.NAME→KEY_NAME)--save、-s— 保存此命令以供后续使用--name、-n— 已保存命令的名称(若与--save一起省略,则交互式提示输入)
# Placeholders {key} are resolved with secret values before execution
envsec -c myapp.dev run 'curl {api.url} -H "Authorization: Bearer {api.token}"'
# Any {dotted.key} in the command string is replaced with its value
envsec -c myapp.prod run 'psql {db.connection_string}'
# Inject ALL context secrets as environment variables (KEY.NAME → KEY_NAME)
envsec -c myapp.dev run --inject 'node server.js'
envsec -c myapp.dev run -i 'docker compose up'
# Combine --inject with placeholders
envsec -c myapp.dev run --inject 'curl {api.url} -H "Authorization: Bearer $API_TOKEN"'
# Save the command for later use with --save (-s) and --name (-n)
envsec -c myapp.dev run --save --name deploy 'kubectl apply -f - <<< {k8s.manifest}'
# If you use --save without --name, you'll be prompted interactively
envsec -c myapp.dev run --save 'psql {db.connection_string}'
如果任何占位符引用了不存在的密钥,命令将不会执行,你会看到明确的错误提示: