diff options
author | Stephen Frost <sfrost@snowman.net> | 2014-09-24 16:32:22 -0400 |
---|---|---|
committer | Stephen Frost <sfrost@snowman.net> | 2014-09-24 16:32:22 -0400 |
commit | 6550b901fe7c47c03775400e0c790c6c1234a017 (patch) | |
tree | f67c2cabd58ef765f0bcaf4307d73d7eac51e5fc /doc/src | |
parent | 3f6f9260e308a331e6809d5309b17d1613ff900f (diff) | |
download | postgresql-6550b901fe7c47c03775400e0c790c6c1234a017.tar.gz postgresql-6550b901fe7c47c03775400e0c790c6c1234a017.zip |
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.
Diffstat (limited to 'doc/src')
-rw-r--r-- | doc/src/sgml/catalogs.sgml | 11 | ||||
-rw-r--r-- | doc/src/sgml/config.sgml | 4 | ||||
-rw-r--r-- | doc/src/sgml/ddl.sgml | 168 | ||||
-rw-r--r-- | doc/src/sgml/ref/alter_table.sgml | 2 | ||||
-rw-r--r-- | doc/src/sgml/ref/create_policy.sgml | 2 | ||||
-rw-r--r-- | doc/src/sgml/ref/pg_dump.sgml | 17 | ||||
-rw-r--r-- | doc/src/sgml/ref/pg_restore.sgml | 23 |
7 files changed, 218 insertions, 9 deletions
diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml index 76d64050618..a6ca290cb3d 100644 --- a/doc/src/sgml/catalogs.sgml +++ b/doc/src/sgml/catalogs.sgml @@ -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> diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index 70e47aaa3a1..949443931cd 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -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> diff --git a/doc/src/sgml/ddl.sgml b/doc/src/sgml/ddl.sgml index c07f5a203dd..e5ee5910513 100644 --- a/doc/src/sgml/ddl.sgml +++ b/doc/src/sgml/ddl.sgml @@ -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> diff --git a/doc/src/sgml/ref/alter_table.sgml b/doc/src/sgml/ref/alter_table.sgml index 1b35756c295..b5ef09e6a4a 100644 --- a/doc/src/sgml/ref/alter_table.sgml +++ b/doc/src/sgml/ref/alter_table.sgml @@ -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">. diff --git a/doc/src/sgml/ref/create_policy.sgml b/doc/src/sgml/ref/create_policy.sgml index c6599eda1c0..3c5bdc69cdc 100644 --- a/doc/src/sgml/ref/create_policy.sgml +++ b/doc/src/sgml/ref/create_policy.sgml @@ -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 diff --git a/doc/src/sgml/ref/pg_dump.sgml b/doc/src/sgml/ref/pg_dump.sgml index eabdc62f820..c92c6eef5d3 100644 --- a/doc/src/sgml/ref/pg_dump.sgml +++ b/doc/src/sgml/ref/pg_dump.sgml @@ -688,6 +688,23 @@ PostgreSQL documentation </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> <para> diff --git a/doc/src/sgml/ref/pg_restore.sgml b/doc/src/sgml/ref/pg_restore.sgml index 4bc30ce679b..9f8dc00480c 100644 --- a/doc/src/sgml/ref/pg_restore.sgml +++ b/doc/src/sgml/ref/pg_restore.sgml @@ -491,6 +491,29 @@ </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> <para> |