By default, any account with read or write privileges on a table can access all rows. Row security policies let you restrict each account to only the rows it is authorized to see or modify.
This feature is available in AnalyticDB for PostgreSQL V7.0. Applying row security policies to views requires V7.0.6.0 or later.
Usage notes
Policy combination
When multiple policies apply to the same table, their USING expressions are combined with OR (permissive by default). If Policy A allows rows 1 and 2, and Policy B allows row 4, the query returns rows 1, 2, and 4.
Limits
Row security policies do not apply to privileged accounts or accounts with the
BYPASSRLSattribute.ALTER TABLE ... ENABLE ROW LEVEL SECURITYdoes not apply policies to the table owner. To enforce policies on the table owner, runALTER TABLE ... FORCE ROW LEVEL SECURITY.
For the full CREATE POLICY parameter reference, see Row Security Policies and CREATE POLICY.
Apply row security policies to a table
Prerequisites
Before you begin, make sure that you have:
A client tool connected to an AnalyticDB for PostgreSQL database. See Connect to an AnalyticDB for PostgreSQL database.
Sufficient privileges to create tables, roles, and policies.
Procedure
Create a table named
logtestand insert test data.CREATE TABLE logtest ( id serial primary key, username text, log_event text); INSERT INTO logtest VALUES (1,'report','DELETE issued'), (2,'messaging', 'Message queue purged'), (3,'messaging','Reset accounts'), (4,'report', 'Reset accounts');Create two standard accounts named
reportandmessaging, and grant the SELECT privilege onlogtestto both.CREATE ROLE report WITH LOGIN ENCRYPTED PASSWORD '111111'; CREATE ROLE messaging WITH LOGIN ENCRYPTED PASSWORD '111111'; GRANT SELECT ON logtest TO report; GRANT SELECT ON logtest TO messaging;Create a row security policy that restricts each account to rows where
usernamematches the current account name.CREATE POLICY policy_user_log ON logtest FOR ALL TO PUBLIC USING (username = current_user);Enable row-level security on
logtest. All policies take effect immediately.ImportantALTER TABLE ... ENABLE ROW LEVEL SECURITYdoes not apply policies to the table owner. To apply policies to the table owner, runALTER TABLE logtest FORCE ROW LEVEL SECURITY.ALTER TABLE logtest ENABLE ROW LEVEL SECURITY;Verify that the policy is working by querying
logtestwith each account.`report` account — only rows where
username = 'report'are returned:SELECT * FROM logtest;id| username | log_event --+----------+-------------- 1 | report | DELETE issued 4 | report | Reset accounts (2 rows)`messaging` account — only rows where
username = 'messaging'are returned:SELECT * FROM logtest;id| username | log_event --+-----------+--------------------- 2 | messaging | Message queue purged 3 | messaging | Reset accounts (2 rows)Privileged account — all rows are returned because row security policies do not apply to privileged accounts:
SELECT * FROM logtest;id| username | log_event --+-----------+--------------------- 1 | report | DELETE issued 2 | messaging | Message queue purged 3 | messaging | Reset accounts 4 | report | Reset accounts (4 rows)
Add a second policy that restricts results to rows with an even
id.CREATE POLICY policy_even_ids_only ON logtest FOR ALL TO PUBLIC USING (id % 2 = 0);Both policies are now active. Because multiple policies combine with
OR, thereportaccount sees rows that satisfy either policy — rows with an evenid(rows 2 and 4) or rows whereusername = 'report'(rows 1 and 4):SELECT * FROM logtest;id| username | log_event --+-----------+--------------------- 1 | report | DELETE issued 2 | messaging | Message queue purged 4 | report | Reset accounts (3 rows)
Apply row security policies to a view
By default, row security policies on base tables do not carry through to views. When a standard account queries a view, the view runs with the privileges of the view definer (typically a privileged account), bypassing any policies on the underlying tables. The security_invoker parameter changes this behavior so that the view runs with the privileges of the view caller instead.
Prerequisites
AnalyticDB for PostgreSQL V7.0.6.0 or later.
The view caller must have the SELECT privilege on all data exposed by the view.
Create a secure view
When creating the view, set security_invoker to make all queries run under the caller's privileges:
CREATE VIEW v1 WITH (security_invoker) AS SELECT * FROM logtest;To understand why this matters, compare the behavior without and with security_invoker.
Without `security_invoker` — the report account sees all rows, because the view runs under the definer's (privileged) account:
CREATE VIEW v1 AS SELECT * FROM logtest;
GRANT SELECT ON v1 TO report;
-- Queried by the report account:
SELECT * FROM v1;id| username | log_event
--+-----------+---------------------
1 | report | DELETE issued
2 | messaging | Message queue purged
3 | messaging | Reset accounts
4 | report | Reset accounts
(4 rows)With `security_invoker` — the report account sees only its authorized rows, because the view now runs under the caller's privileges:
-- Queried by the report account:
SELECT * FROM v1;id| username | log_event
--+-----------+---------------------
1 | report | DELETE issued
2 | messaging | Message queue purged
4 | report | Reset accounts
(3 rows)Enable or disable security invoker on an existing view
-- Enable row security.
ALTER VIEW v1 SET (security_invoker = on);
-- Disable row security.
ALTER VIEW v1 SET (security_invoker = off);Apply row security policies to a materialized view
Row security policies can be applied to both standard materialized views and real-time materialized views. The configuration steps are the same as for regular tables.
Create a materialized view
mv_logtestbased onlogtestand grant the SELECT privilege to thereportaccount.CREATE MATERIALIZED VIEW mv_logtest AS SELECT * FROM logtest; GRANT SELECT ON mv_logtest TO report;Verify the starting state. The
reportaccount currently sees all rows because no policy is active:SELECT * FROM mv_logtest;id | username | log_event ----+-----------+---------------------- 2 | messaging | Message queue purged 3 | messaging | Reset accounts 4 | report | Reset accounts 1 | report | DELETE issued (4 rows)Create a row security policy that restricts each account to rows where
usernamematches the current account name.CREATE POLICY policy_user_log ON mv_logtest FOR ALL TO PUBLIC USING (username = current_user);Enable row-level security on
mv_logtest.ALTER MATERIALIZED VIEW ... ENABLE ROW LEVEL SECURITYdoes not apply policies to the view owner. To apply policies to the view owner, runALTER MATERIALIZED VIEW mv_logtest FORCE ROW LEVEL SECURITY. Multiple policies can be configured for the same materialized view. Policies apply to both standard materialized views and real-time materialized views.ALTER MATERIALIZED VIEW mv_logtest ENABLE ROW LEVEL SECURITY;Verify that the policy is working. The
reportaccount now sees only its authorized rows:SELECT * FROM mv_logtest;id| username | log_event --+----------+-------------- 1 | report | DELETE issued 4 | report | Reset accounts (2 rows)