Files
dsh_ai1net_server/交付物/建库权限-D档被证伪与修正判定-20260923.md
admin ce8e6ceed9 chore(工作区): 纳入版本控制基线(回收 411 MB 过程产物)
回收 411 MB(470 M → 58.8 M),全部经回收站,可恢复:
- 待清理/(146.2 M,含 relay 分片 128 M 与 42 项过程目录)
- tmp/(32.4 M,按接续棒命名的过程临时区)
- .workbuddy/tmp/(39.5 M)
- 4 份 workbuddy.db 冗余副本(101 M,09-23 事故的坏副本 / 抢救产物)
- tmp/im16/gw/centrifugo 二进制(63.9 M,可重下)+ 缓存残留

入库范围:常驻规则(CODEBUDDY.md / README.md / state.py)、在途接续入口与
接续包、docs/、交付物/、交接单/、归档/、scripts/、.codebuddy/、
.workbuddy/memory/;共 398 件,其中 >60 KB 的 26 件全为文档。

排除(.gitignore):tmp/、待清理/、运行态日志与缓存、*.db 与 DB 备份整目录、
打包二进制(*.tar.gz / *.tgz)、记忆修复前备份。
2026-09-24 07:51:03 +08:00

7.8 KiB
Raw Permalink Blame History

建库权限 · D 档被证伪后的修正判定(2026-09-23)

一句话结论:2026-09-22 拍板的 D 档(SECURITY DEFINER 函数建库)在 PostgreSQL 上不可实现 —— 这是 PG 内核硬限制,不是实现姿势问题。已回滚,服务器零残留。修正后可行路径为 B 档 / C 档二选一,等你拍板。 🔴 2026-09-23 05:4x 更新:用户已拍板「B」 ⇒ 落地件另见 交付物/插件建库权限-B档落地-20260923.md(已在 47 落地 + 11 条验收通过)。本文以下保留为判定过程与证据记录。 机位:仅 47(PG 只在 Manager 上;106 无 PG)。 本轮对生产的净影响:零(建了又按回滚流程清掉;dshs 权限、内核 13 表、服务状态全部原样)。


一 D 档为什么不可实现(实测证据,非推断)

PG 对 CREATE DATABASE 有两层独立禁止,任一层单独就足以否决:

层 报错原文 触发条件
事务层 CREATE DATABASE cannot run inside a transaction block 任何事务内 —— PL/pgSQL 函数体恒在事务内
函数层 CREATE DATABASE cannot be executed from a function PG 显式禁止从函数发起(即使 SECURITY DEFINER)

实测对照(同一私有 schema、同一 SECURITY DEFINER 姿势,只换语句):

函数内 CREATE SCHEMA   → schema_ok        ✅ 成功
函数内 CREATE ROLE     → role_ok          ✅ 成功
函数内 CREATE DATABASE → ERROR: CREATE DATABASE cannot be executed from a function   ❌ 内核拒绝

⇒ SECURITY DEFINER 这条封装路径对 CREATE DATABASE 无效。当初选 D 档的动机("让平台能建库,但不把 CREATEDB 给 dshs")在这条路上无法同时满足。

一并探明的旁路(避免重复试)

旁路 结论 证据
dblink 扩展 ❌ 不可用 pg_available_extensions 无该条目;select dblink_connect(...) ⇒ function does not exist
postgres_fdw 扩展 ❌ 不可用 同上,未安装且不可安装
已装扩展 仅 plpgsql select extname from pg_extension ⇒ plpgsql(单条)
su postgres 到平台进程 ❌ 不存在该用户 su: user dshs does not exist —— dshs 是 systemd 服务名,不是系统用户

二 修正后可行路径(两条,各有优有劣 ⇒ 交你拍板)

候选 B · 角色级授权(给 dshs 加 CREATEDB)

做法:ALTER ROLE dshs CREATEDB,平台侧用现有 dshs 连接直接执行 CREATE DATABASE dshs_pl_<id>。

优点

  • 实现最直:平台代码里零新增凭据、零新增连接路径,一条 Pool.query 即可。
  • 与现有部署形态完全同构(DSHS_DB_URL 不变)⇒ 换机器重建时无额外步骤。
  • 权限面收在 PG 内,pg_roles / 审计里可查可审计。

缺点

  • dshs 拿到全局 CREATEDB ⇒ PG 没有"只允许建 dshs_pl_* 前缀库"的原生机制,白名单只能靠平台代码自觉。
  • 一旦平台代码被注入,攻击面从"当前库"扩到"可建库"(虽然仍不能 DROP 别人的库)。
  • 这正是 09-22 否掉 A 档的同一条理由,换个档位名原样复现。

候选 C · 平台侧超管直连建库

做法:平台侧持一份超管凭据(只落 systemd drop-in,600),建库时单开一条连接、单语句执行、用完即断。

