在所有 1000 个 postgres 数据库和模式上创建只读用户

Create readonly user on all 1000 postgres databases and schema's

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

我会有:

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

虽然我想到了以下片段:

-- 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 个数据库(当前数据库)。如果我使用只读用户登录并切换到某些数据库,除了第一个数据库之外,我看不到任何表。

A cluster holds many databases, which hold many schemas. Schemas (even with the same name) in different DBs are unrelated. Granting privileges for a schema only applies to this particular schema in the current DB (the current DB at the time of granting).

由于这个限制,上面的授权代码片段似乎变得更加复杂。我应该以某种方式迭代我的所有数据库和 运行 代码片段吗?我将如何进行数据库切换?甚至可以在 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';

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

是的,您将必须遍历集群中的所有数据库和 运行 您的脚本。

请注意,您的脚本中存在一个错误:您不应授予 read-only 用户 USAGE 序列,否则他们可以修改序列值。 SELECT 可以。

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

如果您想只使用 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 扩展,当然,除非您已经在使用该扩展用于其他目的。