如何正确定义角色和权限(案例研究 - PostgreSQL)?

时间:2016-06-01 18:55:43

标签: sql database postgresql roles privileges

不久前,我来到社区,询问我正在开发的系统触发器的定义。我仍然发现自己正在开发相同的系统,现在我对角色产生怀疑。我是使用PostgreSQL的新手,甚至在文档之后,我最后还是提出了一些问题。

为了开发我的系统,我创建了3个用户:

  • dbadiretor(已翻译为dbadirector):它的行为与DBA相同,仅供一个人使用。
  • dbagerente(翻译为dbamanager):用户可以在没有的情况下更改表结构 操纵它的数据。同一个用户也可以创建 触发器,函数,索引等。
  • clisistema(翻译成clisystem):这是系统用的 连接到数据库。该用户可以执行CRUD操作, 但无法创建,删除,修改或删除现有对象 数据库。对于某些表,此用户已过滤其权限。

创建用户,表格,简单数据和设置权限后,pgAdmin向我显示以下消息:

ERROR:  permission denied for relation tb_tabelas
CONTEXT:  SQL statement "SELECT 1 FROM ONLY "regrast"."tb_tabelas" x WHERE "tab_id" OPERATOR(pg_catalog.=) $1 FOR KEY SHARE OF x"

********** Error **********

ERROR: permission denied for relation tb_tabelas
SQL state: 42501
Context: SQL statement "SELECT 1 FROM ONLY "regrast"."tb_tabelas" x WHERE "tab_id" OPERATOR(pg_catalog.=) $1 FOR KEY SHARE OF x"

我使用postgres用户,我不知道我做错了什么。我没有做出这些陈述(至少不是直接):

"SELECT 1 FROM ONLY "regrast"."tb_tabelas" x WHERE "tab_id" OPERATOR(pg_catalog.=) $1 FOR KEY SHARE OF x"

以下是我的用户的创建:

-- DROP OWNED BY dbadiretor CASCADE;    
DROP ROLE IF EXISTS dbadiretor; 
CREATE ROLE dbadiretor WITH     
    SUPERUSER                   
    CREATEDB                    
    CREATEROLE                  
    LOGIN                       
    REPLICATION             
    CONNECTION LIMIT 1  
    PASSWORD 'dbadiretor';  

-- DROP OWNED BY dbagerente CASCADE;    
DROP ROLE IF EXISTS dbagerente;     
CREATE ROLE dbagerente WITH     
    NOSUPERUSER                 
    NOCREATEDB                  
    NOCREATEROLE            
    NOINHERIT                   
    LOGIN                   
    NOREPLICATION       
    CONNECTION LIMIT 3  
    PASSWORD 'dbagerente';  

-- DROP OWNED BY clisistema CASCADE;
DROP ROLE IF EXISTS clisistema; 
CREATE ROLE clisistema WITH 
    NOSUPERUSER                 
    NOCREATEDB                  
    NOCREATEROLE                
    NOINHERIT                   
    LOGIN                       
    NOREPLICATION                   
    CONNECTION LIMIT 30             
    PASSWORD '12345';   

以下是特权的分配:

-- #####################################
--  USUÁRIO: PUBLIC
-- #####################################

REVOKE ALL PRIVILEGES ON DATABASE "ELocadora" FROM PUBLIC;

-- #####################################
--  USUÁRIO: dbadiretor
-- #####################################

GRANT ALL PRIVILEGES ON SCHEMA regrast TO dbadiretor;
GRANT ALL PRIVILEGES ON DATABASE "ELocadora" TO dbadiretor;
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA regrast TO dbadiretor;

-- #####################################
--  USUÁRIO: clisistema
-- #####################################

GRANT CONNECT ON DATABASE "ELocadora" TO clisistema;
GRANT USAGE ON SCHEMA regrast TO clisistema;
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA regrast TO clisistema;

-- NÍVEL DE FILTRO 1

REVOKE TRUNCATE, REFERENCES, TRIGGER ON ALL TABLES IN SCHEMA regrast FROM clisistema;
REVOKE CREATE ON SCHEMA regrast FROM clisistema;
REVOKE TEMP ON DATABASE "ELocadora" FROM clisistema;

-- NÍVEL DE FILTRO 2

-- Tabela: TB_TABELAS
-- Revogação: CUD
REVOKE INSERT, UPDATE, DELETE ON TABLE regrast.tb_tabelas FROM clisistema;

-- Tabela: TB_DADOS
-- Revogação: CUD
REVOKE INSERT, UPDATE, DELETE ON TABLE regrast.tb_dados FROM clisistema;

-- Tabela: TB_MODIFICACOES
-- Revogação: CUD
REVOKE INSERT, UPDATE, DELETE ON TABLE regrast.tb_modificacoes FROM clisistema;

-- Tabela: TB_TIPOS_DE_LOGS
-- Revogação: CUD
REVOKE INSERT, UPDATE, DELETE ON TABLE regrast.tb_tipos_de_logs FROM clisistema;

