PostgreSQL-在数据库范围内授予DEFAULT PRIVILEGES并仅针对特定模式撤销它们

时间:2019-07-28 16:07:26

标签: postgresql

我正在经历与DEFAULT PRIVILEGES相关的奇怪和(对我来说)莫名其妙的行为。一旦授予了整个数据库的权限,似乎就不能仅针对特定的架构撤销默认权限。 我目前正在CentOS上使用PostgreSQL 10.5对此进行测试。

假设有3个用户:

admin    Owner of the database. Used to manipulate the STRUCTURE of the database (CREATE, DROP, TRUNCATE...)
manager  Used for DATA manipulation (INSERT, UPDATE, DELETE)
reader   Used to read DATA (basically SELECT)

想法是:

  1. admin将是数据库及其包含的所有对象的所有者
  2. manager将用于跨所有模式的数据操作,但public(仅用户admin可以修改public模式的数据)< / li>
  3. reader将能够阅读所有内容。

为了使事情变得简单,这将依赖默认特权,以便新创建的对象(方案,表,视图,函数等)都将具有正确的权限。

这是我第一次尝试类似的方法,而不是基于针对所有不同架构的多个用户的细粒度权限策略,显然,此设置应该非常简单。 原来我缺少了一些东西。

这是一个简单的测试脚本。用户admindb数据库的所有者,发出的所有这些命令都以admin的身份连接到数据库:

-- 1. User manager inherits from user reader 
GRANT reader TO manager;

-- 2. Allow connections to the database
REVOKE ALL ON DATABASE db FROM PUBLIC;
GRANT CONNECT ON DATABASE db TO reader;

-- 3. Default reading privileges for user reader
ALTER DEFAULT PRIVILEGES GRANT USAGE ON SCHEMAS TO reader;
ALTER DEFAULT PRIVILEGES GRANT SELECT, REFERENCES ON TABLES TO reader;
ALTER DEFAULT PRIVILEGES GRANT SELECT ON SEQUENCES TO reader;
ALTER DEFAULT PRIVILEGES GRANT EXECUTE ON FUNCTIONS TO reader;

-- 4. Defauly writing privileges for user manager
ALTER DEFAULT PRIVILEGES GRANT INSERT, UPDATE, DELETE ON TABLES TO manager;
ALTER DEFAULT PRIVILEGES GRANT USAGE ON SEQUENCES TO manager;

-- 5. Reinit public schema
DROP SCHEMA public;
CREATE SCHEMA public;

-- 6. Revoke access and default privileges from PUBLIC to public schema
REVOKE ALL ON SCHEMA public FROM PUBLIC;
ALTER DEFAULT PRIVILEGES REVOKE ALL ON TABLES FROM PUBLIC;
ALTER DEFAULT PRIVILEGES REVOKE ALL ON SEQUENCES FROM PUBLIC;
ALTER DEFAULT PRIVILEGES REVOKE ALL ON FUNCTIONS FROM PUBLIC;

-- 7. HERE COMES THE WEIRD STUFF, the two following statements don't have any effect at all
ALTER DEFAULT PRIVILEGES IN SCHEMA public REVOKE INSERT, UPDATE, DELETE ON TABLES FROM manager;
ALTER DEFAULT PRIVILEGES IN SCHEMA public REVOKE USAGE ON SEQUENCES FROM manager;

可以很容易地这样验证:

-- Execute as user admin:
CREATE TABLE public.t (id serial PRIMARY KEY, dummy integer)

-- Execute as user manager (it should not be allowed, but it is!)
DELETE FROM public.t;

我知道我可以使用一些触发函数来规避这一点,但是问题的关键是这是否是正常的和预期的,某种错误还是我缺少什么?

2 个答案:

答案 0 :(得分:0)

我一直在考虑,我想出的最优雅的解决方案取决于Event Trigger

当然,它并不能直接回答我的问题,这意味着我仍然想知道为什么不能像这样使用默认特权,但是至少这满足了 set-and-forget 的最初要求默认权限将提供。

创建一个撤销不需要的特权并返回event_trigger 的函数:

CREATE FUNCTION reset_privileges() RETURNS event_trigger AS $$
BEGIN
    IF EXISTS (SELECT true FROM pg_event_trigger_ddl_commands() WHERE schema_name = 'public') THEN
        REVOKE INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public FROM manager;
        REVOKE USAGE ON ALL SEQUENCES IN SCHEMA public FROM manager;
    END IF;
END;
$$ LANGUAGE plpgsql;

创建实际的EVENT TRIGGER(这需要超级用户权限!)

CREATE EVENT TRIGGER reset_public_schema_privileges
    ON ddl_command_end WHEN TAG IN (
        'CREATE TABLE', 
        'CREATE TABLE AS', 
        'CREATE VIEW', 
        'CREATE MATERIALIZED VIEW', 
        'CREATE FUNCTION'
    ) EXECUTE PROCEDURE reset_privileges();

该函数检查新创建的对象是否在public模式中,并最终撤消用户manager的所有不需要的特权。

它甚至不必费心过滤那些对象,而是撤消{{1}中ALL TABLE s,VIEW s和FUNCTION s的特权}}模式。当然,可以使用pg_event_trigger_ddl_commands提供的public字段以及函数内部更精细的逻辑轻松地对其进行自定义。

答案 1 :(得分:0)

根据the manual for ALTER DEFAULT PRIVILEGES

按架构指定的默认特权将添加到特定对象类型的全局默认特权中。这意味着,如果按全局授予特权(默认情况下或根据先前未指定架构的ALTER DEFAULT PRIVILEGES命令),则无法撤消每个模式的特权。按方案REVOKE仅可用于反转先前按方案GRANT的效果。

(这在该手册页上给出的示例中更加明确。)

因此,我认为正在发生的事情是,在脚本的第5步中,您正在设置默认权限,以授予 all 模式的表上的DELETE(作为全局默认值) :

ALTER DEFAULT PRIVILEGES GRANT INSERT, UPDATE, DELETE ON TABLES TO manager;

但是在第7步中,您将专门撤消public模式。此撤销对全局授予没有任何影响,因此仍将授予DELETE(及其他)特权:

ALTER DEFAULT PRIVILEGES IN SCHEMA public REVOKE INSERT, UPDATE, DELETE ON TABLES FROM manager;

我想我要么(a)硬着头皮,为每个模式添加默认特权(不是“即发即弃”,而是更明确的特权),或者(b)质疑为什么我需要{{1 }}模式存在,旨在将其删除以简化这种情况。