mcpField
S
sealkeep

sealkeep

本地服务
github.com/munhq安全11 天前更新

关于 sealkeep

sealkeep 为 AI Agent 管理机密信息,可将命名机密注入命令环境,并从输出中脱敏。它包含命令行工具、MCP 服务和防护钩子。

主要功能

  1. 01将机密注入命令
  2. 02脱敏命令输出中的机密值
  3. 03使用系统密钥环和 Vault 存储
  4. 04扫描并导入机密文件
  5. 05拦截会打印机密的调用

适用场景

  1. 01运行需要 API 密钥的 Agent 命令
  2. 02从 .env 或 INI 文件迁移凭据
  3. 03避免机密进入 Agent 对话记录

MCP 相关

`sealkeep mcp` 服务提供 `list_secrets`、`run_with_secrets` 和 `store_status` 工具。任何工具都不会返回机密值。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"munhq-sealkeep": {
"command": "npx",
"args": [
"-y",
"@munhq/sealkeep"
],
"env": {
"SEALKEEP_CONFIG": "<SEALKEEP_CONFIG>"
}
}
}
}
启动命令npx -y @munhq/sealkeep
需要配置的环境变量
SEALKEEP_CONFIGPath of the config file (stores, aliases, guard rules). Default: the config folder of the OS. With no file, sealkeep uses the OS keyring.

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
npm@munhq/sealkeep0.5.0

工具

还没有获取到工具列表

本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。

详细介绍

sealkeep:你的 Agent 使用密钥,但永远看不到密钥

npm MCP registry CI Smithery MIT

Install in Cursor Install in VS Code

sealkeep

sealkeep 让 AI Agent 使用你的密钥,却无法看到密钥。

你只需将每个密钥保存一次,并为它命名,例如 shared/stripe/test/SECRET_KEY。Agent 通过 sealkeep list 查找名称,然后用它运行命令。Agent 永远不会读取密钥的值,也不需要向你索要密钥。

Agent 按名称请求密钥。sealkeep 会将密钥值放入某个命令的环境变量中,运行该命令,并在所有输出中将密钥值替换为 [sealkeep:NAME]。密钥值不会进入上下文、对话记录或文件。

agent ──► sealkeep run OPENROUTER_API_KEY -- sh -c 'curl -H "Authorization: Bearer $OPENROUTER_API_KEY" …'
              │
              ├─ reads the value from a store ──► OS keyring  (macOS Keychain, Secret Service, Windows Credential Manager)
              │                               └─► Vault KV v2 (a replica)
              ├─ starts the command with the value in its environment
              └─ redacts the value from stdout and stderr ──► agent sees [sealkeep:OPENROUTER_API_KEY]

它由四部分组成:

  1. 一个 CLI(sealkeep):set、list、run、import、scan、sync、别名和存储命令。
  2. 一个 MCP 服务(sealkeep mcp):提供 list_secrets、run_with_secrets 和 store_status 工具。没有任何工具会返回密钥值。
  3. 一个防护钩子(sealkeep guard):拒绝会打印密钥的工具调用,例如 cat .env 或 sealkeep get。
  4. 一项技能,告诉 Agent 何时以及如何使用 CLI。

安装

仅作为 MCP 服务使用(适用于任何客户端)时,命令为 npx -y @munhq/sealkeep:

{ "mcpServers": { "sealkeep": { "command": "npx", "args": ["-y", "@munhq/sealkeep"] } } }

在 Claude Code 中,插件只需一步即可添加 MCP 服务、技能和防护钩子:

/plugin marketplace add munhq/sealkeep
/plugin install sealkeep@sealkeep

下面的完整安装过程也可为 Claude Code、Codex 和 Cursor 完成相同操作。

Linux 和 macOS:

curl -fsSL https://raw.githubusercontent.com/munhq/sealkeep/main/install.sh | sh

