让编程智能体建库,同时隔离数据库密码
作者介绍开源工具 agentic-hosting,让 AI 智能体在 Linux 服务器上自行部署应用和数据库。文章展示通过 API 创建 Postgres 或 Redis、连接应用并清理资源的流程,重点是避免密码进入聊天记录。
AI 深度解读
让 AI Agent 自动建库并不难,难的是别让数据库密码顺手进入聊天记录、命令输出和各种配置副本。agentic-hosting 给出的办法,是把建库、凭据存储、环境变量注入和容器联网收进一套 API,让 Agent 操作资源,减少人工传递密码。
这套方案值得看的,是它把自动化的边界交代得比较清楚:密码加密不等于业务数据加密,私有网络不等于加密通信,数据库创建成功也不代表备份已经安排好了。
一次建库请求,为什么还要处理重试
agentic-hosting 是作者开发的开源工具,服务端程序 ah 运行在 Linux 服务器上。Agent 或团队各自作为一个租户,持有独立 API key;部署的应用叫 service。
下面的请求解决建库问题,AH_URL 是服务器地址,AH_KEY 是租户密钥:
IDEM=$(uuidgen) # 重试时复用这个值
curl -s -X POST "$AH_URL/v1/databases" \
-H "Authorization: Bearer $AH_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $IDEM" \
-d '{"name":"notes-db","type":"postgres"}'
要盯住的是 Idempotency-Key:重试必须复用同一个值,不能每次重新执行 uuidgen。
ah 会拉取 postgres:16-alpine 或 redis:7-alpine,启动容器,再通过数据库自身协议检查就绪状态。只看端口打开,无法确认数据库已经能接受请求。
作者给出的耗时是:镜像已在本机时约 30 秒;首次拉取可能更慢,所以接口最多等待 6 分钟。连接中途断开后,相同幂等键会让后续请求等待第一次操作完成并领取结果,避免多建一个数据库。成功结果保留 10 分钟。
创建成功返回 201,包含 status: ready、主机、端口和连接字符串。数据库名称须以字母开头,只能包含字母、数字、连字符和下划线,最长 63 字符。Postgres 的数据库名和用户名都固定为 ah;密码由 32 个随机字节生成,表示为 64 个十六进制字符。
这些约束减少了 Agent 需要决策的参数,也降低了自动化流程的分支数量。
密码没有打印出来,不代表从未暴露
ah 在保存前,用服务器主密钥通过 AES-256-GCM 加密密码和完整连接字符串,控制数据库里只保存密文。
明文仍有两个出口:创建响应,以及专门的 GET /v1/databases/{id}/connection-string。后者每次调用都会记录租户、数据库和请求所用 API key 的 ID。普通列表接口 GET /v1/databases 和详情接口 GET /v1/databases/{id} 不返回连接字符串。
所以,标题里的密码锁起来,要理解为控制明文流转,而非 Agent 永远接触不到密码。如果工具把创建响应完整回传给模型或写入日志,密码仍可能进入上下文。原文没有说明这些外围工具如何统一脱敏。
把连接字符串交给应用,可以通过 shell 变量和管道完成:
CONN=$(curl -s -H "Authorization: Bearer $AH_KEY" \
"$AH_URL/v1/databases/$DB_ID/connection-string" \
| jq -r .connection_string)
jq -n --arg u "$CONN" '{DATABASE_URL: $u}' \
| curl -s -X POST "$AH_URL/v1/services/$SVC_ID/env" \
-H "Authorization: Bearer $AH_KEY" \
-H "Content-Type: application/json" -d @-
curl -s -X POST \
"$AH_URL/v1/services/$SVC_ID/restart" \
-H "Authorization: Bearer $AH_KEY"
这里要注意最后的 /restart:设置环境变量只会合并新键,重建容器后才会生效。前面获取连接字符串,后面两次调用分别负责写入配置和重启应用。
环境变量同样加密保存,更新响应只包含状态,不回显值;读取时默认显示 ********,只有带 ?reveal=true 才返回明文,并留下审计记录。Redis 使用同样流程,变量名约定为 REDIS_URL,连接格式为 redis://:<password>@ah-db-<id>:6379/0。
这套方案减少了密码被展示的机会,但没有消除运行时使用明文凭据的需要。
此外,目前整台服务器共用一个主密钥,直接加密环境变量、数据库密码和连接字符串。按用途派生不同密钥的方案尚未实现,租户隔离依靠 API 查询范围,而非独立加密密钥。
加密覆盖的也只是 ah 保存的凭据。Postgres 业务数据位于普通 Docker volume;应用到数据库使用私有网络上的明文 TCP,连接配置为 sslmode=disable。
应用能连上数据库,靠的是重启时补齐网络
早期版本返回 127.0.0.1:<port>。应用运行在独立容器里,这个地址指向应用容器自身,自然找不到数据库。作者说,问题记录为 issue #164,并在 10 月修复,原文未注明年份。
现在每个数据库有独立的私有 Docker 网络 ah-dbnet-<tenant>-<db>,没有通往互联网的路由。数据库通过 ah-db-<id> 解析,Postgres 和 Redis 分别使用标准端口 5432、6379。
service 部署、启动或重启时,ah 会检查其环境变量。发现变量引用当前租户的数据库,才把应用接入对应网络。因此,复制其他租户的连接字符串,不会让应用自动加入对方网络;这个主机名也只在接入网络的服务容器内有效,在宿主机上直接运行 psql 无法解析。
升级时,ah 会在启动阶段改写数据库记录和 service 环境变量中的旧地址,运行中的应用仍需重启。作者称修复已有测试,但真实 gVisor 主机上的检查仍列为待办,不能据此判断所有运行环境都验证过。
CLI 将整套流程收成 ahc db provision notes-api postgres:默认创建 notes-api-postgres,可用 --name 改名,随后等待就绪、设置变量并重启,只输出主机名。Claude Code 的 /ah-db 命令也执行这些步骤,并被要求不要打印完整连接字符串。
能力边界同样明确:超配额返回 409;磁盘使用率达到 90% 时,创建返回 503 和 Retry-After,让 Agent 等待。它不支持 MySQL、自定义镜像、副本或故障转移。
我的判断
我认可它把凭据读取单独做成接口、默认隐藏环境变量,以及为重试设计幂等机制。这些都能减少 AI 编程中常见的操作失误。不过,原文没有密码泄漏率、稳定性或运维成本的对照数据,效果仍属于作者的实现说明和使用经验。
比起手工复制 .env,它的流程更容易约束;比起托管数据库,它把更多责任留给了服务器维护者。
其中最容易被忽略的是备份。ah 自带备份只覆盖控制面状态,不包含应用数据。作者交给 Agent 的任务是:每晚在容器内运行 pg_dump,用 gzip 压缩,复制到备份主机并保留 7 天;每周恢复昨晚备份到临时数据库,检查可恢复性;备份缺失或为空时告警。这是任务描述,原文没有展示脚本和长期执行结果。
删除流程也需要谨慎理解。作者要求先删除应用的 DATABASE_URL 并重启,再调用 DELETE /v1/databases/{id},成功返回 204;CLI 则是必须带 --confirm 的 ahc db delete notes-db --confirm。ah 会停止并移除容器,将卷内文件覆写为零,再删除卷、记录和网络。后台清理器还会清理无记录归属的 ah-db-* 卷,以及创建满 15 分钟仍无归属的数据库网络。
但文件覆零不能直接证明底层存储上的数据都不可恢复。原文没有交代快照、存储介质等条件,也没有给出恢复验证。
自动化接管了操作步骤,备份有效性和安全边界仍需要人验收。
能拿来做什么
- 给自托管 Node 应用接入 Postgres 或 Redis 时,可以参考它将建库、等待就绪、注入变量和重启串成固定流程,尤其要保留幂等键,防止超时重试重复创建资源。
- 让 AI 编程工具处理凭据时,应检查工具响应和日志是否包含创建结果或连接字符串;管道没有主动打印密码,并不能保证外层工具也不记录它。
- 把数据库备份交给 Agent 时,可以直接采用原文的验收要求:每日导出、异机保存、保留 7 天、每周恢复验证,并对缺失或空文件告警。最终要检查的是恢复结果。
- 清理临时应用时,先解除数据库引用并重启,再删除数据库;若业务依赖自动故障转移或内置备份,应先评估这套单机方案是否满足要求。