优点

  • dshs 角色权限完全不扩大(保持 f|f|f)—— 保住 09-22 的原始意图。
  • 建库动作天然单点:只有这一处代码能建库,grep 可穷举,审计点唯一。
  • PG 侧不受"函数/事务"限制(已实测单语句 -c 建删成功)。

缺点

  • 超管凭据进入应用进程环境 ⇒ 凭据面从"运维手上"扩到"平台进程内存里"。
  • 平台进程以 root 运行 ⇒ 凭据泄露的最坏后果是同机提取,风险等级高于 B。
  • 换机器重建时多一条必须同步的凭据项(漏了就建不了库)。

三 实测读数总表(2026-09-23 · 全部现场取证)

项 读数 含义
PG 版本 PostgreSQL 13.23 与既有认知一致
已装扩展 plpgsql 无 dblink / postgres_fdw
dshs 权限 rolsuper=f rolcreatedb=f rolcreaterole=f 无间接提权
dshs 在 dshs 库 has_database_privilege('dshs','dshs','CREATE') = t 建 schema 零扩权
平台进程用户 systemctl show dshs -p User ⇒ 空 以 root 运行
pg_hba local all all peer + host … 127.0.0.1/32 scram-sha-256 超管走 socket peer;平台走 TCP 口令
超管通路 su postgres -c 'cd /tmp && psql -h /var/run/postgresql -p 15432 -d dshs …' ✅ 可用(⚠️ 必须先 cd /tmp)
dshs_pl_% 库数 0 尚无业务插件库
内核表数 13 与 §2-2 既有认知一致,未被本轮触碰
lib/ 内建库代码 0 处 CREATE DATABASE 建库面确实从零起
服务状态 dshs = active 全程未重启

四 本轮实际执行与回滚(完整可复现)

1 抢全局锁            → ✓ 已持(插件投放与分库线-执行棒②)
2 落地 D 档 DDL       → DDL_RC=0(schema dshs_int + 函数 create_plugin_database 创建成功)
3 跑 7 条验收         → ①create/②幂等 报 ERROR(事务块)⇒ 判定不可实现
4 旁路探测            → dblink / postgres_fdw / create role / create schema 逐个取证
5 回滚                → REVOKE → DROP FUNCTION → DROP SCHEMA
6 回滚后核查          → dshs_int 残留 0 · 函数残留 0 · dshs 权限 false|false|false
                        内核表 13 · 服务 active · 探测残留(probe%)全 0

净影响 = 零。 服务器状态与本轮开工前逐项一致。


五 待你拍板(一项)

✅ 2026-09-23 05:4x 已拍板 = 「B」。以下候选原文保留作记录;落地件 ⇒ 交付物/插件建库权限-B档落地-20260923.md。

建库通路选 B 还是 C —— 两者各有优有劣、客观标准分不出高下,故不替你拍:

候选 B · 角色级授权(给 dshs 加 CREATEDB)

  • 优点:实现最直、零新增凭据、与现有部署同构、权限面可在 PG 内审计。
  • 缺点:dshs 拿到全局 CREATEDB,白名单只能靠代码自觉;这正是 09-22 否掉 A 档的同一条理由。

候选 C · 平台侧超管直连建库

  • 优点:dshs 权限完全不扩大(保住 09-22 原始意图)、建库动作单点可穷举、PG 侧无函数/事务限制。
  • 缺点:超管凭据进入以 root 运行的应用进程 ⇒ 凭据面扩大,最坏后果同机提取。

我的倾向:C —— 它保住了 09-22 拍 D 档时想守的那条线(角色权限不扩大),而凭据面的代价可以通过"只落 600 drop-in + 单点调用 + 全量审计"压到与 B 同级;B 则是把当初明确否掉的形态原样装回来。此倾向可推翻。


六 拍板后要落的文档(⛔ 本轮未动,等拍板)

  1. DEPLOY-本部署.md DB 初始化步骤 —— 按选定档位写建库通路。
  2. 交接单/插件投放与分库线-①…md §五 S4-2 + §十-D1 —— 建库 = admin 显式按钮(原文写"上传钩子建库",须改)。
  3. DB-03-插件数据面规范.md §三 / §四 / §六 —— 谁建库 / 何时建 / 台账表 plugin_datastores。
  4. 平台侧错误码映射同步改:D 档的 PLUGIN_DB_HELPER_MISSING 随档位作废。

七 未做(具名原因)

项 原因
B / C 档的实际落地 依赖你拍板(§五)⇒ ⛔ 不自选
上述 §六 四份文档回改 内容随档位而变 ⇒ 拍板前落笔必返工
drop_plugin_database(彻底卸载用) ⛔ 不在拍板范围(DB-03 §六-4 将来一并走)