-- Tabela: TB_LOGS
-- Revogação: CUD
REVOKE INSERT, UPDATE, DELETE ON TABLE regrast.tb_logs FROM clisistema;

-- Tabela: TB_HISTORICO_DE_PRODUTOS
-- Revogação: CUD
REVOKE INSERT, UPDATE, DELETE ON TABLE regrast.tb_historico_de_produtos FROM clisistema;

-- Tabela: TB_CONFIGURACOES
-- Revogação: CD
REVOKE INSERT, DELETE ON TABLE regrast.tb_configuracoes FROM clisistema;

-- #####################################
--  USUÁRIO: dbagerente
-- #####################################

GRANT CONNECT ON DATABASE "ELocadora" TO dbagerente;
GRANT USAGE ON SCHEMA regrast TO dbagerente;
REVOKE INSERT, SELECT, UPDATE, DELETE ON ALL TABLES IN SCHEMA regrast FROM dbagerente;
GRANT CREATE ON SCHEMA regrast TO dbagerente;
GRANT REFERENCES, TRIGGER ON ALL TABLES IN SCHEMA regrast TO dbagerente;

我正在阅读PostgreSQL documentation,如果我想以任何方式修改表格,我需要为表格设置合适的所有者。例如,关于CREATE权限:

  

CREATE

     

对于模式,允许在模式中创建新对象。 要   重命名现有对象,您必须拥有该对象 才能拥有此对象   包含架构的特权。

因此,我的所有表都将dbagerente用户作为所有者。作为dbagerente,我可以修改结构。但作为dbadiretor或postgres,我不能,而这不是我想要的。对我来说,dbadiretor和postgres是超级用户,他们应该能够完成任何事情......或者不是吗? :/

进一步向前看......我必须注意*小心)其他数据库对象,如函数,触发器等吗?

注意:我使用PostgreSQL 9.5 ,使用名为ELocadora的数据库和名为regrast的模式。

出现这个问题,如果可能的话(如果你不介意的话),你会为像我这样的初学者正确分配角色吗?任何链接或提示可以帮助我。

此外,为了实现日志而创建新用户是否有禁忌症?系统事务(对于某些操作)可能最终必须使用两种类型的用户才能完成。

感谢您的关注。

修改

  

我怀疑由于依赖性而出现此错误   表之间。在某些外键的表格中,我正在使用   ON DELETE和ON UPDATE语句。

     

第一次输入数据时,输入的数据没有问题。   但是,如果我删除它们以重新插入它们,则会出现此错误。

     

这与此有关吗?

我错了,这些信息没有根据。请忽略它。我很抱歉。

编辑2

我记录了所有过程,包括所有步骤和明显的问题。一切都是从头开始的。请看一下(4分钟):

Here

打开的SQL文件代表正在进行的不同操作。它们分为不同的步骤。我又做错了什么?

编辑3

我在代码中发现了一个小错误。非破坏性(最初)。在记录插入代码中,我改变了这个:

INSERT INTO regrast.TB_DADOS (DAD_NOME_VISUAL , DAD_NOME_COLUNA , DAD_TABELA) VALUES ('ID' , 'USU_ID' , (SELECT tba_id FROM regrast.tb_tabelas WHERE tba_nome ILIKE 'tb_usu%'));

进入这个:

INSERT INTO regrast.TB_DADOS (DAD_NOME_VISUAL , DAD_NOME_COLUNA , DAD_TABELA) VALUES ('ID' , 'USU_ID' , (SELECT tba_id FROM regrast.tb_tabelas WHERE tba_nome ILIKE 'tb_usu%' LIMIT 1));
  

@Chris Travers

     

[...]因此表所有者必须具有写入权限   任何人都可以从中删除级联表。

     

[...]所以这里的问题是表所有者没有访问权限。

但我使用超级帐户。我的意思是,我使用超级用户。从理论上讲,这里没有限制,因为我是超级用户,不是吗?我作为超级用户尝试插入和删除表记录。然而,我收到了这个错误。

以下代码给出了错误:

