ariodb 发布:在 AI 智能体与数据库之间加一层安全代理
Ariodb – a proxy that checks and can undo what AI agents do to your DB
ariodb 是一个位于 AI 智能体与数据库之间的安全代理,智能体可像连接 Postgres、MySQL、MariaDB 或 ClickHouse 一样接入,也可作为 MCP 工具使用。
ariodb 是 AI 代理与你的数据库之间的安全代理。代理可以像连接 Postgres、MySQL、MariaDB 或 ClickHouse 一样连接到它,也可以将其用作 MCP 工具。ariodb 会在每条语句执行前进行检查,强制读取操作只读,在提交前测量每次写入实际更改了什么,将高风险语句保留给人工或模型审批,记录代理更改的每一行,并允许你稍后撤销某个代理的会话而不影响其他人的工作。它是一个带有内置仪表板的单一 Rust 二进制文件,并在 Sustainable Use License 下提供源代码。
为什么
给代理一个数据库登录账号,就等于赋予它该登录账号能做的一切,以机器速度运行,且没有人逐条阅读语句。实践中会出现三类问题:
- 错误。代理误读任务,在没有使用它本意的
WHERE的情况下运行了UPDATE orders SET status = 'void'。对数据库来说,这条语句看起来没有任何异常。 - 操纵。代理读取了它不应信任的文本(支持工单、网页、数据库自身中的某一行),而该文本指示它导出或删除一张表。这就是提示注入:被攻击的正是代理自身的判断力,因此它无法成为防御手段。
- 失控写入。一个本应触及十行的循环触及了一万行,或者触发器或级联悄然更改了代理从未提及的表。
数据库授权有帮助,但粒度太粗:一个可以更新 orders 的角色就可以更新它的每一行。ariodb 增加了授权无法表达的检查(按代理的表清单、语句类型、事后测量的行数限制、对特定语句的审批),以及当某些操作仍然漏过时的回退方式。
它做什么
- 说你的数据库的协议。Postgres 14 到 18 以及兼容 Postgres 的数据库(TimescaleDB、Supabase、YugabyteDB、CockroachDB),MySQL 8.4 和 MariaDB 11.4,以及通过 HTTP 和原生协议的 ClickHouse。代理使用
psql、mysql、clickhouse-client或任何驱动程序,代理与 ariodb 之间以及 ariodb 与数据库之间使用 TLS(ClickHouse 的原生端口除外)。 - 读取 SQL,而不仅仅是其文本。Postgres 语句使用 Postgres 自己的解析器进行解析,包括隐藏在
EXPLAIN ANALYZE、PREPARE、COPY (...)和数据修改型WITH中的内容。MySQL 和 MariaDB 语句经过一个 SQL 解析器,并由遵循服务器自身规则的词法分析器交叉检查,ClickHouse 语句则经过一个谨慎的分词器。ariodb 无法看清内部的任何内容都会被拒绝。 - 强制读取为只读。每次读取都在一个
READ ONLY事务中运行(在 ClickHouse 上,设置readonly),因此隐藏写入的读取会被数据库本身拒绝。 - 在提交前检查写入。每次写入都在一个事务中运行,并在提交前进行测量,因此由触发器、级联和函数更改的行也会被计入。行数过多,或者代理不得更改的表,写入会在代理看到结果之前回滚。
- 具有内置策略。默认拒绝,按代理:每个代理只能接触为其列出的表,只读或读写。破坏性语句、模式更改、事务控制、大多数会话设置以及会绕过 ariodb 检查的函数都会被拒绝。
- 以 CEL 接受规则。在策略之上,规则可以拒绝某条语句或将其保留以待审批,可以在其运行之前,或在写入已运行但尚未提交之前。规则可在 ariodb 运行时重新加载,
ariodb test会在 CI 中检查它们。 - 请求批准。被拦截的语句会等待人员(在仪表板、CLI、Slack、Discord、Telegram、Microsoft Teams、Google Chat、Mattermost、PagerDuty、Opsgenie、电子邮件或任何 webhook 中)、等待模型根据书面策略(Anthropic、OpenAI、Gemini、Azure OpenAI 或任何兼容 OpenAI 的服务)对其进行判断,或等待插件。
- 撤销一个会话。一份记录前后镜像的日志,按 agent 会话打标签,让你在一个事务中反转某个会话的更改。自那以后被其他人更改的行会被报告为冲突,绝不会被静默覆盖。
- 保留决策日志。每条语句、裁决、规则、行数、延迟和批准人,均以哈希链连接,支持保留策略、可选的字面值脱敏,并可导出为测试夹具。
- 带有仪表板。批准、决策、会话与撤销、规则、配置、密钥、用户和插件,均内置于二进制文件中。支持任何 OpenID Connect 提供商的单点登录,并根据提供商的组分配查看者、批准者和管理员角色。
- 先检查你的数据库。
ariodb doctor报告你的数据库支持什么(只读读取、受检写入、撤销),而不做任何更改。 - 可作为 MCP 服务器运行。
ariodb mcp为 agent 提供一个用于 Postgres 的query工具,该工具经过相同的检查。 - 支持插件。任何通过 stdin 和 stdout 使用 JSON-RPC 通信的程序都可以批准语句、为规则提供事实、接收通知或接收决策日志。提供 Python 和 TypeScript 示例。
- 让凭据远离 agent。Agent 使用自己的令牌登录;数据库密码存放在环境变量或加密的密钥存储中,每个 agent 都可以作为自己的数据库角色运行。总连接数和每个 agent 的连接数限制,以及握手超时,可约束缓慢或贪婪的客户端。
工作原理
flowchart LR
A["AI agent<br/>(driver, CLI or MCP)"] -->|"agent name + token"| C["Classify the statement"]
C --> P{"Built-in policy<br/>and rules"}
P -->|refused| E["Error to the agent"]
P -->|approve| AP{"People, models<br/>or plugins"}
AP -->|denied or timed out| E
AP -->|allowed| X
P -->|allowed| X{"Read or write?"}
X -->|read| RO["READ ONLY transaction"]
X -->|write| W["Run, then measure<br/>before commit"]
W -->|"over the limit or<br/>after-stage rule says no"| RB["Rollback"]
W -->|ok| CM["Commit"]
RO --> DB[("Database")]
CM --> DB
DB -->|"replication stream<br/>or binlog"| J["Journal, by session"]
J --> U["Undo one session"]
E & RB & CM & RO --> L["Decisions log"]
L --> D["Dashboard"]
U --> D
加载中
概述逐步介绍了每个步骤。ClickHouse 没有事务,因此其写入在执行前会被判断,且无法回滚或撤销;在 MySQL 和 MariaDB 上,写入检查比 Postgres 上更弱(参见兼容性)。
快速开始
该演示需要 Docker、Rust(通过 rustup)、带有 libclang 的 C 编译器,以及 psql。从本仓库的克隆开始:
./scripts/demo.sh
它会构建 ariodb,在 Docker 中启动带有示例表(customers、orders、secrets)的 Postgres 16,将配置写入 .ariodb-demo/,运行 ariodb setup 和 ariodb serve,并发送一些好的和坏的 agent 语句,以便有内容可看。然后以 agent 身份连接:
psql "postgres://coding-agent:demo-agent-token@127.0.0.1:6543/app?sslmode=disable"并打开仪表板 http://127.0.0.1:8080(用户 root,密码 demo-dashboard-password)。试试:
DELETE FROM orders:被拒绝,因为它没有WHERE。UPDATE orders SET status = 'void' WHERE id < 600:会运行,测得有数百行,并因演示的限制为 200 而被回滚。SELECT name, email FROM customers:会等待,直到你在仪表板的 Approvals 页面上批准它。
Ctrl-C 会停止一切并移除容器。演示中的每个密码都是用完即弃的测试值。
对于真实设置(数据库角色、配置文件、密钥、ariodb doctor、ariodb setup,然后是一次拒绝、一次回滚、一次批准和一次撤销),请遵循快速入门。要将 ariodb 作为服务运行,请参见安装。
配置
一个 TOML 文件,默认为 ariodb.toml。下面这个为一个 agent 保护一个 Postgres 数据库,将大型写入保留给人员处理,并让所有凭据都不出现在文件中:
[database] url = "postgres://ariodb_gw@db.internal.example:5432/app" # the password comes from ARIODB_DATABASE_URL tls = "verify" [limits] max_rows_per_write = 200 # a write that changes more is rolled back statement_timeout_ms = 5000 [proxy] listen = "127.0.0.1:6543" # where agents connect [journal] dir = "/var/lib/ariodb" # state: journal, decisions log, secrets [[agents]] name = "coding-agent" # the user name the agent logs in with access = "read_write" tables = ["orders", "customers"] token_env = "ARIODB_TOKEN_CODING_AGENT" [[rules]] name = "big-writes-need-a-person" stage = "after" # judged on what the write did, before commit condition = "effects.rows > 50" verdict = "approve" approve = ["ops"] reason = "writes over 50 rows need a person to agree" [[rules]] name = "no-file-functions" condition = "sql.functions.exists(f, f.matches('(^|[.])pg_(read_file|read_binary_file|ls_dir|stat_file)$'))" verdict = "deny" reason = "functions that read server files are off-limits" [[approvers]] name = "ops" type = "dashboard" # decide in the dashboard or with `ariodb approve` [dashboard] listen = "127.0.0.1:8080" public_url = "https://ariodb.internal.example"
然后,在环境中设置凭据:
export ARIODB_DATABASE_URL='postgres://ariodb_gw:not-a-real-password@db.internal.example:5432/app' export ARIODB_JOURNAL_URL='postgres://ariodb_journal:not-a-real-password@db.internal.example:5432/app' export ARIODB_TOKEN_CODING_AGENT="$(openssl rand -hex 32)" ariodb check # validate the file and show what it allows ariodb doctor # what this database supports; changes nothing ariodb setup # once: replica identity, publication, replication slot ariodb dashboard-password # set the first dashboard password, read from stdin ariodb serve # the proxy, journal and dashboard
代理连接到 postgres://coding-agent:<token>@127.0.0.1:6543/app,
或者使用其令牌在
ARIODB_AGENT_TOKEN 中运行 ariodb mcp --agent coding-agent。每个部分和键都在
配置参考中;仓库的
ariodb.toml 是一个更长的示例。
文档
| 页面 | 涵盖内容 |
|---|---|
| 文档索引 | 面向新用户、运维人员和贡献者的阅读顺序 |
| 概述 | 问题所在、语句如何流经 ariodb、关键概念、它不做什么 |
| 快速开始 | 演示,然后在 Docker 中针对 Postgres 的完整设置 |
| 安装 | 要求、构建、systemd、容器和升级 |
| 配置 | ariodb.toml 的每个部分、环境变量和密钥存储 |
| CLI | 每个 ariodb 命令、其选项及其输出 |
| Postgres | 角色和授权、TLS、线路代理、写入检查和日志 |
| MySQL 和 MariaDB | 登录和授权、binlog 设置、如何统计写入、撤销及其限制 |
| ClickHouse | HTTP 和原生协议代理、插入及其限制 |
| 兼容性 | 经过测试的数据库、托管服务和 write_check = "reported" |
| 策略 | 内置的默认拒绝策略 |
| 规则 | CEL 规则、其事实、阶段及其组合方式,附有示例手册 |
| 测试策略 | ariodb classify、explain 和 test,以及 CI 中的测试夹具 |
| 审批 | 人员、聊天和寻呼渠道、电子邮件、webhook、模型和插件 |
| 插件 | 插件协议以及 Python 和 TypeScript 示例 |
| 撤销 | 会话、撤销计划、冲突以及无法逆转的内容 |
| 仪表板 | 页面、用户和角色、单点登录和反向代理 |
| MCP | 将 ariodb 作为 MCP 工具提供给代理 |
| 运维 | 部署形态、日志、备份、保留、凭据轮换 |
| 故障排除 | 症状、原因和修复方法 |
| 安全模型 | 威胁、保证、已接受的风险、安全审查和加固检查清单 |
| 架构 | 模块图、请求生命周期和测试 |
状态和兼容性
ariodb 的版本为 0.1.0,这是其首个公开发布版本。它的端到端 测试套件使用真实客户端驱动 Docker 中的真实数据库,但它还很年轻: 配置格式和插件协议在 1.0 之前可能会发生变化, 变更日志会在发生变化时说明。
| 数据库 | 读取强制为只读 | 提交前检查写入 | 撤销 |
|---|---|---|---|
| PostgreSQL 14 至 18、TimescaleDB、Supabase | 是 | 是 | 是 |
| YugabyteDB、CockroachDB | 是 | 使用 write_check = "reported" |
否 |
| MySQL 8.4、MariaDB 11.4 | 是 | 是,较弱的检查 | 是 |
| ClickHouse | 是 | 运行前判定;无回滚 | 否 |
托管 Postgres 服务(RDS、Aurora、Cloud SQL、AlloyDB、Azure、Neon
等)预计可以工作;兼容性
中有详细信息和撤销所需的设置。针对
你自己的数据库运行 ariodb doctor 以确保无误。ariodb 可在 Linux 和 macOS 上运行。
安全
ariodb 的职责是站在不受信任的代理和你的数据之间,因此其 自身的安全性很重要。安全模型阐明了 它防御什么、保证什么、故意不做什么 (数据库角色的授权仍然是真正的边界)、其安全审查的发现, 以及生产环境的加固检查清单。
请按照 SECURITY.md 中所述私下报告漏洞, 而不要在公开 issue 中报告。
贡献
欢迎提交错误报告、修复和文档改进。 CONTRIBUTING.md 说明了如何构建 ariodb、运行每个 测试套件,以及如何发送拉取请求,包括每次提交所需的开发者原创性证明 签署。所有参与者都应遵守 行为准则。
许可证
ariodb 根据 可持续使用许可证 1.0 版 提供源码,许可人为 Rooz Jalali。用通俗的话说(以许可证文本为准,这 不构成法律建议):
- 你可以 将 ariodb 用于你自己组织的 内部业务目的,并对其进行修改:例如,用于你公司自己的 数据库、你自己的代理,在生产环境中。
- 你可以 将其用于个人或非商业目的,并分享它, 无论是否修改,只要用于非商业目的即可免费分享,前提是 许可证随附,且修改后的副本注明已修改。
- 你不得 出售 ariodb、对其分发收费,或将其作为托管或管理服务,或作为你销售的产品的 一部分提供给他人。
- 你不得 移除或掩盖其许可证、版权或其他 声明。
如果你想以许可证不允许的方式使用 ariodb,请询问 维护者。依赖项保留其各自的许可证。
来源:Hacker News · github.com