是否有一种简单的方法可以枚举特定角色具有某些访问权限的所有对象?我知道这一套 has_*_privilege
pg_catalog中的函数但它们不能完成这项工作,我想以相反的方式工作。实际上,我希望有一个视图为pg_class中存储的特定角色提供oid和access权限。
这样的视图非常便于检查数据库的安全性是否正确设置。通常,角色的关系远远少于关系,因此检查角色的麻烦要少得多。这种实用程序是否应该不适用于标准的PostgreSQL发行版?
根据源代码(acl.h),aclitem是一个结构:
typedef struct AclItem
{ Oid ai_grantee; /* ID that this item grants privs to */
Oid ai_grantor; /* grantor of privs */
AclMode ai_privs; /* privilege bits */
} AclItem;
易于使用。但是,pg_type将其列为用户定义的非复合类型。这是为什么?我现在看到的唯一方法是使用字符串函数解析aclitem []数组。有没有更好的方法来分析aclitem数组?
添加信息
浏览各种PG列表,显然这个问题至少从1997年开始以各种形式出现(我们当时有电脑吗?是电视吗?),最相关的讨论主题是“二进制输入/输出用于aclitem”在2011年初的pgsql-hackers上。作为PG技术熟练的用户 - 而不是黑客 - 我很欣赏开发人员对维护稳定界面的关注,但是线程中表达的一些担忧有点远我的口味。在系统目录中没有pg_acl表的真正原因是什么,其定义等于源代码中的AclItem结构?该结构何时发生变化?我也知道SE的发展很可能会改变安全性的处理方式 - 当用户选择的时候 - 大概是这样 - 所以我会满足于提供acl信息的东西,以便很容易枚举授予的权限特定用户,例如:
SELECT * FROM pg_privileges WHERE grantee = 16384;
像这样,它仍然可以是底层结构的抽象,因此引擎盖下的任何变化都可能(可能)仍然被转换为暴露的界面。我会说,与information_schema方法没什么不同。
干杯,
帕特里克
没有开箱即用的这种视图,但创建它所需的数据在系统目录中:
http://www.postgresql.org/docs/current/static/catalogs.html
例如,有一个 relacl
在 pg_class
:
select oid::regclass, relacl from pg_class;
其他目录中也有类似的字段,即 typacl
在 pg_type
和 proacl
在 pg_proc
。
你可能想要再使用两个目录,即 pg_authid
了解哪些角色具有超级用户权限,以及 pg_auth_members
知道谁有什么角色。
(该 pg_default_acl
仅在对象创建期间使用,因此没有用。)
有一些与aclitem相关的内部函数可以在创建视图时派上用场。你可以列出它们 psql
像这样:
\df+ *acl*
尤其是 aclexplode()
。以下示例有望让您入门:
select oid::regclass,
(aclexplode(relacl)).grantor,
(aclexplode(relacl)).grantee,
(aclexplode(relacl)).privilege_type,
(aclexplode(relacl)).is_grantable
from pg_class
where relacl is not null;
它可以通过首先扩展acl行来优化,例如:
select oid::regclass,
aclitem.grantee
from (select oid, aclexplode(relacl) as aclitem from pg_class) sub
它会引导您直接达到预期的效果。
就我所知,这与使用内置工具一样好。 (当然,如果你想进一步优化它,你可以在C中编写自己的一组运算符。)
关于你的额外问题,我担心它们只能由世界上的少数人来回答,也就是核心开发者本身。他们比在这里更频繁地登上pg黑客列表。
没有开箱即用的这种视图,但创建它所需的数据在系统目录中:
http://www.postgresql.org/docs/current/static/catalogs.html
例如,有一个 relacl
在 pg_class
:
select oid::regclass, relacl from pg_class;
其他目录中也有类似的字段,即 typacl
在 pg_type
和 proacl
在 pg_proc
。
你可能想要再使用两个目录,即 pg_authid
了解哪些角色具有超级用户权限,以及 pg_auth_members
知道谁有什么角色。
(该 pg_default_acl
仅在对象创建期间使用,因此没有用。)
有一些与aclitem相关的内部函数可以在创建视图时派上用场。你可以列出它们 psql
像这样:
\df+ *acl*
尤其是 aclexplode()
。以下示例有望让您入门:
select oid::regclass,
(aclexplode(relacl)).grantor,
(aclexplode(relacl)).grantee,
(aclexplode(relacl)).privilege_type,
(aclexplode(relacl)).is_grantable
from pg_class
where relacl is not null;
它可以通过首先扩展acl行来优化,例如:
select oid::regclass,
aclitem.grantee
from (select oid, aclexplode(relacl) as aclitem from pg_class) sub
它会引导您直接达到预期的效果。
就我所知,这与使用内置工具一样好。 (当然,如果你想进一步优化它,你可以在C中编写自己的一组运算符。)
关于你的额外问题,我担心它们只能由世界上的少数人来回答,也就是核心开发者本身。他们比在这里更频繁地登上pg黑客列表。
可能不是最好/最有效的方式,但它对我帮助很大!我在需要删除角色和出错时遇到了问题。
ERROR: role ROLE_NAME cannot be dropped because some objects depend on it
你可以用它
SELECT * FROM upg_roles_privs WHERE grantee = 'testuser'
代码如下。我不包括“系统”对象(来自pg_catalog和information_schema),如果要枚举它们,可以从查询中取出条件。
CREATE VIEW upg_roles_privs AS
/* Databases */
select type, objname, r1.rolname grantor, r2.rolname grantee, privilege_type
from
(select
'database'::text as type, datname as objname, datistemplate, datallowconn,
(aclexplode(datacl)).grantor as grantorI,
(aclexplode(datacl)).grantee as granteeI,
(aclexplode(datacl)).privilege_type,
(aclexplode(datacl)).is_grantable
from pg_database) as db
join pg_roles r1 on db.grantorI = r1.oid
join pg_roles r2 on db.granteeI = r2.oid
where r2.rolname not in ('postgres')
union all
/* Schemas / Namespaces */
select type, objname, r1.rolname grantor, r2.rolname grantee, privilege_type from
(select
'schema'::text as type, nspname as objname,
(aclexplode(nspacl)).grantor as grantorI,
(aclexplode(nspacl)).grantee as granteeI,
(aclexplode(nspacl)).privilege_type,
(aclexplode(nspacl)).is_grantable
from pg_catalog.pg_namespace) as ns
join pg_roles r1 on ns.grantorI = r1.oid
join pg_roles r2 on ns.granteeI = r2.oid
where r2.rolname not in ('postgres')
union all
/* Tabelas */
select 'tables'::text as type, table_name||' ('||table_schema||')' as objname, grantor, grantee, privilege_type
from information_schema.role_table_grants
where grantee not in ('postgres')
and table_schema not in ('information_schema', 'pg_catalog')
and grantor <> grantee
union all
/* Colunas (TODO: se o revoke on table from x retirar acesso das colunas, nao precisa desse bloco) */
select
'columns'::text as type, column_name||' ('||table_name||')' as objname,
grantor, grantee, privilege_type
from information_schema.role_column_grants
where
table_schema not in ('information_schema', 'pg_catalog')
and grantor <> grantee
union all
/* Funcoes / Procedures */
select 'routine'::text as type, routine_name as objname, grantor, grantee, privilege_type
from information_schema.role_routine_grants
where grantor <> grantee
and routine_schema not in ('information_schema', 'pg_catalog')
--union all information_schema.role_udt_grants
union all
/* Outros objetos */
select 'object'::text as type, object_name||'( '||object_type||')' as objname, grantor, grantee, privilege_type
from information_schema.role_usage_grants
where object_type <> 'COLLATION' and object_type <> 'DOMAIN'