该脚本会下载最新版本的二进制文件,通过 SHA256SUMS 校验文件,并将其复制到 ~/.local/bin,然后运行 sealkeep install。

使用 Rust:

cargo install --locked --git https://github.com/munhq/sealkeep
sealkeep install

sealkeep install 会查找这台机器上的 AI 客户端,并为每个客户端添加技能、MCP 服务和防护钩子:

客户端技能MCP 服务防护钩子
Claude Code(每个配置文件夹)<config>/skills/sealkeepclaude mcp add --scope user<config>/settings.json,对 Bash、Read、Grep 执行 PreToolUse
Codex$CODEX_HOME/skills/sealkeepcodex mcp add$CODEX_HOME/hooks.json,PreToolUse(通过 /hooks 批准一次)
Cursor~/.cursor/skills/sealkeep~/.cursor/mcp.json~/.cursor/hooks.json,beforeShellExecution

选项:--client claude,codex 仅安装到指定客户端。--dry-run 显示执行计划。--no-skills、--no-mcp 和 --no-hooks 可跳过对应部分。sealkeep 修改 JSON 文件前,会先创建备份(<file>.bak-<unix time>)。sealkeep uninstall 会移除 install 添加的内容。

运行 sealkeep doctor 检查存储和客户端。

名称

名称的格式为 <scope>/<project>/<env>/<KEY>:

部分值示例
scope密钥的所有者:personal、雇主或客户的名称,或者供多个 scope 共用的单个账户对应的 sharedpersonal、acme、shared
project仓库或服务example-app、stripe、ovh
envprod、dev、test、local。密钥没有环境时(例如账户的 API 密钥),省略此项prod
KEY程序读取的环境变量DATABASE_URL

文件夹名称使用小写字母(a-z、0-9、.、_、-)。密钥使用大写字母(A-Z、0-9、_),它就是 run 设置的变量。

personal/example-app/prod/DATABASE_URL
personal/example-app/dev/DATABASE_URL
personal/example-app/dev/STRIPE_SECRET_KEY   -> shared/stripe/test/SECRET_KEY   (alias)
acme/ovh/ovh-eu/APPLICATION_KEY
acme/cloudflare/API_TOKEN
shared/stripe/test/SECRET_KEY
shared/openrouter/API_KEY

一个值对应一个名称。 两个项目使用同一个账户时,将该值存一次,放在 shared/… 下,然后在每个项目文件夹中创建别名。这样,项目文件夹就包含该项目所需的所有变量,而轮换时只需更改一个值。

存储密钥
sealkeep set shared/openrouter/API_KEY -d "OpenRouter, the main account"   # writes to every store

sealkeep 会要求输入两次值,且不会回显。若要通过管道传入值,请使用 --stdin:

some-password-tool show openrouter | sealkeep set shared/openrouter/API_KEY --stdin

若要查找机器上的密钥,请运行 scan。它会打印每个 .env 文件的路径、密钥名称、每个密钥的类别(secret、config 或 empty),以及出现在多个位置的每个值对应的组编号。它绝不会打印任何值。它还会按路径列出其他常用于存放凭据的文件:

sealkeep scan ~/code --max-depth 4

若要将文件复制到文件夹中:

sealkeep import ../example-app/.env --to personal/example-app/dev \
  --map STRIPE_SECRET_KEY=shared/stripe/test/SECRET_KEY
sealkeep import ~/.ovh.conf --to acme/ovh            # INI: one folder for each section
sealkeep set personal/github/PAT --from-file ~/.github-token

import 会读取 dotenv 文件和 INI 文件(.ini、.conf、AWS credentials)。它只会打印名称。--map KEY=NAME 会将值存储在 NAME,并将项目密钥设为该值的别名。如果 NAME 已有不同的值,import 会停止并说明原因。导入后,请删除源文件,或将其放在 Agent 无法访问的位置。

让 Agent 使用密钥

