Row security policies

You can apply row security policies to a table. These policies determine, on a per-user basis, which rows can be processed. You can create a row security policy for specific commands like SELECT, INSERT, UPDATE, and DELETE, or specify it for ALL commands. This feature is also known as row-level security.

Connect to the database as the postgres user and create a table for examples. You can use psql for this:

$ psql -h 10.92.6.36 -p 5432 -U postgres postgres

In the code above, 10.92.6.36 is the server address, 5432 is the port for connections, -U postgres is a user name, and postgres is the database name.

CREATE TABLE users (
user_id serial PRIMARY KEY,
user_name  VARCHAR NOT NULL,
pwhash VARCHAR,
real_name  VARCHAR NOT NULL
);

Insert data to the table:

INSERT INTO users (user_name, pwhash, real_name)
    VALUES
   ('james', 'xxx', 'James Brown'),
   ('mary', 'xxx', 'Mary Smith'),
   ('alice', 'xxx', 'Alice Gray');

Create roles and use the GRANT command to define their access privileges on the users table:

CREATE ROLE james WITH LOGIN PASSWORD 'password1';
GRANT ALL ON users TO james;

CREATE ROLE mary WITH LOGIN PASSWORD 'password2';
GRANT ALL ON users TO mary;

Now users james and mary have ALL privileges on the users table.

Enable row security

To enable row security, execute the ALTER TABLE command with the ENABLE ROW LEVEL SECURITY parameter.

ALTER TABLE users ENABLE ROW LEVEL SECURITY;

When row security is enabled on a table, access to the table for selecting and modifying rows must be allowed by a row security policy. If no policy is defined for a table, the default deny policy is applied: no rows are visible or can be modified. Operations that are applied to the whole table, for example, TRUNCATE, REFERENCES, are not subject to row security.

Superusers and roles with the BYPASSRLS attribute always bypass the row security system. Table owners are also not affected by row security, but they can enable it for themselves with the ALTER TABLE …​ FORCE ROW LEVEL SECURITY command.

Reconnect to the database as the user james:

$ psql -h 10.92.6.36 -p 5432 -U james postgres

If you try to select rows from the users table, you will get the following result:

 SELECT * FROM users;
 user_id | user_name | pwhash | real_name
---------+-----------+--------+-----------
(0 rows)

The user james cannot access table data because row security is enabled and no row security policy is created.

NOTE
Only a table owner can enable and disable row security and add policies to a table.

Manage row security policies

Row security policies can be specific to commands, or to roles, or both. A policy can be specified to apply to ALL commands, or to SELECT, INSERT, UPDATE, or DELETE. Multiple roles can be assigned to a current policy. See CREATE POLICY for details.

PostgreSQL also applies standard role membership and inheritance rules to row security policies.

Each policy has a name. Multiple policies can be defined for a single table. Policies are table-specific, each policy for a table must have a unique name. Different tables can have policies with the same name.

Reconnect to the database as the postgres user and define the following row security policy:

$ psql -h 10.92.6.36 -p 5432 -U postgres postgres
CREATE POLICY policy1 ON users FOR ALL TO PUBLIC USING (user_name=current_user);

This policy allows all roles to execute all commands if the particular value from the user_name column of the users table is equal to the current user name.

PUBLIC is used instead of a role name and applies the policy to all roles.

The USING expression is any SQL conditional expression returning a boolean value.

According to this policy, the users james and mary created above can manipulate rows that contain information about each of them.

Reconnect to the database as james and select data:

$ psql -h 10.92.6.36 -p 5432 -U james postgres
 SELECT * FROM users;

The result:

 user_id | user_name | pwhash |  real_name
---------+-----------+--------+-------------
       1 | james     | xxx    | James Brown

Reconnect to the database as mary and select data:

$ psql -h 10.92.6.36 -p 5432 -U mary postgres
 SELECT * FROM users;

The result:

user_id | user_name | pwhash | real_name
--------+-----------+--------+-----------
      2 | mary      | xxx    | Mary Smith

Reconnect to the database as the postgres user, create a new user alice and add a new policy:

$ psql -h 10.92.6.36 -p 5432 -U postgres postgres
CREATE ROLE alice WITH LOGIN PASSWORD 'password3';
GRANT ALL ON users TO alice;

CREATE POLICY policy2 ON users TO alice USING (true) WITH CHECK (true);

The WITH CHECK expression should return true to allow a user to insert and update rows.

This policy allows alice all operations on all rows from the table.

Reconnect to the database as alice and check the result:

$ psql -h 10.92.6.36 -p 5432 -U alice postgres
DELETE FROM users WHERE user_id=1;

SELECT * FROM users;

The result:

 user_id | user_name | pwhash |  real_name
---------+-----------+--------+-------------
       2 | mary      | xxx    | Mary Smith
       3 | alice     | xxx    | Alice Gray

You can also use the ALTER POLICY command to update a policy. The following code renames policy1 to policy_for_users:

ALTER POLICY policy1 ON users RENAME TO policy_for_users;

The DROP POLICY command deletes a policy:

DROP POLICY policy_for_users ON users;

Disable row security

To disable row security, execute the ALTER TABLE command with the DISABLE ROW LEVEL SECURITY parameter.

ALTER TABLE users DISABLE ROW LEVEL SECURITY;
Found a mistake? Seleсt text and press Ctrl+Enter to report it