mirror of
https://github.com/postgres/postgres.git
synced 2025-07-27 12:41:57 +03:00
Code review for row security.
Buildfarm member tick identified an issue where the policies in the relcache for a relation were were being replaced underneath a running query, leading to segfaults while processing the policies to be added to a query. Similar to how TupleDesc RuleLocks are handled, add in a equalRSDesc() function to check if the policies have actually changed and, if not, swap back the rsdesc field (using the original instead of the temporairly built one; the whole structure is swapped and then specific fields swapped back). This now passes a CLOBBER_CACHE_ALWAYS for me and should resolve the buildfarm error. In addition to addressing this, add a new chapter in Data Definition under Privileges which explains row security and provides examples of its usage, change \d to always list policies (even if row security is disabled- but note that it is disabled, or enabled with no policies), rework check_role_for_policy (it really didn't need the entire policy, but it did need to be using has_privs_of_role()), and change the field in pg_class to relrowsecurity from relhasrowsecurity, based on Heikki's suggestion. Also from Heikki, only issue SET ROW_SECURITY in pg_restore when talking to a 9.5+ server, list Bypass RLS in \du, and document --enable-row-security options for pg_dump and pg_restore. Lastly, fix a number of minor whitespace and typo issues from Heikki, Dimitri, add a missing #include, per Peter E, fix a few minor variable-assigned-but-not-used and resource leak issues from Coverity and add tab completion for role attribute bypassrls as well.
This commit is contained in:
@ -1941,8 +1941,9 @@
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><structfield>relhasrowsecurity</structfield></entry>
|
||||
<entry><structfield>relrowsecurity</structfield></entry>
|
||||
<entry><type>bool</type></entry>
|
||||
<entry></entry>
|
||||
<entry>
|
||||
True if table has row-security enabled; see
|
||||
<link linkend="catalog-pg-rowsecurity"><structname>pg_rowsecurity</structname></link> catalog
|
||||
@ -5415,7 +5416,7 @@
|
||||
|
||||
<note>
|
||||
<para>
|
||||
<literal>pg_class.relhasrowsecurity</literal>
|
||||
<literal>pg_class.relrowsecurity</literal>
|
||||
True if the table has row-security enabled.
|
||||
Must be true if the table has a row-security policy in this catalog.
|
||||
</para>
|
||||
@ -9228,10 +9229,10 @@ SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx
|
||||
<entry>True if table has (or once had) triggers</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><structfield>hasrowsecurity</structfield></entry>
|
||||
<entry><structfield>rowsecurity</structfield></entry>
|
||||
<entry><type>boolean</type></entry>
|
||||
<entry><literal><link linkend="catalog-pg-class"><structname>pg_class</structname></link>.relhasrowsecurity</literal></entry>
|
||||
<entry>True if table has row security enabled</entry>
|
||||
<entry><literal><link linkend="catalog-pg-class"><structname>pg_class</structname></link>.relrowsecurity</literal></entry>
|
||||
<entry>True if row security is enabled on the table</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
|
@ -5457,9 +5457,9 @@ COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv;
|
||||
|
||||
<para>
|
||||
The allowed values of <varname>row_security</> are
|
||||
<literal>on</> (apply normally- not to superuser or table owner),
|
||||
<literal>on</> (apply normally - not to superuser or table owner),
|
||||
<literal>off</> (fail if row security would be applied), and
|
||||
<literal>force</> (apply always- even to superuser and table owner).
|
||||
<literal>force</> (apply always - even to superuser and table owner).
|
||||
</para>
|
||||
|
||||
<para>
|
||||
|
@ -1508,6 +1508,174 @@ REVOKE ALL ON accounts FROM PUBLIC;
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="ddl-rowsecurity">
|
||||
<title>Row Security Policies</title>
|
||||
|
||||
<indexterm zone="ddl-rowsecurity">
|
||||
<primary>rowsecurity</primary>
|
||||
</indexterm>
|
||||
|
||||
<indexterm zone="ddl-rowsecurity">
|
||||
<primary>rls</primary>
|
||||
</indexterm>
|
||||
|
||||
<indexterm>
|
||||
<primary>policies</primary>
|
||||
<see>policy</see>
|
||||
</indexterm>
|
||||
|
||||
<indexterm zone="ddl-rowsecurity">
|
||||
<primary>POLICY</primary>
|
||||
</indexterm>
|
||||
|
||||
<para>
|
||||
In addition to the <xref linkend="ddl-priv"> system available through
|
||||
<xref linkend="sql-grant">, tables can have row security policies
|
||||
which limit the rows returned for normal queries and rows which can
|
||||
be added through data modification commands. By default, tables do
|
||||
not have any policies and all rows are visible and able to be added,
|
||||
subject to the regular <xref linkend="ddl-priv"> system. This is
|
||||
also known to as Row Level Security.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
When row security is enabled on a table with
|
||||
<xref linkend="sql-altertable">, all normal access to the table
|
||||
(excluding the owner) for selecting rows or adding rows must be through
|
||||
a policy. If no policy exists for the table, a default-deny policy is
|
||||
used and no rows are visible or can be added. Privileges which operate
|
||||
at the whole table level such as <literal>TRUNCATE</>, and
|
||||
<literal>REFERENCES</> are not subject to row security.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Row security policies can be specific to commands, or to roles, or to
|
||||
both. The commands available are <literal>SELECT</>, <literal>INSERT</>,
|
||||
<literal>UPDATE</>, and <literal>DELETE</>. Multiple roles can be
|
||||
assigned to a given policy and normal role membership and inheiritance
|
||||
rules apply.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
To specify which rows are visible and what rows can be added to the
|
||||
table with row security, an expression is required which returns a
|
||||
boolean result. This expression will be evaluated for each row prior
|
||||
to other conditionals or functions which are part of the query. The
|
||||
one exception to this rule are <literal>leakproof</literal> functions,
|
||||
which are guaranteed to not leak information. Two expressions may be
|
||||
specified to provide independent control over the rows which are
|
||||
visible and the rows which are allowed to be added. The expression
|
||||
is run as part of the query and with the privileges of the user
|
||||
running the query, however, security definer functions can be used in
|
||||
the expression.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Enabling and disabling row security, as well as adding policies to a
|
||||
table, is always the privilege of the owner only.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Policies are created using the <xref linkend="sql-createpolicy">
|
||||
command, altered using the <xref linkend="sql-alterpolicy"> command,
|
||||
and dropped using the <xref linkend="sql-droppolicy"> command. To
|
||||
enable and disable row security for a given table, use the
|
||||
<xref linkend="sql-altertable"> command.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The table owners and superusers bypass the row security system when
|
||||
querying a table, by default. Row security can be enabled for
|
||||
superusers and table owners by setting
|
||||
<xref linkend="guc-row-security"> to <literal>force</literal>. Any
|
||||
user can request that row security be bypassed by setting
|
||||
<xref linkend="guc-row-security"> to <literal>off</literal>. If
|
||||
the user does not have privileges to bypass row security when
|
||||
querying a given table then an error will be returned instead. Other
|
||||
users can be granted the ability to bypass the row security system
|
||||
with the <literal>BYPASSRLS</literal> role attribute. This
|
||||
attribute can only be set by a superuser.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Each policy has a name and multiple policies can be defined for a
|
||||
table. As policies are table-specific, each policy for a table must
|
||||
have a unique name. Different tables may have policies with the
|
||||
same name.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
When multiple policies apply to a given query, they are combined using
|
||||
<literal>OR</literal>, similar to how a given role has the privileges
|
||||
of all roles which they are a member of.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Referential integrity checks, such as unique or primary key constraints
|
||||
and foreign key references, will bypass row security to ensure that
|
||||
data integrity is maintained. Care must be taken when developing
|
||||
schemas and row level policies to avoid a "covert channel" leak of
|
||||
information through these referntial integrity checks.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
To enable row security for a table,
|
||||
the <command>ALTER TABLE</command> is used. For example, to enable
|
||||
row level security for the table accounts, use:
|
||||
</para>
|
||||
|
||||
<programlisting>
|
||||
-- Create the table first
|
||||
CREATE TABLE accounts (manager text, company text, contact_email text);
|
||||
ALTER TABLE accounts ENABLE ROW LEVEL SECURITY;
|
||||
</programlisting>
|
||||
|
||||
<para>
|
||||
To create a policy on the account relation to allow the managers role
|
||||
to view the rows of their accounts, the <command>CREATE POLICY</command>
|
||||
command can be used:
|
||||
</para>
|
||||
|
||||
<programlisting>
|
||||
CREATE POLICY account_managers ON accounts TO managers
|
||||
USING (manager = current_user);
|
||||
</programlisting>
|
||||
|
||||
<para>
|
||||
If no role is specified, or the special <quote>user</quote> name
|
||||
<literal>PUBLIC</literal> is used, then the policy applies to all
|
||||
users on the system. To allow all users to view their own row in
|
||||
a user table, a simple policy can be used:
|
||||
</para>
|
||||
|
||||
<programlisting>
|
||||
CREATE POLICY user_policy ON users
|
||||
USING (user = current_user);
|
||||
</programlisting>
|
||||
|
||||
<para>
|
||||
To use a different policy for rows which are being added to the
|
||||
table from those rows which are visible, the WITH CHECK clause
|
||||
can be used. This would allow all users to view all rows in the
|
||||
users table, but only modify their own:
|
||||
</para>
|
||||
|
||||
<programlisting>
|
||||
CREATE POLICY user_policy ON users
|
||||
USING (true)
|
||||
WITH CHECK (user = current_user);
|
||||
</programlisting>
|
||||
|
||||
<para>
|
||||
Row security can be disabled with the <command>ALTER TABLE</command>
|
||||
also. Note that disabling row security does not remove the
|
||||
policies which are defined on the table, they are simply ignored
|
||||
and all rows are visible and able to be added, subject to the
|
||||
normal privileges system.
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="ddl-schemas">
|
||||
<title>Schemas</title>
|
||||
|
||||
|
@ -429,7 +429,7 @@ ALTER TABLE ALL IN TABLESPACE <replaceable class="PARAMETER">name</replaceable>
|
||||
These forms control the application of row security policies belonging
|
||||
to the table. If enabled and no policies exist for the table, then a
|
||||
default-deny policy is applied. Note that policies can exist for a table
|
||||
even if row level security is disabled- in this case, the policies will
|
||||
even if row level security is disabled - in this case, the policies will
|
||||
NOT be applied and the policies will be ignored.
|
||||
See also
|
||||
<xref linkend="SQL-CREATEPOLICY">.
|
||||
|
@ -240,7 +240,7 @@ CREATE POLICY <replaceable class="parameter">name</replaceable> ON <replaceable
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry id="SQL-CREATEPOLICY-UPDATE">
|
||||
<term><literal>DELETE</></term>
|
||||
<term><literal>UPDATE</></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Using <literal>UPDATE</literal> for a policy means that it will apply
|
||||
|
@ -687,6 +687,23 @@ PostgreSQL documentation
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--enable-row-security</></term>
|
||||
<listitem>
|
||||
<para>
|
||||
This option is relevant only when dumping the contents of a table
|
||||
which has row security. By default, pg_dump will set
|
||||
<literal>ROW_SECURITY</literal> to <literal>OFF</literal>, to ensure
|
||||
that all data is dumped from the table. If the user does not have
|
||||
sufficient privileges to bypass row security, then an error is thrown.
|
||||
This parameter instructs <application>pg_dump</application> to set
|
||||
row_security to 'ON' instead, allowing the user to dump the contents
|
||||
of the table which they have access to.
|
||||
</para>
|
||||
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--exclude-table-data=<replaceable class="parameter">table</replaceable></option></term>
|
||||
<listitem>
|
||||
|
@ -490,6 +490,29 @@
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--enable-row-security</></term> <listitem>
|
||||
<para>
|
||||
This option is relevant only when restoring the contents of a table
|
||||
which has row security. By default, pg_restore will set
|
||||
<literal>ROW_SECURITY</literal> to <literal>OFF</literal>, to ensure
|
||||
that all data is restored in to the table. If the user does not have
|
||||
sufficient privileges to bypass row security, then an error is thrown.
|
||||
This parameter instructs <application>pg_restore</application> to set
|
||||
row_security to 'ON' instead, allowing the user to attempt to restore
|
||||
the contents of the table with row security enabled. This may still
|
||||
fail if the user does not have the right to insert the rows from the
|
||||
dump into the table.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Note that this option currently also requires the dump be in INSERT
|
||||
format as COPY TO does not support row security.
|
||||
</para>
|
||||
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--if-exists</option></term>
|
||||
<listitem>
|
||||
|
Reference in New Issue
Block a user