我正在尝试编写一个查询(给定一个角色列表和数据库列表),列出database
,schema
和table
类型对象的有效权限(开头)
我一直在尝试使用has_XXX_privilege()
函数,但输出感觉很尴尬......
有3个角色,例如,(app_rwc
,app_rw
,app_r
)和单个数据库test_db
我希望得到这样的输出< / p>
role, obj_type, obj_name, has_permissions, missing_premissions
app_rwc, DATABASE, test_db, CREATE+CONNECT+TEMPORARY", NULL
app_rw, DATABASE, test_db, CONNECT+TEMPORARY, CREATE
app_r, DATABASE, test_db, CONNECT+TEMPORARY, CREATE
app_rwc, SCHEMA, audit, CREATE+USAGE, NULL
app_rwc, SCHEMA, shared, CREATE+USAGE, NULL
app_rw, SCHEMA, audit, USAGE, CREATE
app_rw, SCHEMA, shared, USAGE, CREATE
app_r, SCHEMA, audit, USAGE, CREATE
app_r, SCHEMA, audit, USAGE, CREATE
app_rwc, TABLE, audit.trail, SELECT+INSERT+UPDATE+DELETE+REFERENCES+TRIGGERS, TRUNCATE
etc
etc
到目前为止,这是我得到的,它有点工作,除了它是冗长的... 如果有人有更好的方法请指教 - 谢谢。
WITH
databases AS (
SELECT * FROM (VALUES ('app_prod')) AS t(database_name)
),
roles AS (
SELECT * FROM (VALUES ('app_rwc'), ('app_rw'), ('app_r')) AS t(role_name)
),
db_permissions AS (
SELECT * FROM (VALUES ('CREATE'), ('CONNECT'), ('TEMPORARY')) AS t(permission_name)
),
schemas AS (
SELECT
schema_name
FROM
information_schema.schemata
WHERE
catalog_name IN (SELECT database_name FROM databases)
AND schema_owner IN (SELECT role_name FROM roles)
),
schema_permissions AS (
SELECT * FROM (VALUES ('CREATE'), ('USAGE')) AS t(permission_name)
),
tables AS (
SELECT table_schema, table_name
FROM information_schema.tables
WHERE
table_catalog IN (SELECT database_name FROM databases)
AND table_schema IN (SELECT schema_name FROM schemas)
AND table_type IN ('BASE TABLE') -- , 'VIEW'
),
table_permissions AS (
SELECT * FROM (VALUES ('SELECT'), ('INSERT'), ('UPDATE'), ('DELETE'), ('TRUNCATE'), ('REFERENCES'), ('TRIGGER')) AS t(permission_name)
)
-- ----------------------------------------------------------------------------
SELECT
'DATABASE' AS obj_type
, databases.database_name AS obj_name
, roles.role_name
, db_permissions.permission_name
, has_database_privilege(roles.role_name, databases.database_name, db_permissions.permission_name) AS has_permission
FROM
databases
CROSS JOIN roles
CROSS JOIN db_permissions
-- ----------------------------------------------------------------------------
UNION ALL
-- ----------------------------------------------------------------------------
SELECT
'SCHEMA' AS obj_type
, schemas.schema_name AS obj_name
, roles.role_name
, schema_permissions.permission_name
, has_schema_privilege(roles.role_name, schemas.schema_name, schema_permissions.permission_name) AS has_permission
FROM
schemas
CROSS JOIN roles
CROSS JOIN schema_permissions
-- ----------------------------------------------------------------------------
UNION ALL
-- ----------------------------------------------------------------------------
SELECT
'TABLE' AS obj_type
, tables.table_schema || '.' || tables.table_name AS obj_name
, roles.role_name
, table_permissions.permission_name
, has_table_privilege(roles.role_name, (tables.table_schema || '.' || tables.table_name),table_permissions.permission_name) AS has_permission
FROM
tables
CROSS JOIN roles
CROSS JOIN table_permissions
UPDATE#1 - 这是扩展查询(类型,序列和函数)与聚合(感谢@filiprem的提示!)仍然相当大,但它做我想要的要做。
WITH
databases AS (
SELECT unnest('{app_prod}'::text[]) AS dbname
),
roles AS (
SELECT unnest('{app_rwc,app_rw,app_r}'::text[]) AS rname
),
permissions AS (
SELECT 'DATABASE' AS ptype, unnest('{CREATE,CONNECT,TEMPORARY}'::text[]) AS pname
UNION ALL
SELECT 'SCHEMA' AS ptype, unnest('{CREATE,USAGE}'::text[]) AS pname
UNION ALL
SELECT 'TABLE' AS ptype, unnest('{SELECT,INSERT,UPDATE,DELETE,TRUNCATE,REFERENCES,TRIGGER}'::text[]) AS pname
UNION ALL
SELECT 'SEQUENCE' AS ptype, unnest('{USAGE,SELECT,UPDATE}'::text[]) AS pname
UNION ALL
SELECT 'TYPE' AS ptype, unnest('{USAGE}'::text[]) AS pname
UNION ALL
SELECT 'FUNCTION' AS ptype, unnest('{EXECUTE}'::text[]) AS pname
),
schemas AS (
SELECT schema_name AS sname
FROM information_schema.schemata
WHERE catalog_name IN (SELECT dbname FROM databases) -- show schemas that exist in specified DB
AND schema_owner IN (SELECT rname FROM roles) -- show schemas that are owned by specified roles
OR schema_name IN ('public') -- always include these
--OR schema_name IN ('public', 'information_schema', 'pg_catalog')
),
tables AS (
SELECT table_schema AS tschema, table_name AS tname
FROM information_schema.tables
WHERE table_catalog IN (SELECT dbname FROM databases)
AND table_schema IN (SELECT sname FROM schemas)
AND table_type IN ('BASE TABLE') -- , 'VIEW'
),
sequences AS (
SELECT schemaname AS seqschema, sequencename AS seqname
FROM pg_sequences
WHERE schemaname IN (SELECT sname FROM schemas)
),
types AS (
SELECT nspname AS typeschema, typname AS typename, CASE typtype WHEN 'c' THEN 'composite' WHEN 'd' THEN 'domain' WHEN 'e' THEN 'enum' WHEN 'r' THEN 'range' ELSE 'other' END AS typekind
FROM pg_type INNER JOIN pg_namespace ON pg_type.typnamespace = pg_namespace.oid
WHERE nspname IN (SELECT sname FROM schemas)
AND typtype NOT IN ('b','p') -- exclude base and pseudo types
AND typname NOT IN (SELECT seqname FROM sequences) -- exclude sequences
),
functions AS (
SELECT nspname AS fnschema, proname AS fnname, pg_proc.oid AS fnoid, pg_get_function_arguments(pg_proc.oid) AS fnargs
FROM pg_proc INNER JOIN pg_namespace ON pg_proc.pronamespace = pg_namespace.oid
WHERE nspname IN (SELECT sname FROM schemas)
),
final AS (
SELECT
permissions.ptype
, databases.dbname AS obj_name
, roles.rname
, permissions.pname
, has_database_privilege(roles.rname, databases.dbname, permissions.pname) AS has_permission
FROM
databases
CROSS JOIN roles
CROSS JOIN permissions
WHERE
permissions.ptype = 'DATABASE'
UNION ALL -- ----------------------------------------------------------------------------------------------------------
SELECT
permissions.ptype
, schemas.sname AS obj_name
, roles.rname
, permissions.pname
, has_schema_privilege(roles.rname, schemas.sname, permissions.pname) AS has_permission
FROM
schemas
CROSS JOIN roles
CROSS JOIN permissions
WHERE
permissions.ptype = 'SCHEMA'
UNION ALL -- ----------------------------------------------------------------------------------------------------------
SELECT
permissions.ptype
, tables.tschema || '.' || tables.tname AS obj_name
, roles.rname
, permissions.pname
, has_table_privilege(roles.rname, (tables.tschema || '.' || tables.tname), permissions.pname) AS has_permission
FROM
tables
CROSS JOIN roles
CROSS JOIN permissions
WHERE
permissions.ptype = 'TABLE'
UNION ALL -- ----------------------------------------------------------------------------------------------------------
SELECT
permissions.ptype
, sequences.seqschema || '.' || sequences.seqname AS obj_name
, roles.rname
, permissions.pname
, has_sequence_privilege(roles.rname, (sequences.seqschema || '.' || sequences.seqname), permissions.pname) AS has_permission
FROM
sequences
CROSS JOIN roles
CROSS JOIN permissions
WHERE
permissions.ptype = 'SEQUENCE'
UNION ALL -- ----------------------------------------------------------------------------------------------------------
SELECT
permissions.ptype || ' - ' || types.typekind
, types.typeschema || '.' || types.typename AS obj_name
, roles.rname
, permissions.pname
, has_type_privilege(roles.rname, (types.typeschema || '.' || types.typename), permissions.pname) AS has_permission
FROM
types
CROSS JOIN roles
CROSS JOIN permissions
WHERE
permissions.ptype = 'TYPE'
UNION ALL -- ----------------------------------------------------------------------------------------------------------
SELECT
permissions.ptype
, functions.fnschema || '.' || functions.fnname || '(' || fnargs || ')' AS obj_name
, roles.rname
, permissions.pname
, has_function_privilege(roles.rname, functions.fnoid, permissions.pname) AS has_permission
FROM
functions
CROSS JOIN roles
CROSS JOIN permissions
WHERE
permissions.ptype = 'FUNCTION'
)
-- ====================================================================================================================
SELECT
rname AS role_name
, ptype AS object_type
, obj_name AS object_name
, string_agg(DISTINCT CASE WHEN has_permission THEN pname END, ',') AS granted_permissions
, string_agg(DISTINCT CASE WHEN NOT has_permission THEN pname END, ',') AS missing_premissions
FROM
final
GROUP BY 1, 2, 3
ORDER BY 1, 2, 3
答案 0 :(得分:0)
您的查询很好,您只需要添加一些聚合。这是一个开始:
select obj_type, obj_name, role_name,
array_agg(distinct case when has_permission then permission_name end),
array_agg(distinct case when not has_permission then permission_name end)
from ( /* your query */ ) AS q1
group by 1,2,3
order by 1,2,3