跳到正文
Hacker News· roozbehjalali·· 8 天前AI 评分71

ariodb 发布:在 AI 智能体与数据库之间加一层安全代理

Ariodb – a proxy that checks and can undo what AI agents do to your DB

AI 导读

ariodb 是一个位于 AI 智能体与数据库之间的安全代理,智能体可像连接 Postgres、MySQL、MariaDB 或 ClickHouse 一样接入,也可作为 MCP 工具使用。

正文 · AI 翻译

CI

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