# secrets 跨设备密钥与配置管理 CLI,基于 Rust + PostgreSQL 18。 将服务器信息、服务凭据统一存入数据库,供本地工具和 AI 读取上下文。敏感数据(`encrypted` 字段)使用 AES-256-GCM 加密存储,主密钥由 Argon2id 从主密码派生并存入系统钥匙串。 ## 安装 ```bash cargo build --release # 或从 Release 页面下载预编译二进制 ``` ## 首次使用(每台设备各执行一次) ```bash # 1. 配置数据库连接(会先验证连接可用再写入) secrets config set-db "postgres://postgres:@:/secrets" # 2. 初始化主密钥(提示输入主密码,派生后存入 OS 钥匙串) secrets init ``` 主密码不会存储,仅用于派生主密钥。同一主密码在所有设备上会得到相同主密钥(salt 存于数据库,首台设备生成后共享)。 **主密钥存储**:macOS → Keychain;Windows → Credential Manager;Linux → keyutils(会话级,重启后需再次 `secrets init`)。 **从旧版(明文存储)升级**:升级后首次运行需执行 `secrets init` 即可(明文记录需手动重新 add 或通过 update 更新)。 ## AI Agent 快速指南 这个 CLI 以 AI 使用优先设计。核心路径只有一条:**读取用 `search`,写入用 `add` / `update`**。 ### 第一步:发现有哪些数据 ```bash # 列出所有记录摘要(默认最多 50 条,安全起步) secrets search --summary --limit 20 # 按 namespace 过滤 secrets search -n refining --summary --limit 20 # 按最近更新排序 secrets search --sort updated --limit 10 --summary ``` `--summary` 只返回轻量字段(namespace、kind、name、tags、desc、updated_at),不含完整 metadata 和 secrets。 ### 第二步:精确读取单条记录 ```bash # 精确定位(namespace + kind + name 三元组) secrets search -n refining --kind service --name gitea # 获取完整记录含 secrets(JSON 格式,AI 最易解析) secrets search -n refining --kind service --name gitea -o json --show-secrets # 直接提取单个字段值(最短路径) secrets search -n refining --kind service --name gitea -f secret.token secrets search -n refining --kind service --name gitea -f metadata.url # 同时提取多个字段 secrets search -n refining --kind service --name gitea \ -f metadata.url -f metadata.default_org -f secret.token ``` `-f secret.*` 会自动解锁 secrets,无需额外加 `--show-secrets`。 ### 输出格式 | 场景 | 推荐命令 | |------|----------| | AI 解析 / 管道处理 | `-o json` 或 `-o json-compact` | | 写入 `.env` 文件 | `-o env --show-secrets` | | 人类查看 | 默认 `text`(TTY 下自动启用) | | 非 TTY(管道/重定向) | 自动 `json-compact` | ```bash # 管道直接 jq 解析(非 TTY 自动 json-compact) secrets search -n refining --kind service | jq '.[].name' secrets search -n refining --kind service --name gitea --show-secrets | jq '.secrets.token' # 导出为可 source 的 env 文件(单条记录) secrets search -n refining --kind service --name gitea -o env --show-secrets \ > ~/.config/gitea/config.env ``` ## 完整命令参考 ```bash # 查看帮助(包含各子命令 EXAMPLES) secrets --help secrets init --help # 主密钥初始化 secrets search --help secrets add --help secrets update --help secrets delete --help secrets config --help # ── search ────────────────────────────────────────────────────────────────── secrets search --summary --limit 20 # 发现概览 secrets search -n refining --kind service # 按 namespace + kind secrets search -n refining --kind service --name gitea # 精确查找 secrets search -q mqtt # 关键词模糊搜索 secrets search --tag hongkong # 按 tag 过滤 secrets search -n refining --kind service --name gitea -f secret.token # 提取字段 secrets search -n refining --kind service --name gitea -o json --show-secrets # 完整 JSON secrets search --sort updated --limit 10 --summary # 最近改动 secrets search -n refining --summary --limit 10 --offset 10 # 翻页 # ── add ────────────────────────────────────────────────────────────────────── secrets add -n refining --kind server --name my-server \ --tag aliyun --tag shanghai \ -m ip=47.117.131.22 -m desc="Aliyun Shanghai ECS" \ -s username=root -s ssh_key=@./keys/server.pem secrets add -n refining --kind service --name gitea \ --tag gitea \ -m url=https://gitea.refining.dev -m default_org=refining \ -s token= # ── update ─────────────────────────────────────────────────────────────────── secrets update -n refining --kind server --name my-server -m ip=10.0.0.1 secrets update -n refining --kind service --name gitea --add-tag production -s token= secrets update -n refining --kind service --name mqtt --remove-meta old_port --remove-secret old_key # ── delete ─────────────────────────────────────────────────────────────────── secrets delete -n refining --kind service --name legacy-mqtt # ── init ───────────────────────────────────────────────────────────────────── secrets init # 主密钥初始化(每台设备一次,主密码派生后存钥匙串) # ── config ─────────────────────────────────────────────────────────────────── secrets config set-db "postgres://postgres:@:/secrets" # 先验证再写入 secrets config show # 密码脱敏展示 secrets config path # 打印配置文件路径 # ── 调试 ────────────────────────────────────────────────────────────────────── secrets --verbose search -q mqtt RUST_LOG=secrets=trace secrets search ``` ## 数据模型 单张 `secrets` 表,首次连接自动建表;同时自动创建 `audit_log` 表,记录所有写操作。 | 字段 | 说明 | |------|------| | `namespace` | 一级隔离,如 `refining`、`ricnsmart` | | `kind` | 记录类型,如 `server`、`service`(可自由扩展) | | `name` | 人类可读唯一标识 | | `tags` | 多维标签,如 `["aliyun","hongkong"]` | | `metadata` | 明文描述信息(ip、desc、domains 等) | | `encrypted` | 敏感凭据(ssh_key、password、token 等),AES-256-GCM 加密存储 | `-m` / `--meta` 写入 `metadata`,`-s` / `--secret` 写入 `encrypted`,`value=@file` 从文件读取内容。加解密使用主密钥(由 `secrets init` 设置)。 ## 审计日志 `add`、`update`、`delete` 操作成功后自动向 `audit_log` 表写入一条记录,包含操作类型、操作对象和变更摘要(不含 secret 值)。操作者取自 `$USER` 环境变量。 ```sql -- 查看最近 20 条审计记录 SELECT action, namespace, kind, name, actor, detail, created_at FROM audit_log ORDER BY created_at DESC LIMIT 20; ``` ## 项目结构 ``` src/ main.rs # CLI 入口(clap),含各子命令 after_help 示例 output.rs # OutputMode 枚举 + TTY 检测 config.rs # 配置读写(~/.config/secrets/config.toml) db.rs # 连接池 + auto-migrate(secrets + audit_log + kv_config) crypto.rs # AES-256-GCM 加解密、Argon2id 派生、OS 钥匙串 models.rs # Secret 结构体 audit.rs # 审计日志写入(audit_log 表) commands/ init.rs # 主密钥初始化(首次/新设备) add.rs # upsert,支持 -o json config.rs # config set-db/show/path search.rs # 多条件查询,支持 -f/-o/--summary/--limit/--offset/--sort delete.rs # 删除 update.rs # 增量更新(合并 tags/metadata/encrypted) scripts/ setup-gitea-actions.sh # 配置 Gitea Actions 变量与 Secrets ``` ## CI/CD(Gitea Actions) 推送 `main` 分支时自动:fmt/clippy 检查 → musl 构建 → 创建 Release 并上传二进制。 **首次使用需配置 Actions 变量和 Secrets:** ```bash # 需有 ~/.config/gitea/config.env(GITEA_URL、GITEA_TOKEN、GITEA_WEBHOOK_URL) ./scripts/setup-gitea-actions.sh ``` - `RELEASE_TOKEN`(Secret):Gitea PAT,用于创建 Release 上传二进制 - `WEBHOOK_URL`(Variable):飞书通知,可选 - **注意**:Secret/Variable 的 `data`/`value` 字段需传入原始值,不要 base64 编码 详见 [AGENTS.md](AGENTS.md)。