Chris van Eijk:ALTER DEFAULT PRIVILEGES 不生效?我们的实测结果

Chris van Eijk:ALTER DEFAULT PRIVILEGES 不生效?我们的实测结果

💡 原文英文,约2500词,阅读约需9分钟。
📝

内容提要

PostgreSQL 的 ALTER DEFAULT PRIVILEGES 仅对指定创建角色之后新建的对象生效,且只在创建时读取一次。常见失效原因包括:未用 FOR ROLE 指定实际建表角色,或对象由其他角色创建、事后更改属主或移动 schema。按 schema 撤销无法覆盖全局默认权限,需先全局撤销再按 schema 授予。序列和函数需单独设置,默认权限不涉及行级安全。

🔎

延伸解读

默认权限的生效时机与角色绑定

ALTER DEFAULT PRIVILEGES 只在对象创建时读取一次,且仅对指定创建角色之后新建的对象生效。若未用 FOR ROLE 指定实际建表角色,或对象由其他角色创建、事后更改属主或移动 schema,默认权限都不会应用。因此,部署脚本中必须明确 FOR ROLE 为迁移角色,并确保建表操作以该角色执行。

按 schema 撤销的局限性

按 schema 撤销默认权限无法覆盖全局默认权限,因为 per-schema 默认是添加到全局默认之上的。例如,函数默认对 PUBLIC 可执行属于全局默认,按 schema 撤销无效,必须先全局撤销再按 schema 授予。对于表,若存在全局授予,按 schema 撤销也不会生效。

序列与函数的独立设置

序列和函数需要单独设置默认权限。仅对表设置默认权限时,使用 serial 列的新表插入会因序列权限被拒,而 identity 列则正常。函数默认对 PUBLIC 可执行,需全局撤销后再按 schema 授予。默认权限不涉及行级安全,RLS 策略仍需在每个新表上单独配置。

默认权限的查看与角色删除影响

使用 \ddp 或查询 pg_default_acl 可查看默认权限。Owner 列是创建角色,空 schema 表示全局。默认权限会作为依赖阻止角色删除,需用 DROP OWNED BY 清除。注意 pg_read_all_data 可覆盖未来表,但会带来更广的读取权限,包括系统表。

❓

Q&A

为什么我设置了 ALTER DEFAULT PRIVILEGES,新表还是报 permission denied?

最常见的原因是默认权限记录给了错误的角色。ALTER DEFAULT PRIVILEGES 只对指定创建角色(FOR ROLE)之后新建的对象生效,且只在创建时读取一次。如果建表角色与 FOR ROLE 指定的角色不一致,或者没有用 FOR ROLE 指定实际建表角色,默认权限就不会应用。此外,对象由其他角色创建、事后更改属主或移动 schema 也会导致默认权限不生效。

ALTER DEFAULT PRIVILEGES 对哪些对象类型有效?序列和函数需要单独设置吗?

默认权限对表(包括视图、物化视图、CREATE TABLE AS、SELECT INTO、分区表、分区、LIKE 创建的表)有效,但序列和函数是单独的类型,需要分别设置。例如,只对表设置默认权限时,新序列的 nextval 仍会被拒绝;需要额外执行 ALTER DEFAULT PRIVILEGES ... GRANT USAGE ON SEQUENCES。函数也需要单独的 GRANT EXECUTE 语句。

为什么在某个 schema 下 REVOKE 默认权限不起作用?

因为按 schema 设置的默认权限是叠加在全局默认权限之上的,按 schema 的 REVOKE 只能移除按 schema 授予的部分,无法撤销全局授予的权限。例如,函数默认对 PUBLIC 可执行,这是全局默认,按 schema 的 REVOKE 不会生效。正确做法是先全局 REVOKE,再按 schema GRANT 回来。

如何查看当前已设置的默认权限?

在 psql 中可以使用 \ddp 命令,或查询 pg_default_acl 系统目录。\ddp 输出中 Owner 列表示默认权限适用的创建角色,Schema 列为空表示全局默认。也可以通过 SQL 查询 pg_default_acl 并展开 acl 来查看详细的授权信息。

为什么有默认权限的角色无法被 DROP ROLE?

因为默认权限中引用了该角色,构成依赖关系,必须在每个存在该默认权限的数据库中清除。可以使用 DROP OWNED BY 角色名 来移除该角色的授权和默认权限条目,然后再 DROP ROLE。注意 DROP OWNED BY 也会删除该角色拥有的所有对象,且需要在每个数据库分别执行。

默认权限能替代行级安全(RLS)吗?

不能。默认权限只授予新对象的权限,不涉及行级安全。即使通过默认权限授予了 SELECT,表上的行级安全策略仍需单独设置。如果没有启用 RLS 或没有策略,应用角色可以读取所有行。默认权限不会自动添加 RLS 策略。

🏷️

标签

➡️

继续阅读