INSERT INTO regrast.TB_DADOS (DAD_NOME_VISUAL , DAD_NOME_COLUNA , DAD_TABELA) VALUES ('ID' , 'USU_ID' , (SELECT tba_id FROM regrast.tb_tabelas WHERE tba_nome ILIKE 'tb_usu%' LIMIT 1));
INSERT INTO regrast.TB_DADOS (DAD_NOME_VISUAL , DAD_NOME_COLUNA , DAD_TABELA) VALUES ('Login' , 'USU_LOGIN' , (SELECT tba_id FROM regrast.tb_tabelas WHERE tba_nome ILIKE 'tb_usu%' LIMIT 1));
INSERT INTO regrast.TB_DADOS (DAD_NOME_VISUAL , DAD_NOME_COLUNA , DAD_TABELA) VALUES ('Senha' , 'USU_SENHA' , (SELECT tba_id FROM regrast.tb_tabelas WHERE tba_nome ILIKE 'tb_usu%' LIMIT 1));
INSERT INTO regrast.TB_DADOS (DAD_NOME_VISUAL , DAD_NOME_COLUNA , DAD_TABELA) VALUES ('Apelido' , 'USU_APELIDO' , (SELECT tba_id FROM regrast.tb_tabelas WHERE tba_nome ILIKE 'tb_usu%' LIMIT 1));
INSERT INTO regrast.TB_DADOS (DAD_NOME_VISUAL , DAD_NOME_COLUNA , DAD_TABELA) VALUES ('Nascimento' , 'USU_NASCIMENTO' , (SELECT tba_id FROM regrast.tb_tabelas WHERE tba_nome ILIKE 'tb_usu%' LIMIT 1));
INSERT INTO regrast.TB_DADOS (DAD_NOME_VISUAL , DAD_NOME_COLUNA , DAD_TABELA) VALUES ('Cadastro' , 'USU_CADASTRO' , (SELECT tba_id FROM regrast.tb_tabelas WHERE tba_nome ILIKE 'tb_usu%' LIMIT 1));
INSERT INTO regrast.TB_DADOS (DAD_NOME_VISUAL , DAD_NOME_COLUNA , DAD_TABELA) VALUES ('Gênero' , 'USU_GENERO' , (SELECT tba_id FROM regrast.tb_tabelas WHERE tba_nome ILIKE 'tb_usu%' LIMIT 1));
INSERT INTO regrast.TB_DADOS (DAD_NOME_VISUAL , DAD_NOME_COLUNA , DAD_TABELA) VALUES ('Privilégio' , 'USU_PRIVILEGIO' , (SELECT tba_id FROM regrast.tb_tabelas WHERE tba_nome ILIKE 'tb_usu%' LIMIT 1));
INSERT INTO regrast.TB_DADOS (DAD_NOME_VISUAL , DAD_NOME_COLUNA , DAD_TABELA) VALUES ('CEP' , 'USU_CEP' , (SELECT tba_id FROM regrast.tb_tabelas WHERE tba_nome ILIKE 'tb_usu%' LIMIT 1));
INSERT INTO regrast.TB_DADOS (DAD_NOME_VISUAL , DAD_NOME_COLUNA , DAD_TABELA) VALUES ('Número Residencial' , 'USU_NUMERO' , (SELECT tba_id FROM regrast.tb_tabelas WHERE tba_nome ILIKE 'tb_usu%' LIMIT 1));
INSERT INTO regrast.TB_DADOS (DAD_NOME_VISUAL , DAD_NOME_COLUNA , DAD_TABELA) VALUES ('Complemento' , 'USU_COMPLEMENTO' , (SELECT tba_id FROM regrast.tb_tabelas WHERE tba_nome ILIKE 'tb_usu%' LIMIT 1));

如果我对此发表评论,一切正常。

1 个答案:

答案 0 :(得分:1)

右。关于改变表的共享能力,您有几个选项。

  1. 您可以将dba用户变为超级用户(这会绕过此用户的权限检查)或

  2. 您可以创建另一个角色(with INHERIT NOLOGIN)为该角色分配所有权,并将该角色授予需要修改结构的任何人。添加这些选项的原因是,这不是登录角色,而是管理共享权限的角色。授予此角色的权限(以及所有权!)将在授予此角色的所有角色之间共享。

  3. 对于select用户拒绝的权限,您使用的是dbagerente用户吗?如果是这样,那么因为你因此撤销了对此的权限。如果不是您使用的是哪个用户名?

    修改即可。请注意,此类RI RI触发器作为表所有者运行,因此表所有者必须具有对级联表的写访问权限,然后才能从中删除它们。

    您通过(在回滚的交易中)进行测试:

    BEGIN;
    ALTER TABLE ... DISABLE TRIGGER ALL;
    -- statements that are failing here
    ROLLBACK;
    

    所以这里的问题是表所有者没有访问权限。根据我的经验,我必须添加授予表所有者的选择权限和删除权限(如果您还有更新,则可能需要更新)。\

    EDIT2:如何重现

     CREATE USER myuser;
    

    现在以myuser身份登录:

     CREATE TABLE ctest1 (id int primary key);
     INSERT INTO ctest1 (id) SELECT generate_series(0, 10);
     CREATE TABLE ctest2 (id int references ctest1(id) on delete cascade);
     INSERT INTO ctest2 (id) SELECT generate_series(0, 10);
     REVOKE ALL ON ctest2 FROM myuser; -- nonsuperuser owner
    

    现在以postgres(超级用户)身份登录:

     DELETE FROM ctest1 WHERE id = 4;
     -- throws the error
     GRANT DELETE ON ctest2 TO myuser;
     DELETE FROM ctest1 WHERE id = 4;
     -- throws the error
     GRANT SELECT ON ctest2 TO myuser;
     DELETE FROM ctest1 WHERE id = 4; -- success