1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-13 07:41:39 +03:00

Add support for restrictive RLS policies

We have had support for restrictive RLS policies since 9.5, but they
were only available through extensions which use the appropriate hooks.
This adds support into the grammer, catalog, psql and pg_dump for
restrictive RLS policies, thus reducing the cases where an extension is
necessary.

In passing, also move away from using "AND"d and "OR"d in comments.
As pointed out by Alvaro, it's not really appropriate to attempt
to make verbs out of "AND" and "OR", so reword those comments which
attempted to.

Reviewed By: Jeevan Chalke, Dean Rasheed
Discussion: https://postgr.es/m/20160901063404.GY4028@tamriel.snowman.net
This commit is contained in:
Stephen Frost
2016-12-05 15:50:55 -05:00
parent 2bbdc6875d
commit 093129c9d9
21 changed files with 667 additions and 152 deletions

View File

@ -4747,6 +4747,13 @@
or <literal>*</> for all</entry>
</row>
<row>
<entry><structfield>polpermissive</structfield></entry>
<entry><type>boolean</type></entry>
<entry></entry>
<entry>Is the policy permissive or restrictive?</entry>
</row>
<row>
<entry><structfield>polroles</structfield></entry>
<entry><type>oid[]</type></entry>
@ -8437,6 +8444,12 @@ SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx
<entry><literal><link linkend="catalog-pg-policy"><structname>pg_policy</structname></link>.polname</literal></entry>
<entry>Name of policy</entry>
</row>
<row>
<entry><structfield>polpermissive</structfield></entry>
<entry><type>text</type></entry>
<entry></entry>
<entry>Is the policy permissive or restrictive?</entry>
</row>
<row>
<entry><structfield>roles</structfield></entry>
<entry><type>name[]</type></entry>

View File

@ -1599,9 +1599,11 @@ REVOKE ALL ON accounts FROM PUBLIC;
<para>
When multiple policies apply to a given query, they are combined using
<literal>OR</literal>, so that a row is accessible if any policy allows
it. This is similar to the rule that a given role has the privileges
of all roles that they are a member of.
either <literal>OR</literal> (for permissive policies, which are the
default) or using <literal>AND</literal> (for restrictive policies).
This is similar to the rule that a given role has the privileges
of all roles that they are a member of. Permissive vs. restrictive
policies are discussed further below.
</para>
<para>
@ -1761,6 +1763,56 @@ ERROR: permission denied for relation passwd
-- Alice can change her own password; RLS silently prevents updating other rows
postgres=&gt; update passwd set pwhash = 'abc';
UPDATE 1
</programlisting>
<para>
All of the policies constructed thus far have been permissive policies,
meaning that when multiple policies are applied they are combined using
the "OR" boolean operator. While permissive policies can be constructed
to only allow access to rows in the intended cases, it can be simpler to
combine permissive policies with restrictive policies (which the records
must pass and which are combined using the "AND" boolean operator).
Building on the example above, we add a restrictive policy to require
the administrator to be connected over a local unix socket to access the
records of the passwd table:
</para>
<programlisting>
CREATE POLICY admin_local_only ON passwd AS RESTRICTIVE TO admin
USING (pg_catalog.inet_client_addr() IS NULL);
</programlisting>
<para>
We can then see that an administrator connecting over a network will not
see any records, due to the restrictive policy:
</para>
<programlisting>
=&gt; SELECT current_user;
current_user
--------------
admin
(1 row)
=&gt; select inet_client_addr();
inet_client_addr
------------------
127.0.0.1
(1 row)
=&gt; SELECT current_user;
current_user
--------------
admin
(1 row)
=&gt; TABLE passwd;
user_name | pwhash | uid | gid | real_name | home_phone | extra_info | home_dir | shell
-----------+--------+-----+-----+-----------+------------+------------+----------+-------
(0 rows)
=&gt; UPDATE passwd set pwhash = NULL;
UPDATE 0
</programlisting>
<para>

View File

@ -35,7 +35,12 @@ ALTER POLICY <replaceable class="parameter">name</replaceable> ON <replaceable c
<para>
<command>ALTER POLICY</command> changes the definition of an existing
row-level security policy.
row-level security policy. Note that <command>ALTER POLICY</command>
only allows the set of roles to which the policy applies and the
<literal>USING</literal> and <literal>WITH CHECK</literal> expressions to
be modified. To change other properties of a policy, such as the command
to which it applies or whether it is permissive or restrictive, the policy
must be dropped and recreated.
</para>
<para>

View File

@ -22,6 +22,7 @@ PostgreSQL documentation
<refsynopsisdiv>
<synopsis>
CREATE POLICY <replaceable class="parameter">name</replaceable> ON <replaceable class="parameter">table_name</replaceable>
[ AS { PERMISSIVE | RESTRICTIVE } ]
[ FOR { ALL | SELECT | INSERT | UPDATE | DELETE } ]
[ TO { <replaceable class="parameter">role_name</replaceable> | PUBLIC | CURRENT_USER | SESSION_USER } [, ...] ]
[ USING ( <replaceable class="parameter">using_expression</replaceable> ) ]
@ -119,6 +120,33 @@ CREATE POLICY <replaceable class="parameter">name</replaceable> ON <replaceable
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">PERMISSIVE</replaceable></term>
<listitem>
<para>
Specify that the policy is to be created as a permissive policy.
All permissive policies which are applicable to a given query will
be combined together using the boolean "OR" operator. By creating
permissive policies, administrators can add to the set of records
which can be accessed. Policies are PERMISSIVE by default.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">RESTRICTIVE</replaceable></term>
<listitem>
<para>
Specify that the policy is to be created as a restrictive policy.
All restrictive policies which are applicable to a given query will
be combined together using the boolean "AND" operator. By creating
restrictive policies, administrators can reduce the set of records
which can be accessed as all restrictive policies must be passed for
each record.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">command</replaceable></term>
<listitem>
@ -390,6 +418,16 @@ CREATE POLICY <replaceable class="parameter">name</replaceable> ON <replaceable
keys) instead of keys with external meanings.
</para>
<para>
Note that there needs to be at least one permissive policy to grant
access to records before restrictive policies can be usefully used to
reduce that access. If only restrictive policies exist, then no records
will be accessible. When a mix of permissive and restrictive policies
are present, a record is only accessible if at least one of the
permissive policies passes, in addition to all the restrictive
policies.
</para>
<para>
Generally, the system will enforce filter conditions imposed using
security policies prior to qualifications that appear in user queries,