告诉 Agent 要做什么。该技能会指示它运行 sealkeep list 获取名称,并运行 sealkeep run 执行命令:

sealkeep run shared/openrouter/API_KEY -- sh -c 'curl -sS -H "Authorization: Bearer $API_KEY" https://openrouter.ai/api/v1/key'
sealkeep run --all personal/example-app/dev -- npm run dev
sealkeep run -e GITHUB_TOKEN=personal/github/PAT -- gh api user

名称会设置由其密钥指定的变量。--all FOLDER 会为文件夹中的每个密钥设置一个变量,效果与 .env 文件相同。--recursive 还会包含子文件夹;此时,两个密钥若名称相同,就会报错。-e VAR=NAME 会设置一个名称不同的变量。STORE:NAME 仅从一个存储中读取。

对于从文件读取密钥的工具,--dotenv 会写入一个只有你能读取的临时文件。如果 $XDG_RUNTIME_DIR/sealkeep 存在,文件就会放在其中。sealkeep 会将文件路径填入命令中的 {dotenv},并在命令结束时删除该文件。此示例会将测试账户的登录信息提供给 Playwright MCP。Agent 输入名称 ADMIN_PASSWORD,Playwright 会填入对应的值:

sealkeep run --dotenv personal/example-app/dev/ADMIN_EMAIL --dotenv personal/example-app/dev/ADMIN_PASSWORD \
  -- npx @playwright/mcp@latest --secrets {dotenv}

--secrets <path> 是 @playwright/mcp 的选项(请参阅其 README)。

自行查看值
sealkeep get shared/openrouter/API_KEY

只有在 stdin 和 stdout 都是终端时,get 才能使用。Agent 运行命令时没有终端,因此 get 会拒绝执行,防护钩子也会拒绝执行。

存储

sealkeep 会按配置文件中的顺序在各存储中查找不带限定的名称。第一个包含该名称的存储会提供对应的值。

在 Linux 上,配置文件为 ~/.config/sealkeep/config.toml;在 macOS 上为 ~/Library/Application Support/sealkeep/config.toml。$SEALKEEP_CONFIG 可指定其他路径。没有配置文件时,sealkeep 会有一个名为 local 的密钥环存储。

[[store]]
name = "local"
kind = "keyring"

[[store]]
name = "vault"
kind = "vault"
address = "http://127.0.0.1:{port}"
mount = "agent"
auth = "kubernetes"
role = "sealkeep"
jwt_command = ["kubectl", "-n", "vault", "create", "token", "sealkeep", "--duration", "10m"]
port_forward = ["kubectl", "-n", "vault", "port-forward", "svc/vault", "{port}:8200"]

[aliases]
"personal/example-app/dev/STRIPE_SECRET_KEY" = "shared/stripe/test/SECRET_KEY"

[guard]
block_dotenv = true
deny = ["vault kv get", "ansible-vault view"]
OS 密钥环
OS存储位置
macOS登录钥匙串
Linux、BSD会话 D-Bus 上的 Secret Service(GNOME Keyring、KWallet)
WindowsCredential Manager

每个机密都是一条条目,服务名为 sealkeep,机密名称用作账户。索引条目(__index__)保存名称及其描述。

在 Linux 上,密钥环必须处于解锁状态。登录时,桌面会话会解锁密钥环。没有桌面的会话(SSH、登录时未设置密钥环密码)会导致密钥环处于锁定状态,且不会显示解锁提示。每次启动后运行一次:

sealkeep unlock

此命令会询问登录密钥环的密码,并将其传给 gnome-keyring-daemon --unlock。每次调用密钥环最多等待 30 秒(SEALKEEP_KEYRING_TIMEOUT),因此 Agent 会收到错误,调用也不会一直卡住。

将 Vault 用作副本

