【问题标题】:Create readonly user on all 1000 postgres databases and schema's在所有 1000 个 postgres 数据库和模式上创建只读用户
【发布时间】:2021-02-21 22:33:23
【问题描述】:

使用Vault 我正在尝试在 Postgres 11.8 实例中创建按需临时只读用户。

我会:

  • 1000 多个数据库(每个客户(即租户)一个)
  • 每个数据库都有一个publicreporting 架构。

所以我试图找到一种方法来授予这个只读用户对每个数据库以及两个架构中所有表的访问权限。

虽然我想出了以下 sn-p:

-- Create a new user
CREATE ROLE "my-readonly-user" WITH LOGIN PASSWORD 'test123';

-- Grant access to the two schema's we have
GRANT USAGE ON SCHEMA public TO "my-readonly-user";
GRANT USAGE ON SCHEMA reporting TO "my-readonly-user";

-- Grant access to all tables in our two schema's
GRANT SELECT ON ALL TABLES IN SCHEMA public TO "my-readonly-user";
GRANT SELECT ON ALL TABLES IN SCHEMA reporting TO "my-readonly-user";

-- Grant access to sequences
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO "my-readonly-user";
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA reporting TO "my-readonly-user";

-- Grant access to future tables
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO "my-readonly-user";
ALTER DEFAULT PRIVILEGES IN SCHEMA reporting GRANT SELECT ON TABLES TO "my-readonly-user";

它仅适用于 1 个单一数据库(当前数据库)。如果我使用只读用户登录并切换到某些数据库,除了第一个数据库之外,我看不到任何表。

一个集群包含许多数据库,其中包含许多模式。模式(甚至 同名)在不同的数据库中是不相关的。授予 架构的权限仅适用于 当前 DB(授予时的当前 DB)https://stackoverflow.com/a/24923877/1409047

由于该限制,似乎使上述授权 sn-p 更加复杂。我应该以某种方式迭代我的所有数据库并运行sn-p吗?我将如何进行数据库切换?甚至可以在普通 SQL 中使用(如Vault's API 所要求的那样)?以前有人这样做过吗?

注意:在 MySQL 中做同样的事情只需要 2 行代码,使用 Postgres afaik 不支持的通配符 *.*

CREATE USER '{{name}}'@'10.0.0.0/255.0.0.0' IDENTIFIED BY '{{password}}';
GRANT SELECT, SHOW DATABASES, SHOW VIEW ON *.* TO '{{name}}'@'10.0.0.0/255.0.0.0';

【问题讨论】:

    标签: postgresql grant


    【解决方案1】:

    如果您想仅使用 Postgres 脚本向用户授予只读访问权限,您可以这样做:

    CREATE EXTENSION IF NOT EXISTS dblink;
    
    DO 
    $$
    DECLARE nome_banco TEXT;
    DECLARE template_conexao TEXT;
    DECLARE string_conexao TEXT;
    DECLARE nome_usuario TEXT;
    BEGIN
        template_conexao = 'user=foo password=bar dbname=';
        nome_usuario = 'baz';
    
        FOR nome_banco IN
            SELECT datname FROM pg_database
            WHERE datistemplate = false
        LOOP
            string_conexao = template_conexao || nome_banco;
    
            perform dblink_exec(string_conexao, 'GRANT CONNECT ON DATABASE "' || nome_banco || '" TO ' || nome_usuario);
            perform dblink_exec(string_conexao, 'GRANT SELECT ON ALL TABLES IN SCHEMA public TO ' || nome_usuario);
        END LOOP;
    
    END
    $$
    
    --DROP EXTENSION IF EXISTS dblink;
    

    连接各个数据库,执行脚本;它可以轻松适应需要在所有数据库上执行数据库本地命令的其他情况。

    请记住,为了安全起见,在执行上述脚本后,您应该删除上述脚本创建的 dblink 扩展名,当然,除非您已经将该扩展名用于其他目的。 em>

    【讨论】:

      【解决方案2】:

      SQL 语句不能影响与您连接的数据库不同的数据库中的对象,这是一个深思熟虑的设计决定。

      是的,您必须遍历集群中的所有数据库并在那里运行您的脚本。

      请注意,您的脚本中有一个错误:您不应该在序列上授予只读用户USAGE,否则他们可以修改序列值。 SELECT 很好。

      我要做的是创建一个read_only_group(带有NOLOGIN)并将所有这些权限授予该角色。然后,当有对只读用户的请求时,创建一个用户并将其添加到该组,使其继承该组的权限。不要将任何东西授予用户本身,以便在不再需要时轻松DROP

      【讨论】:

      • 感谢劳伦兹!非常有帮助。我们使用 Flyway 并构建了一个 python 包装器,它迭代每个数据库并将我们的 flyway 迁移应用到它们。我们创建了一个迁移,它为当前连接的数据库上的两个模式提供只读和读写角色,并将该迁移应用到所有数据库。然后在 Hashicorp Vault 中,我们只需创建一个用户角色并将只读或读写角色授予此临时用户。几个小时后,用户被丢弃。
      猜你喜欢
      • 2020-05-06
      • 2018-08-13
      • 2012-02-17
      • 1970-01-01
      • 2020-07-04
      • 1970-01-01
      • 2012-08-10
      • 2017-07-20
      • 2011-09-21
      相关资源
      最近更新 更多