DEBUG.WIKI
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
雨云;给项目一台云服务器
RackNerd;$21.99/年 · 1GB KVM

pg_dump 报 row-level security policy:检查完整导出权限

pg_dump 在 COPY 阶段遭遇 RLS 报错,核对实际角色、表所有者和强制策略。区分完整备份、按可见行导出与排除管理对象的迁移范围。

pg_dump -Fc 导出到一半,在某张表的 COPY ... TO stdout 处停止:

ERROR: query would be affected by row-level security policy for table "job"

先核对报错中的完整表名和实际导出角色。如果日志指向 cron.job,尤其是在托管 PostgreSQL 上,不要因为账户名叫 postgres,就认定它能绕过这张表的行级安全策略。

pg_dump 默认拒绝受策略过滤的导出

表的普通 SELECT 权限与行级安全策略是两层控制。一个角色能查询表,仍可能只看到策略允许的部分行。

pg_dump 默认在导出会话中设置 row_security = off,目的是避免悄悄得到不完整的备份。这里的 off 不会关闭表上的 RLS:当查询可能受到策略过滤时,它让查询报错。手动再执行一次 SET row_security = off,并不能获得原来没有的绕过权限。

这也解释了为何相同的命令在本地正常、在托管实例上失败。两边的角色属性、表所有者和 RLS 配置可能不同;它不自动证明归档格式或客户端损坏。

核对实际身份和失败表

在与导出任务相同的连接目标和角色下执行以下只读检查。cron.job 是报错场景示例,其他表需换成日志中的实际名称:

SELECT current_database(), session_user, current_user;

SELECT rolname, rolsuper, rolbypassrls
FROM pg_roles
WHERE rolname = current_user;

SELECT c.oid::regclass AS table_name,
       pg_get_userbyid(c.relowner) AS owner,
       c.relrowsecurity, c.relforcerowsecurity
FROM pg_class AS c
WHERE c.oid = 'cron.job'::regclass;

超级用户和具有 BYPASSRLS 属性的角色可以绕过 RLS;表所有者通常也可绕过,但 FORCE ROW LEVEL SECURITY 会改变所有者的适用情况。pg_read_all_data 一类读取权限不等于 BYPASSRLS,不能仅凭“已授予全表读取”排除这一层。

托管平台可能限制管理角色的实际能力,扩展表还可能有平台专用规则。查询结果和平台允许的操作才是判断依据,不应给所有托管平台套同一条授权命令。

需要完整备份,使用获准的完整读取路径

业务库的完整逻辑备份,应由管理员确认导出角色能读取计划包含的全部数据,并具有所需的 schema、表和其他对象权限。若涉及绕过 RLS,按既有备份职责使用受控维护角色;不要为此长期放宽应用账号,也不要临时关闭业务表的 RLS。

确认角色与目标后,导出命令可以类似下面这样。所有连接值和文件名均为示例,认证沿用现有受控方式:

pg_dump -h db.example.internal -p 5432 -U backup_user \
  -d app_db -Fc -f app_db.dump

使用新文件记录这一轮,检查退出状态,失败产物不能作为可用备份。若托管管理对象无法通过该角色完整导出,需要按平台支持的备份或迁移方式处理,并单独记录对象与数据的迁移范围。

两个能绕开报错的选项,会改变导出范围

--enable-row-security 允许按当前策略导出可见行。它适合有意导出某个权限视角的数据,不应作为完整备份的修复。还需考虑恢复形式:向启用 RLS 的表执行 COPY FROM 有限制,不能只在导出侧加一个选项就认定整个恢复过程可用。

排除报错表或 schema 也会遗漏相应内容。只需要迁移业务数据、明确不迁移 pg_cron 管理数据时,可以评估排除范围;但任务定义、调度和后续重建必须另有安排。不能把“排除后命令成功”写成原数据库已完整备份。

最终应对照预定备份清单,在隔离目标检查对象、数据、角色权限和应用需要的扩展或任务。导出不再报 RLS 错误只解决了读取路径的问题;是否覆盖应迁移的数据,还要由清单与恢复结果确认。