0

I have tables with enabled row-level-security and the relevant policies in place - working really well.

My problem is that sometimes, based on some conditions, I want to bypass a policy for a specific statement during a function execution.

something like:

...
statement 1
statement 2
if (some cond) then
   disable rls temporarily 
   statement 3 -- mostly delete rows the user can't normally see
   enable rls
else
   statement 3
end if

The way I've implemented it is by creating a function check_cond which returns a boolean evaluating some cond and created an additional select policy which calls this check_cond.

It works - but the actual problem is that the query select * from tab now looks like this: select * from tab where <original policy condition> or check_cond()

This or check_cond() causes postges to always do a full table scan since it cannot evaluate the result pre-planning.

If I were able to write "dynamic" code in the policy I would have been able to add/remove conditions based on the value of check_cond() but as far as I know it's not possible.

Any smart way which would allow me to temporarily disable rls or dynamically add conditions without sacrificing performance?

Thanks.

Pyrocks
  • 401
  • 3
  • 14

1 Answers1

1

The easiest way would be to have a SECURITY DEFINER function owned by a superuser which runs:

ALTER ROLE someuser BYPASSRLS;

where someuser is the user that runs the SQL statements.

Afterwards, you can re-enable it in the same way.

But that's pretty insecure, because nothing keeps the user from calling theses functions at other times.

A better way would be to define a security definer function owned by a user with BYPASSRLS that does the deletes for you.

Note: for security reasons, always SET search_path when you define a SECURITY DEFINER function.

Laurenz Albe
  • 209,280
  • 17
  • 206
  • 263
  • "A better way would be to define a security definer function owned by a user with BYPASSRLS that does the deletes for you." - security definer is the magic word I was looking for - this should do the trick - thanks! Will accept once I get it working – Pyrocks Feb 19 '20 at 14:15