Vault(或 OpenBao)KV v2 挂载可以保存密钥环的副本,用于另一台机器或备份。每个文件夹对应一个 KV 机密,每个键对应其中的一个字段:shared/stripe/test/SECRET_KEY 是 agent/shared/stripe/test 中的 SECRET_KEY 字段。每个机密的 custom_metadata 会列出其键及其描述,因此 list 不会读取任何值。

对于 Kubernetes 内的 Vault,sealkeep 可以通过 Kubernetes API 使用端口转发访问 Vault,并使用短期 ServiceAccount 令牌登录。这样,机器上就不会保留 Vault 令牌:

sealkeep store add-vault vault \
  --address 'http://127.0.0.1:{port}' --mount agent --auth kubernetes --role sealkeep \
  --jwt-command 'kubectl -n vault create token sealkeep --duration 10m' \
  --port-forward 'kubectl -n vault port-forward svc/vault {port}:8200'
sealkeep sync --from local --to vault   # one time, for the secrets that are already in the keyring

set、import 和 mv 会写入每个存储(Vault 存储只接受带文件夹的名称),因此各存储会保持一致。--store NAME 则只写入一个存储。Vault 端需要 KV v2 挂载、一个对 agent/data/* 具有 create、read 和 update 权限,并对 agent/metadata/* 具有 read、list 和 update 权限的策略,以及绑定到 ServiceAccount 的 Kubernetes 身份验证角色。使用 --auth token 时,sealkeep 会读取 $VAULT_TOKEN,或读取由 sealkeep store token vault 保存在密钥环中的令牌。

其他机密管理器

以下每一种都是一种存储类型。它会运行供应商的官方 CLI,因此适用供应商自身的登录方式(SSO、服务账户、生物识别),而 sealkeep 不会保留供应商令牌。值会通过标准输入或仅你本人可读的文件传给 CLI,不会作为命令参数传递,因此不会被 ps 显示。

存储添加方式布局值的传入方式
AWS Secrets Managersealkeep store add-aws aws --region eu-west-1每个文件夹对应一个 JSON 机密,sealkeep/<folder>--secret-string file://…
Google Secret Managersealkeep store add-gcp gcp --project acme-prod每个名称对应一个机密;注释中保存名称--data-file=-(标准输入)
Azure Key Vaultsealkeep store add-azure azure --vault acme-kv每个名称对应一个机密;标签中保存名称--file …
1Password(CLI 2.23+)sealkeep store add-1password op --vault Engineering每个文件夹对应一条安全备注,每个键对应一个隐藏字段通过标准输入传入条目 JSON
Bitwarden / Vaultwardensealkeep store add-bitwarden bw一条 sealkeep:<folder> 安全备注,每个键对应一个隐藏字段通过标准输入传入条目 JSON
OpenBaosealkeep store add-vault …同 Vault同 Vault

Google 和 Azure 的机密 ID 只允许使用部分字符,因此 ID 会将名称中的 / 替换为 --,并附加一个短哈希;实际名称保存在注释或标签中。Azure 会将已删除的机密保留在软删除状态,之后对同名机密执行 set 会将其恢复。对于 Bitwarden,请先解锁:export BW_SESSION=$(bw unlock --raw)。Bitwarden Secrets Manager CLI(bws)只接受通过命令参数传入的值,因此 sealkeep 使用密码管理器 CLI(bw)。

SSH 密钥

SSH Agent 仅在内存中保存带有口令的密钥。重启后,Agent 为空,Agent 的 git push 会因 Permission denied (publickey) 而失败。sealkeep 会保存口令并加载密钥:

sealkeep set personal/ssh/ID_ED25519_PASSPHRASE
sealkeep ssh-add ~/.ssh/id_ed25519 --passphrase personal/ssh/ID_ED25519_PASSPHRASE
sealkeep ssh-load      # unlock runs it too

ssh-load 会将 sealkeep 作为 SSH_ASKPASS 程序运行 ssh-add。askpass 步骤仅在其父进程是 ssh-add 且一次性令牌匹配时才会响应,并从存储中读取口令,因此口令不会写入文件或输出。--agent 用于选择 Agent 套接字;默认值为 $SSH_AUTH_SOCK。

MCP

sealkeep mcp 会通过 stdio 提供以下工具:

工具功能
list_secrets列出所有名称或某个 folder 的名称、存储和说明。
run_with_secrets在环境中提供 folders 和 secrets,并在临时文件中提供 dotenv,运行 command(参数列表,不使用 shell)。返回经过脱敏的退出代码、stdout 和 stderr。默认时间限制为 120 s,最长为 900 s。每个流最多截取 100 KiB。
store_status检查各个存储当前是否可用。

防护钩子

该钩子会拒绝以下工具调用,并告知 Agent 使用 sealkeep run:

  1. sealkeep get,包括在 $(…)、反引号和 bash -c 中使用的情况。
  2. 读取 sealkeep 密钥环条目:secret-tool lookup service sealkeep …、security find-generic-password -s sealkeep … -w、keyring get sealkeep …。
  3. 当 block_dotenv 启用时,通过 shell 命令或 Read 和 Grep 工具读取 .env 文件。.env.example、.env.sample、.env.template 和 .env.dist 仍可读取。
  4. guard.deny 中的每个命令前缀。

Claude Code 还采用另外两层防护:

  1. 输出防护(sealkeep guard --after,适用于 Bash、Read 和 Grep 的 PostToolUse 钩子)。工具调用后,它会将结果与已存储密钥的值进行比对,使用与 run 相同的脱敏形式。如果结果中包含某个值,钩子会在 Agent 读取结果前将其替换为 [sealkeep:NAME],并在说明中指出密钥名称。这也涵盖先运行 env > out.txt 再读取 out.txt,以及路径中使用通配符或变量的情况。存储会并行加载,最长等待 4 秒;未响应的存储不会提供任何值。Claude Code 会在其自身的遥测中记录原始输出。
  2. 拒绝规则(settings.json 中的 permissions.deny)。sealkeep install 会添加 Read(**/.env)、Read(**/.env.local)、Read(**/*.env),以及针对其他 .env.* 名称的规则。Claude Code 会根据路径检查这些规则,因此 Read 工具和它能识别的文件命令无法通过 shell 技巧访问文件。启用 block_dotenv 时,安装程序会添加这些规则;sealkeep uninstall 会将其移除。

sealkeep 能保护什么,不能保护什么

sealkeep 会将密钥排除在 Agent 上下文、对话记录和项目文件之外。每次使用都会记入审计日志(Linux 上为 ~/.local/share/sealkeep/audit.jsonl,或 $SEALKEEP_AUDIT_LOG),记录名称和命令,但绝不记录密钥值。

脱敏会匹配原始值、JSON 转义形式、百分号编码形式和 Base64 形式。当某个值的键名看起来像密钥(KEY、TOKEN、SECRET、PASS、AUTH 等类似单词),当它是带密码的 URL,或长度不少于 16 个字符时,该值会被脱敏。PORT=3000 这样的配置值仍可读取。短于 4 个字符的值不会被脱敏。以其他方式转换值的命令(例如生成哈希或截取部分值)可能会以 sealkeep 无法匹配的形式输出该值。

能够以你的用户身份运行任意 shell 命令的 Agent,也能读取你的用户可以读取的内容。sealkeep 不会改变这一点。它让安全的使用方式更简单,拒绝获取密钥值的常见途径,并记录每次使用。为 Agent 提供权限范围较小的密钥:受限的 Stripe 密钥、有支出限额的 OpenRouter 密钥,以及用于网页登录的测试账户。

构建和测试

cargo build --release
cargo test --features test-store

test-store 功能会用文件替代操作系统密钥环,但仅用于测试。发布版二进制文件不包含此功能。

许可证

MIT

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。