Go to file
voson bce01a0f2b
Some checks failed
Secrets MCP — Build & Release / 版本 & Release (push) Successful in 3s
Secrets MCP — Build & Release / 质量检查 (fmt / clippy / test) (push) Failing after 2m21s
Secrets MCP — Build & Release / Build Linux (secrets-mcp, musl) (push) Has been skipped
Secrets MCP — Build & Release / 部署 secrets-mcp (push) Has been skipped
Secrets MCP — Build & Release / 发布草稿 Release (push) Successful in 8s
chore(secrets-mcp): bump version to 0.1.2
Made-with: Cursor
2026-03-20 21:56:57 +08:00

secrets-mcp

Workspacesecrets-core + secrets-mcpHTTP Streamable MCP + Web。多租户密钥与元数据存 PostgreSQL用户通过 Google OAuth 登录,API Key 鉴权 MCP 请求;秘密数据用用户密码短语派生的密钥在客户端加密,服务端不持有原始密钥。

安装

cargo build --release -p secrets-mcp
# 产物: target/release/secrets-mcp

发版产物见 Gitea Releasetagsecrets-mcp-<version>Linux musl 预编译);其它平台本地 cargo build

环境变量与本地运行

复制 deploy/.env.example 为项目根目录 .env(已在 .gitignore),或导出同名变量:

变量 说明
SECRETS_DATABASE_URL 必填。PostgreSQL 连接串(建议专用库,如 secrets-mcp)。
BASE_URL 对外访问基址OAuth 回调为 {BASE_URL}/auth/google/callback。默认 http://localhost:9315
SECRETS_MCP_BIND 监听地址,默认 0.0.0.0:9315。反代时常为 127.0.0.1:9315
GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET 可选;不配置则无 Google 登录入口。运行时从环境读取,勿写入 CI、勿打入二进制。
cargo run -p secrets-mcp
  • WebBASE_URL登录、Dashboard、设置密码短语、创建 API Key
  • MCPStreamable HTTP 基址 {BASE_URL}/mcp,需 Authorization: Bearer <api_key> + X-Encryption-Key: <hex> 请求头。

加密架构(混合 E2EE

密钥派生

用户在 Web Dashboard 设置密码短语,浏览器使用 **Web Crypto APIPBKDF2-SHA256600k 次迭代)**在本地派生 256-bit AES 密钥。

  • Salt32B:首次设置时在浏览器生成,存入服务端 users.key_salt
  • key_check:派生密钥加密已知常量 "secrets-mcp-key-check",存入 users.key_check,用于登录时验证密码短语
  • 服务端不存储原始密钥,只存 salt + key_check

跨设备同步:新设备登录 → 输入相同密码短语 → 从服务端取 salt → 同样的 PBKDF2 → 得到相同密钥。

写入与读取流程

flowchart LR
    subgraph Web["Web 浏览器E2E"]
        P["密码短语"] --> K["PBKDF2 → 256-bit key"]
        K --> Enc["AES-256-GCM 加密"]
        K --> Dec["AES-256-GCM 解密"]
    end

    subgraph AI["AI 客户端MCP"]
        HdrKey["X-Encryption-Key: hex"]
    end

    subgraph Server["secrets-mcp 服务端"]
        Middleware["请求中临时持有 key\n请求结束即丢弃"]
        DB[(PostgreSQL\nsecrets.encrypted = 密文\nentries.metadata = 明文)]
    end

    Enc -->|密文| Server
    HdrKey -->|key + 请求| Middleware
    Middleware <-->|加解密| DB
    DB -->|密文| Dec

两种客户端对比

