I'm tying to grasp the best way to use the new row level security feature in a multi-tenant database that supports a web application.
Currently, the application has a few different ROLEs available, depending on the action it is attempting to take.
Once the application makes a connection using its own ROLE, the application passes authentication parameters (provided by the user) into different functions that filter out rows based on the user supplied authentication parameters. The system is designed to work with thousands of users and it seems to work; however, it's defiantly clunky (and slow).
It seems that if I wanted to use the new row level security feature I would need to create a new ROLE for each real world user (not just for the web application) to access the database.
Is this correct? and if so, is it a good idea to create thousands of ROLEs in the database?
Update from a_horse_with_no_name's link in the comments (thanks, that thread is spot on):
CREATE USER application;
CREATE TABLE t1 (id int primary key, f1 text, app_user text);
INSERT INTO t1 VALUES(1,'a','bob');
INSERT INTO t1 VALUES(2,'b','alice');
ALTER TABLE t1 ENABLE ROW LEVEL SECURITY;
CREATE POLICY P ON t1 USING (app_user = current_setting('app_name.app_user'));
GRANT SELECT ON t1 TO application;
SET SESSION AUTHORIZATION application;
SET app_name.app_user = 'bob';
SELECT * FROM t1;
id | f1 | app_user
----+----+----------
1 | a | bob
(1 row)
SET app_name.app_user = 'alice';
SELECT * FROM t1;
id | f1 | app_user
----+----+----------
2 | b | alice
(1 row)
SET app_name.app_user = 'none';
SELECT * FROM t1;
id | f1 | app_user
----+----+----------
(0 rows)
Now, I'm confused by current_setting('app_name.app_user')
as I was under the impression this was only for configuration parameters... where is app_name
defined?
current_setting('app_name.app_user')
will result in an error if the parameter has not been defined before.To prevent that, you can define a dummy value inpostgresql.conf
– Pangenesis