删除具有特权的角色

Posted

技术标签:

【中文标题】删除具有特权的角色【英文标题】:Drop a role with privileges 【发布时间】:2018-06-08 10:28:03 【问题描述】:

这看起来像是一个非常基本的需求,但我没有找到任何快速且合适的答案。我在 Postgres 中有一个角色,它对各种数据库中的许多其他表具有特权。

我需要放弃这个角色。我有一个 postgres 实例,然后在它上面有许多数据库。

SELECT DISTINCT 'REVOKE ALL ON TABLE ' || table_schema || '.' || table_name || ' FROM ' || r.param_role_name || ';'  
FROM information_schema.table_privileges CROSS JOIN (SELECT 'some_role_name'::text AS param_role_name) r
WHERE grantee ~* r.param_role_name;

我可以像上面那样做,通过访问每个数据库并找到所有撤销语句然后删除角色。有什么方法可以在一个地方找到所有数据库的所有撤销语句。

或者像我可以改变这个角色所拥有的东西,我可以用一个语句改变所有的权限吗?

Edit1:由于大多数回复的目标是重新分配拥有者和删除拥有者,因此我想更具体一些。 我可以在每个数据库上执行以下命令,并在删除所有依赖项后删除角色。

REASSIGN OWNED BY some_role_name TO postgres;
DROP OWNED BY some_role_name;

但是有很多数据库,所以我正在寻找一些东西来强制刷新所有权限并放弃这个角色。

【问题讨论】:

过程描述in the documentation. 【参考方案1】:

我需要放弃这个角色。

在同一集群的每个数据库中运行此命令,其中角色可能拥有任何东西或具有任何授予的权限:

REASSIGN OWNED BY some_role_name TO postgres;
DROP OWNED BY some_role_name;

postgres 是默认超级用户,您可以选择任何其他用户。它将拥有旧角色当前拥有的对象。在REASSIGN OWNED 之后,没有任何对象会被同一用户拥有。运行DROP OWNED 可能看起来不直观。该命令的措辞具有误导性,因为它撤销了同一数据库中角色的所有权限和默认权限。 The manual:

DROP OWNED 删除当前数据库中由指定角色之一拥有的所有对象。 在当前数据库中的对象和共享对象(数据库、表空间)上授予给定角色的任何权限也将被撤销。

我的大胆强调。 您仍然必须在每个数据库中执行它,其中角色拥有任何东西或具有任何授予的权限。手册:

因为REASSIGN OWNED 不会影响其他数据库中的对象,所以通常需要在每个包含要删除的角色拥有的对象的数据库中执行此命令。

最后,运行(一次):

DROP role some_role_name;

角色存储在集群范围的系统目录中,而对象的所有权和权限存储在数据库本地系统目录中。

此相关答案中的详细说明:

Find objects linked to a PostgreSQL role

有一个相关的page in the manual with instructions。

全自动化

没有一个命令可以做到这一切。但是你可以让 Postgres 为你生成一个完整的 psql 脚本。

角色的依赖关系存储在系统目录pg_shdepend中:

此信息允许 PostgreSQL 在尝试删除这些对象之前确保它们未被引用。

由于我们(可能)需要连接到不同的数据库,我们需要 psql 元命令 (\c my_database) 和 SQL DDL 命令的组合,如上所示。在您的数据库集群中的某处创建此函数一次:

CREATE OR REPLACE FUNCTION f_generate_ddl_to_remove_role(dead_role_walking regrole)
  RETURNS text
  LANGUAGE sql AS
$func$
SELECT concat_ws(
   E'\n'
 ,(SELECT string_agg(format(E'\\c %I\nREASSIGN OWNED BY %2$s TO postgres; DROP OWNED BY %2$s;'
                          , d.datname, dead_role_walking)
                   , E'\n')
   FROM  (
      SELECT DISTINCT dbid
      FROM   pg_shdepend
      WHERE  refobjid = dead_role_walking
      ) s
   JOIN   pg_database d ON d.oid = s.dbid)
 , format(E'DROP role %s;\n', dead_role_walking)
   )
$func$;

呼叫:

SELECT f_generate_ddl_to_remove_role('some_role_name');

产生如下字符串:

\c my_db1
REASSIGN OWNED BY some_role_name TO postgres; DROP OWNED BY some_role_name;
\c my_db2
REASSIGN OWNED BY some_role_name TO postgres; DROP OWNED BY some_role_name;
DROP role some_role_name;

或者,如果角色不拥有任何东西并且没有特权,那么:

DROP role some_role_name;

如果您提供不存在的角色名称,则会收到错误消息。

将字符串(不包含单引号)复制到以超级用户(如postgres)打开的 psql 会话中。或者将 bash 脚本与它连接起来。全部完成。

有几个相关的答案,对动态SQL有更多解释:

https://***.com/search?q=%5Bplpgsql%5D+%5Bdynamic-sql%5D+string_agg

【讨论】:

感谢您的回复。我已经这样做了,但是有很多数据库,我不想在每个数据库上执行相同的命令,看起来没有其他办法! @user3294904:是的,您需要在每个涉及的数据库中执行。但是你可以让 Postgres 生成整个脚本。我在上面添加了一章。而且您不需要像问题中显示的REVOKE ALL ON TABLE ...,因为DROP OWNED 负责所有权限。【参考方案2】:

在任何数据库中存在依赖对象之前,您不能删除角色。

您必须将此用户 (some_role_name) 拥有的对象重新分配给另一个用户。 对所有数据库中的所有对象完成此操作后,您就可以删除该用户了。

REASSIGN OWNED BY some_role_name TO some_other_role_name;

如果不需要依赖对象,您也可以继续使用 DROP OWNED BY,删除 some_role_name 拥有的所有对象。

DROP OWNED BY some_role_name;

【讨论】:

以上是关于删除具有特权的角色的主要内容,如果未能解决你的问题,请参考以下文章

在 Oracle 数据库中具有角色时错误用户没有特权

检查用户是不是具有 x 角色之一,然后从他们中删除该角色

php 重力特权//填充任何内容//填充用户角色

用户和角色有啥区别?

安全架构 - 驱动 UI 和特权(权利)的设置 - 基于角色,每个用户帐户

JWT基于角色的访问控制