Web 浏览器 AI 客户端MCP
密钥位置 仅在浏览器内存 / sessionStorage MCP 配置 headers 中
加解密位置 客户端(真正 E2E 服务端临时(请求级生命周期)
安全边界 服务端零知识 依赖 TLS + 服务端内存隔离

敏感数据传输

  • OAuth client_secret 只存服务端环境变量,不发给浏览器
  • API Key 创建时原始 key 仅展示一次,库中只存 SHA-256 哈希
  • X-Encryption-Key 随 MCP 请求经 TLS 传输,服务端仅在请求处理期间持有(不持久化)
  • 生产环境必须走 HTTPS/TLS

AI 客户端配置

在 Web Dashboard 设置密码短语后,解锁页面会按客户端格式生成配置。常见客户端示例如下:

Cursor / Claude Desktop 风格:

{
  "mcpServers": {
    "secrets": {
      "url": "https://secrets.example.com/mcp",
      "headers": {
        "Authorization": "Bearer sk_abc123...",
        "X-Encryption-Key": "a1b2c3...64位hex"
      }
    }
  }
}

OpenCode 风格:

{
  "mcp": {
    "secrets": {
      "type": "remote",
      "enabled": true,
      "url": "https://secrets.example.com/mcp",
      "headers": {
        "Authorization": "Bearer sk_abc123...",
        "X-Encryption-Key": "a1b2c3...64位hex"
      }
    }
  }
}

数据模型

主表 entriesnamespacekindnametagsmetadata,多租户时带 user_id+ 子表 secrets(每行一个加密字段:field_nameencrypted)。另有 entries_historysecrets_historyaudit_log,以及 users(含 key_saltkey_checkkey_params)、oauth_accountsapi_keys。首次连库自动迁移建表。

位置 字段 说明
entries namespace 一级隔离,如 refiningricnsmart
entries kind serverservicekey 等(可扩展)
entries name 人类可读标识
entries metadata 明文 JSONip、url、key_ref 等)
secrets field_name 明文字段名,便于 schema 展示
secrets encrypted AES-GCM 密文(含 nonce
users key_salt PBKDF2 salt32B首次设置密码短语时写入
users key_check 派生密钥加密已知常量,用于验证密码短语
users key_params 派生算法参数,如 {"alg":"pbkdf2-sha256","iterations":600000}

PEM 共享(key_ref

同一 PEM 可被多条 server 记录引用:将 PEM 存为 kind=key 的 entry在服务器条目的 metadata.key_ref 中写 key 的名称;轮换时只更新 key 对应记录即可。

审计日志

addupdatedelete 等写操作写入 audit_log(操作类型、对象、摘要,不含 secret 明文)。

SELECT action, namespace, kind, name, actor, detail, created_at
FROM audit_log
ORDER BY created_at DESC
LIMIT 20;

项目结构

Cargo.toml
crates/secrets-core/     # db / crypto / models / audit / service
crates/secrets-mcp/     # MCP HTTP、Web、OAuth、API Key
scripts/
deploy/                 # systemd、.env 示例

CI/CDGitea Actions

.gitea/workflows/secrets.yml

  • 触发:任意分支 push,且变更路径包含 crates/**deploy/**、根目录 Cargo.toml / Cargo.lock
  • 流水线:解析 crates/secrets-mcp/Cargo.toml 版本 → secrets-mcp-<version> 的 tag 已存在则整次运行失败(避免重复发版)→ 否则自动打 tag → cargo fmt / clippy --locked / test --locked → 交叉编译 x86_64-unknown-linux-muslsecrets-mcp
  • Release可选:配置仓库 Secret RELEASE_TOKENGitea PAT明文勿 base64会通过 API 创建草稿 Release、在 Linux 构建成功后上传 tar.gz.sha256,再自动将草稿正式发布;未配置则跳过创建 Release 与产物上传,仅保留 tag 与构建结果。
  • 部署(可选):仅在 mainfeat/mcpmcp 分支且构建成功时,若已配置 vars.DEPLOY_HOSTvars.DEPLOY_USERsecrets.DEPLOY_SSH_KEY,则 deploy-mcp 通过 SCP/SSH 更新目标机二进制并 systemctl restart secrets-mcp
  • 通知(可选)vars.WEBHOOK_URL 为飞书 Webhook 时,构建/部署/发布节点会推送简要状态。
./scripts/setup-gitea-actions.sh   # 通过 Gitea API 写入 RELEASE_TOKEN、WEBHOOK_URL、部署相关变量等

详见 AGENTS.md(发版规则、代码规范)。

Description
Secrets management project
Readme 4 MiB
2026-04-10 17:14:37 +08:00
Languages
Rust 66%
HTML 29.5%
Shell 2.1%
Python 2%
JavaScript 0.4%