Re: [PATCH] Add reloption for views to enable RLS

From: Laurenz Albe <laurenz(dot)albe(at)cybertec(dot)at>
To: Christoph Heiss <christoph(dot)heiss(at)cybertec(dot)at>, pgsql-hackers(at)postgresql(dot)org
Cc: Hans-Jürgen Schönig <hs(at)cybertec(dot)at>
Subject: Re: [PATCH] Add reloption for views to enable RLS
Date: 2022-01-20 14:20:52
Message-ID: 69ed8492b4e54baae1f550e9358a4f05e7b0feb6.camel@cybertec.at
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

On Tue, 2022-01-18 at 16:16 +0100, Christoph Heiss wrote:
> > I think that this should be a boolean reloption, for example "security_definer".
> > If unset or set to "off", you would get the current behavior.
>
> A boolean option would have been indeed the better choice, I agree.
> I haven't though of any specific other values for this enum, it was
> rather a decision following a off-list discussion.
>
> I've changed the option to be boolean and renamed it to
> "security_invoker". This puts it in line with how other systems (e.g.
> MySQL) name their equivalent feature, so I think this should be an
> appropriate choice.
>
>
> > Also, I don't think that the documentation on
> > RLS policies is the correct place for this.  It should be on a page dedicated to views
> > or permissions.
> >
> > The CREATE VIEW page already has a paragraph about this, starting with
> > "Access to tables referenced in the view is determined by permissions of the view owner."
> > This looks like the best place to me (and it would need to be adapted anyway).
> It makes sense to put it there, thanks for the pointer! I wasn't really
> that sure where to put the documentation to start with, and this seems
> like a more appropriate place.

I gave the new patch a spin, and got a surprising result:

CREATE TABLE tab (id integer);

CREATE ROLE duff LOGIN;

CREATE ROLE jock LOGIN;

GRANT INSERT, UPDATE, DELETE ON tab TO jock;

GRANT SELECT ON tab TO duff;

CREATE VIEW v WITH (security_invoker = TRUE) AS SELECT * FROM tab;

ALTER VIEW v OWNER TO jock;

GRANT SELECT, INSERT, UPDATE, DELETE ON v TO duff;

SET SESSION AUTHORIZATION duff;

SELECT * FROM v;
id
════
(0 rows)

That's ok, "duff" has permissions to read "tab".

INSERT INTO v VALUES (1);
INSERT 0 1

Huh? "duff" has no permission to insert into "tab"!

RESET SESSION AUTHORIZATION;

ALTER VIEW v SET (security_invoker = FALSE);

SET SESSION AUTHORIZATION duff;

SELECT * FROM v;
ERROR: permission denied for table tab

As expected.

INSERT INTO v VALUES (1);
INSERT 0 1

As expected.

About the documentation:

--- a/doc/src/sgml/ref/create_view.sgml
+++ b/doc/src/sgml/ref/create_view.sgml
+ <varlistentry>
+ <term><literal>security_invoker</literal> (<type>boolean</type>)</term>
+ <listitem>
+ <para>
+ If this option is set, it will cause all access to the underlying
+ tables to be checked as referenced by the invoking user, rather than
+ the view owner. This will only take effect when row level security is
+ enabled on the underlying tables (using <link linkend="sql-altertable">
+ <command>ALTER TABLE ... ENABLE ROW LEVEL SECURITY</command></link>).
+ </para>

Why should this *only* take effect if (not "when") RLS is enabled?
The above test shows that there is an effect even without RLS.

+ <para>This option can be changed on existing views using <link
+ linkend="sql-alterview"><command>ALTER VIEW</command></link>. See
+ <xref linkend="ddl-rowsecurity"/> for more details on row level security.
+ </para>

I don't think that it is necessary to mention that this can be changed with
ALTER VIEW - all storage parameters can be. I guess you copied that from
the "check_option" documentation, but I would say it need not be mentioned
there either.

+ <para>
+ If the <firstterm>security_invoker</firstterm> option is set on the view,
+ access to tables is determined by permissions of the invoking user, rather
+ than the view owner. This can be used to provide stricter permission
+ checking to the underlying tables than by default.
</para>

Since you are talking about use cases here, RLS might deserve a mention.

--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
+ {
+ {
+ "security_invoker",
+ "View subquery in invoked within the current security context.",
+ RELOPT_KIND_VIEW,
+ AccessExclusiveLock
+ },
+ false
+ },

That doesn't seem to be proper English.

Yours,
Laurenz Albe

In response to

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Alvaro Herrera 2022-01-20 14:26:13 Re: row filtering for logical replication
Previous Message James Coleman 2022-01-20 14:05:40 Re: Document atthasmissing default optimization avoids verification table scan