连接到 PostgreSQL 时自动调用“SET ROLE”

pat*_*pat 8 postgresql role

首先是简短版本:

是否可以SET ROLE通过特定角色自动调用新的 PostgreSQL 数据库连接,无论是通过连接角色上的配置(使用ALTER ROLE),还是通过连接 URI 末尾的选项?


更长,结合上下文:

我正在设置一个 Web 应用程序以使用轮换数据库凭据(因此,有多种角色在发挥作用)。但是,这些凭据还用于对数据库进行修改(通过 Rails 迁移),这意味着表将由不打算长期存在的角色拥有。

我可以修改轮换凭据,以便它们继承父角色(本身无法登录),然后通过SET ROLE所有数据库修改都归父角色所有,而不是短期子角色。这解决了所有权问题,但它需要调用每个连接SET ROLE parent- 不太可行。

因此,我需要某种方法来确保每个子连接始终在父角色的上下文中运行。这可能吗?

Mik*_*ika 7

正如@phemmer在这里回答的那样,您可以使用set如下命令:

ALTER ROLE child_role SET ROLE parent_role;
Run Code Online (Sandbox Code Playgroud)

这样,登录时child_role自动更改为。parent_role

前提是child_role属于parent_role.

评论后编辑:

对象创建:

[postgres@server ~]$ psql postgres 
psql (13.1)
Type "help" for help.

postgres=# CREATE ROLE parent_role NOLOGIN NOSUPERUSER NOCREATEDB NOCREATEROLE;
CREATE ROLE
postgres=# CREATE ROLE child_role LOGIN NOSUPERUSER NOCREATEDB NOCREATEROLE IN ROLE parent_role;
CREATE ROLE
postgres=# CREATE DATABASE my_database OWNER parent_role;
CREATE DATABASE
Run Code Online (Sandbox Code Playgroud)

我们创建my_schema之前的设置:

[postgres@server ~]$ psql my_database -U child_role -c 'CREATE SCHEMA my_schema'
CREATE SCHEMA
[postgres@server ~]$ psql my_database -c "\dn+ my_schema"
                     List of schemas
   Name    |   Owner    | Access privileges | Description 
-----------+------------+-------------------+-------------
 my_schema | child_role |                   | 
 (1 row)
Run Code Online (Sandbox Code Playgroud)

正如我们所看到的,所有者是child_user

现在我们修改用户设置。

my_database=# ALTER ROLE child_role SET ROLE parent_role;
ALTER ROLE
Run Code Online (Sandbox Code Playgroud)

我们创建my_schema2架构:

[postgres@server ~]$ psql my_database -U child_role -c 'CREATE SCHEMA my_schema2'
CREATE SCHEMA
[postgres@server ~]$ psql my_database -c "\dn+ my_schema*"
                             List of schemas
    Name    |    Owner    |  Access privileges   |      Description       
------------+-------------+----------------------+------------------------
 my_schema  | child_role  |                      | 
 my_schema2 | parent_role |                      | 
(3 rows)
Run Code Online (Sandbox Code Playgroud)

my_schema2parent_child无需显式键入命令即可自动拥有SET ROLE

注意: 文档指定它仅在登录时发生

SET ROLE 不处理角色的 ALTER ROLE 设置指定的会话变量;这仅在登录期间发生。


Nei*_*gan 1

这不是 PostgreSQL 自己能做到的事情

您想在连接池中执行此操作

从池中获得连接后,立即调用SET ROLE

释放与池的连接后,立即调用RESET ROLE

我不是 Ruby 专家,所以无法为您提供太多帮助,但在 Java 中您可以这样做:

public class SetRoleJdbcInterceptor extends JdbcInterceptor {

    @Override
    public void reset(ConnectionPool connectionPool, PooledConnection pooledConnection) {

        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

        if(authentication != null) {
            try {

                /* 
                  use OWASP's ESAPI to encode the username to avoid SQL Injection. Can't use parameters with SET ROLE. Need to write PG codec.

                  Or use a whitelist-map approach
                */
                String username = ESAPI.encoder().encodeForSQL(MY_CODEC, authentication.getName());

                Statement statement = pooledConnection.getConnection().createStatement();
                statement.execute("set role \"" + username + "\"");
                statement.close();
            } catch(SQLException exp){
                throw new RuntimeException(exp);
            }
        }
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        if("close".equals(method.getName())){
            Statement statement = ((Connection)proxy).createStatement();
            statement.execute("reset role");
            statement.close();
        }

        return super.invoke(proxy, method, args);
    }
}
Run Code Online (Sandbox Code Playgroud)