riptideslabs/keyledger
GitHub: riptideslabs/keyledger
一个用 Go 构建的终端仪表盘工具,提供跨多个 AI 供应商 API 密钥的统一清单、健康评分和快照差异追踪。
Stars: 24 | Forks: 0
# KeyLedger
KeyLedger 是一个交互式终端仪表板,它为您提供跨 AI 供应商发布的每个 API key 的统一视图——包含健康评分、快照差异对比和加密凭证存储。

## 功能
- **交互式 TUI** — 使用 [Bubble Tea](https://github.com/charmbracelet/bubbletea) 构建的全屏终端仪表板
- **统一清单** — 在可配置的超时时间内同时查询您的所有 AI 供应商
- **健康评分** — 通过可配置的时长阈值标记过时、空闲或从未使用过的 key;在 key 视图中提供专用的且可排序的“风险”列
- **WorkSpaces 视图** — 每个供应商的层级式 workspace/project 树,包含每个作用域的 key 数量和风险明细,可作为 key 视图中的一个标签页访问
- **实时过滤** — 按名称、作用域、状态、时长、所有者、风险评分等条件搜索 key
- **快照管理器** — 在专用的快照视图中列出、导出、删除和对快照进行差异对比;从 key 或健康视图触发快照
- **定期监控模式** — 按计划收集 key,持久化到数据库,并自动导出 JSON 文件
- **加密凭证存储** — 凭证存储在 AES-256-GCM 加密的 SQLite 中;磁盘上绝不会留存明文
- **供应商管理 UI** — 交互式地启用/禁用供应商并配置凭证;凭证状态显示为 "set" 或 "missing"
## 文档
供应商设置指南、配置参考和示例位于 [keyledger.riptides.io](https://keyledger.riptides.io/)。
## 供应商覆盖范围
| 供应商 | Key 列出 | 所有者信息 | 最后使用 |
|---|---|---|---|
| OpenAI | ✓ | ✓ | ✓ |
| Anthropic | ✓ | ✓ | ✓ (30 天窗口期) |
| AWS IAM 访问 key | ✓ | ✓ | ✓ |
| AWS 服务特定凭证 | ✓ | ✓ | — |
| Google Cloud IAM | ✓ | — | — |
| Mistral | ✓ | ✓ | ✓ |
## 安装说明
### go install
```
go install github.com/riptideslabs/keyledger@latest
```
### 从源码构建
```
git clone https://github.com/riptideslabs/keyledger
cd keyledger
make build
./build/keyledger
```
### 安装到 GOPATH/bin
```
make install
```
需要 Go 1.25 或更高版本。不需要 CGO。
## 配置
### 凭证
启动 TUI 并按 **`p`** 打开供应商界面。选择一个供应商,启用它,然后输入您的 API 凭证——它们将存储在 AES-256-GCM 加密的 SQLite 数据库中,绝不会以明文形式写入磁盘。首次使用时,系统会提示您设置主密码。
### OpenAI
| 凭证字段 | 描述 |
|---|---|
| `admin_key` | 来自 platform.openai.com → API keys 的管理员 API key (`sk-admin-…`) |
此管理员 key 必须具有列出组织内所有 key 的权限。默认情况下会枚举所有 project;在供应商界面中使用 **排除项目** 可跳过特定项目。
### Anthropic
| 凭证字段 | 描述 |
|---|---|
| `admin_key` | 来自 console.anthropic.com → API Keys 的管理员 API key (`sk-ant-admin01-…`) |
此管理员 key 必须属于具有 **管理员** 角色的账户。可选设置(解析用户/workspace 名称、排除 workspace)可在供应商界面中进行配置。
### AWS
支持三种凭证模式,按以下顺序尝试:
| 模式 | 凭证字段 | 描述 |
|---|---|---|
| SSO profile | `sso_creds` | 执行 `aws sso login` 后 `~/.aws/config` 中的配置文件名称 |
| 静态 key | `access_key_id` + `secret_access_key` | 长期有效的 IAM 访问 key |
必须单独设置 `sso_creds`,或者同时设置 `access_key_id` **和** `secret_access_key` —— 当存在最少必填字段时,供应商界面会显示 **已设置**。
### Google Cloud
| 凭证字段 | 描述 |
|---|---|
| `service_account_json` | GCP 服务账号 key 文件的完整 JSON 内容 |
将下载的 `.json` key 文件的全部内容粘贴到 `service_account_json` 字段中。该服务账号需要以下角色(或等效的自定义权限):
- `roles/resourcemanager.projectViewer` — 用于枚举项目
- `roles/apikeys.viewer` — 用于列出 API key
- `roles/iam.serviceAccountViewer` — 用于列出服务账号 key
默认情况下,会自动发现所有可访问的项目。使用 **项目 (覆盖)** 可固定一组 project ID 列表,或使用 **排除项目** 跳过特定项目。
### Mistral
Mistral 使用交互式登录流程,而不是静态 API key。在供应商界面中按 **登录** 并输入您的 Mistral 电子邮件和密码 —— keyledger 会通过 Mistral 的 Kratos endpoint 进行身份验证并自动存储 session token。每次登录时都会刷新 session token。
## 用法
### 交互式 TUI
```
keyledger
```
启动全屏仪表板。所有状态(已启用的供应商、设置、快照)都会持久化到 `~/.keyledger/keyledger.db`。
### 键盘快捷键
| 按键 | 操作 |
|---|---|
| `1` | key 视图 |
| `2` | 健康视图 |
| `3` | 差异视图 |
| `4` | 快照视图 |
| `p` | 供应商管理 |
| `g` | 设置 |
| `r` | 刷新所有供应商 |
| `s` | 将快照保存到数据库(key / 健康视图) |
| `tab` | 切换侧边栏焦点 |
| `o` | 循环排序方式(key 视图) |
| `← →` | 在 key 和 WorkSpaces 标签页之间切换(key 视图) |
| `/` | 过滤 key(key 视图) |
| `?` | 切换帮助覆盖层 |
| `esc` | 返回 / 关闭对话框 |
| `q` | 退出 |
#### key 视图列
key 表格在状态列旁边包含一个专用的 **风险** 列(`ok` / `WARN` / `CRIT`),因此您无需打开健康视图即可一目了然地查看健康状况。当前处于激活状态的排序列会以紫色和下划线高亮显示。排序循环依次为:创建时间 → 最后使用 → 名称 → 风险。
#### key 视图过滤语法
| 表达式 | 匹配 |
|---|---|
| `foo` | ID、名称、作用域或状态中的子字符串 |
| `name:prod` | 名称包含 "prod" 的 key |
| `scope:staging` | 作用域包含 "staging" 的 key |
| `status:active` | 状态完全为 "active" 的 key |
| `risk:critical` | 风险评分为 "critical" 的 key |
| `age:>90` | 超过 90 天的 key |
| `idle:never` | 从未使用过的 key |
| `owner:alice` | 由匹配 "alice" 的用户创建的 key |
### 监控模式
```
keyledger watch [--interval ] [--output ] [--unseal-addr ]
keyledger --data-dir /mnt/data watch --interval 1h
```
持续运行:收集 key,保存到数据库,并在每次触发 (tick) 时导出一个 JSON 文件。遇到 `Ctrl+C` 或 `SIGTERM` 时会干净地停止。
```
keyledger watch --interval 1h --output /var/log/keyledger
```
每次运行都会打印一行摘要:
```
[2026-05-11 03:00:00] snapshot #12 — 47 keys (0 critical, 2 warnings) → /var/log/keyledger/snapshot-20260511T030000.json
```
`--interval` 标志接受任何 Go duration 字符串:`30m`、`1h`、`6h`、`24h` 等。默认为 `1h`。
`--output` 设置快照 JSON 文件的写入位置。数据库独立存在 —— 使用 `--data-dir`(或 `$KEYLEDGER_HOME`)将其指向其他位置;启动日志行 `watch: store: …` 始终会显示当前哪个数据库处于活动状态。
#### Unseal API (无头模式 / Docker)
在无头环境(例如,没有终端的 Linux 容器)中,`watch` 会自动启动一个本地 HTTPS API,以便在运行时提供凭证。
```
watch: credential store locked — POST password to https://127.0.0.1:9876/v1/unseal
watch: TLS cert fingerprint (SHA-256): AB:CD:EF:…
```
服务器使用临时的自签名 TLS 证书(ECDSA P-256,有效期 24 小时)。使用 `--unseal-addr` 更改绑定地址(默认为 `127.0.0.1:9876`)。
| Endpoint | 方法 | Body | 描述 |
|---|---|---|---|
| `/v1/status` | GET | — | `{"sealed":bool,"setup":bool}` |
| `/v1/providers` | GET | — | 列出已注册的供应商及其预期的字段名称 |
| `/v1/init` | POST | `{"password":"…"}` | 在首次运行时初始化加密,然后解封 |
| `/v1/unseal` | POST | `{"password":"…"}` | 解封已初始化的存储 |
| `/v1/credentials` | POST | `{"provider":"…","field":"…","value":"…"}` | 存储凭证并启用该供应商(需要处于解封状态) |
| `/v1/credentials` | DELETE | `{"provider":"…","field":"…"}` | 移除凭证(需要处于解封状态) |
在提交凭证之前,使用 `GET /v1/providers` 发现确切的字段名称:
```
curl -sk https://localhost:9876/v1/providers
# [
# {"provider":"anthropic","fields":["admin_key"]},
# {"provider":"aws","fields":["access_key_id","secret_access_key","sso_creds"]},
# {"provider":"google","fields":["service_account_json"]},
# {"provider":"openai","fields":["admin_key"]}
# ]
```
### Docker
每次发布时,都会将预构建的多架构镜像(linux/amd64、linux/arm64)发布到 GitHub Container Registry:
```
docker pull ghcr.io/riptideslabs/keyledger:latest
docker run -p 9876:9876 -v keyledger-data:/data ghcr.io/riptideslabs/keyledger:latest
```
或者从源码在本地构建:
```
docker build -t keyledger .
docker run -p 9876:9876 -v keyledger-data:/data keyledger
```
默认情况下,容器运行 `keyledger watch --unseal-addr 0.0.0.0:9876 --interval 5m`。使用 unseal API 提供凭证:
```
# 1. 检查加密是否已经初始化
curl -sk https://localhost:9876/v1/status
# {"sealed":true,"setup":false}
# 2a. 首次运行 —— 初始化加密并一步解封
curl -sk -X POST https://localhost:9876/v1/init \
-H 'Content-Type: application/json' \
-d '{"password":"my-secret"}'
# {"sealed":false}
# 2b. 后续重启 —— 存储已初始化,只需解封
curl -sk -X POST https://localhost:9876/v1/unseal \
-H 'Content-Type: application/json' \
-d '{"password":"my-secret"}'
# 3. 推送 provider 凭据
curl -sk -X POST https://localhost:9876/v1/credentials \
-H 'Content-Type: application/json' \
-d '{"provider":"openai","field":"admin_key","value":"sk-..."}'
curl -sk -X POST https://localhost:9876/v1/credentials \
-H 'Content-Type: application/json' \
-d '{"provider":"anthropic","field":"admin_key","value":"sk-ant-..."}'
# 移除凭据
curl -sk -X DELETE https://localhost:9876/v1/credentials \
-H 'Content-Type: application/json' \
-d '{"provider":"openai","field":"admin_key"}'
```
## 开发
```
make help # list all targets
make build # build for current platform
make build-all # cross-compile for all platforms
make run # build and launch the TUI
make test # run tests with coverage
make lint # run golangci-lint (downloads on first run)
make lint-fix # run golangci-lint with auto-fix
make check # fmt + vet + lint
make clean # remove build artifacts
```
## 许可证
MIT — 见 [LICENSE](LICENSE)。版权所有 © 2026 Riptides Labs, Inc.
标签:EVTX分析, 日志审计, 请求拦截