Column-level security
Column-level security allows you to create a security policy for table columns allowing or restricting the user to view a specific column or set of columns.
This policy allows blocking access to the columns, including such operations as SELECT
.
The article provides an example of creating a column-level security policy to delimit user access.
You can implement column-level security in three methods:
-
table view;
-
column-level permissions;
-
column-level encryption.
Preparing steps
-
Get access to the ADPG server console by logging in with a trusted account.
-
Switch to the user
postgres
.$ sudo su - postgres
-
Go to the ADPG interactive terminal.
$ psql
-
Create the table
demo2
.CREATE TABLE demo2 ( numb int, role text, name text, param int );
Result:postgres=# CREATE TABLE demo 2 ( numb int, role text, name text, perm int ); CREATE TABLE
-
Add data to the first row.
INSERT INTO demo2 VALUES (1, 'user', 'student01', 1 );
Result:postgres=# INSERT INTO demo2 VALUES (1, 'user', 'student01', 1 ); INSERT 0 1
-
Add data to the second row.
INSERT INTO demo2 VALUES (2, 'non-user', 'student02', 0 );
Result:postgres=# INSERT INTO demo 2 VALUES (2, 'non-user', 'student02', 0 ); INSERT 0 1
-
Output data from the table.
SELECT * FROM demo2;
Result:postgres=# SELECT * FROM demo2; number | role | name | perm ------+----------+-----------+------ 1 | user | student01 | 1 2 | non-user | student02 | 0 (2 rows)
-
Create the
teacher
user.CREATE ROLE teacher;
Result:postgres=# CREATE ROLE teacher; CREATE ROLE
After trying to establish a session by a user, the following error might appear in the console:
connection to server on socket "/tmp/.s.PGSQL.5432" failed: FATAL: role "teacher" isn't permitted to log in
Change the attributes of this role and grant the necessary privilege:
ALTER ROLE teacher WITH LOGIN;
postgres=# ALTER ROLE teacher WITH LOGIN; ALTER ROLE
To make queries to the demo2
table, for example, SELECT
, run the query:
GRANT SELECT ON demo2 TO teacher;
postgres=# GRANT SELECT ON demo2 TO teacher; GRANT
Table view method
The table view method allows you to display only the columns available to the user and provide the view name to the user instead of the table name.
The teacher
user was created in the Preparing steps section.
In this example, the user shouldn’t see the perm
column in the table.
To do this, revoke the teacher
user’s access to the table and create a view with available columns.
-
Revoke access to the table.
REVOKE SELECT ON demo2 FROM teacher;
Result:postgres=# REVOKE SELECT ON demo2 FROM teacher; REVOKE
-
Create the table view
demo2
with available columns.CREATE VIEW demo2_info AS SELECT numb, role, name FROM demo2;
Result:postgres=# CREATE VIEW demo2_info AS SELECT numb, role, name FROM demo2; CREATE VIEW
-
Grant accesses to the table view.
GRANT SELECT ON demo2_info TO teacher;
Result:postgres=# GRANT SELECT ON demo2_info TO teacher; GRANT
-
Connect to the database as the
teacher
user.\c postgres teacher
Result:postgres=# \c postgres teacher You are now connected to database "postgres" as user "teacher".
-
Output data from the table.
SELECT * FROM demo2;
Result:postgres=> SELECT * FROM demo2; ERROR: permission denied for table demo2
-
Output data from the table view.
SELECT * FROM demo2_info;
Result:postgres=> SELECT * FROM demo2_info; numb | role | name ------+----------+----------- 1 | user | student01 2 | non-user | student02 (2 rows)
As you can see, the demo2
table isn’t available to the teacher
user.
When executing the SELECT
query to the created demo2_info
view, the perm
column is unavailable to the teacher
user.
Column-level permissions method
This method is based on granting access only to certain columns of the table for dedicated users.
In the Table view method section the teacher
user was denied access to the demo2
table.
Only the specified columns will be available, but when using the method column-level permissions, the teacher user is granted the right to access the table.
-
Grant the
teacher
user the right to access thenumb
,role
, andname
columns of thedemo2
table.GRANT SELECT (numb, role, name) ON demo2 TO teacher;
Result:postgres=# GRANT SELECT (numb, role, name) ON demo2 TO teacher; GRANT
-
Connect to the database as the
teacher
user.\c postgres teacher
Result:postgres=# \c postgres teacher You are now connected to database "postgres" as user "teacher".
-
Request to view all the columns of the table.
SELECT numb, role, name, perm FROM demo2;
Result:postgres=> SELECT numb, role, name, perm FROM demo2; ERROR: permission denied for table demo2
When executing the request, the
teacher
user was denied access because there is no permission to access all columns of the table. -
Request to view available columns of the table.
SELECT numb, role, name FROM demo2;
Result:postgres=> SELECT numb, role, name FROM demo2; numb | role | name ------+----------+----------- 1 | user | student01 2 | non-user | student02 (2 rows)
The
teacher
user has access to the columns of thedemo2
table, except theperm
column.
The user shouldn’t have GRANT
access to the table if you need to implement the column-level permissions method.
If such access was already granted, it must be revoked via the REVOKE
operator.
For example, use the REVOKE SELECT ON demo2 FROM teacher
query command.
Column-level encryption method
The use of the column-level encryption method is based on column data encryption, with the user getting access to all table columns yet not being able to see the encrypted data. The pgcrypto extension is used to implement this method.
To use this method, you need to install the extension for the ADPG service contrib.
-
Grant the
teacher
user access to thedemo2
table.GRANT SELECT ON demo2_info TO teacher;
Result:postgres=# GRANT SELECT ON demo2 TO teacher; GRANT
-
Connect to the database as the
teacher
user.\c postgres teacher
Result:postgres=# \c postgres teacher You are now connected to database "postgres" as user "teacher".
-
Check access to the information in the table.
SELECT * FROM demo2;
Result:postgres=> SELECT * FROM demo2; numb | role | name | perm ------+----------+-----------+------ 1 | user | student01 | 1 2 | non-user | student02 | 0 (2 rows)
-
Connect to the database as the
postgres
user.\c postgres postgres
Result:postgres=> \c postgres postgres You are now connected to database "postgres" as user "postgres".
-
Create a pgcrypto extension.
CREATE EXTENSION pgcrypto;
Result:postgres=# CREATE EXTENSION pgcrypto; CREATE EXTENSION
-
Create the
methodist
user.CREATE USER methodist;
Result:postgres=# CREATE USER methodist; CREATE ROLE
-
Grant the
methodist
user permission to access thedemo2
table.GRANT SELECT ON demo2 TO methodist;
Result:postgres=# GRANT SELECT ON demo TO student01; GRANT
-
Encrypt the data of the
name
column using the encryption key.UPDATE demo2 SET name = pgp_sym_encrypt('student01','demo_sec_key') WHERE name = 'student01'; UPDATE demo2 SET name = pgp_sym_encrypt('student02','demo_sec_key') WHERE name = 'student02';
Result:UPDATE 1
CAUTIONIn this example,demo_sec_key
is the encryption key. Don’t transfer the encryption key to the third parties. -
Connect to the database as the
methodist
user.\c postgres methodist
Result:postgres=> \c postgres methodist You are now connected to database "postgres" as user "methodist".
-
Check access to the information in the table.
SELECT * FROM demo2;
Result:postgres=> SELECT * FROM demo2; numb | role | name | perm ------+----------+----------------------------------------------------------------------------------------------------------------------------------------------------------+------ 1 | user | \xc30d04070302040d5a2793e68b4a79d23a01742b4db830ffffb32e0d11edb78b720a91e4f9668fba7bad83000de2bd97502b678be31ac2227a3dfa72b94a374b720b06491573fd25eb08da | 1 2 | non-user | \xc30d040703021cc0ce1790a51a2978d23a01932226cb250e6c3707bb33176da2cf3d8aeaedd4916d77a3dc6e2cac21bc8411a1ba79d372394826a5b242a5e41d373a8de60c21f36af6315d | 0 (2 rows)
You can see from the example that the
methodist
user doesn’t see encrypted information from thename
column. The column name is also unavailable. -
To view the encrypted information in the
name
column, run a query that includes the encrypted key:SELECT numb, pgp_sym_decrypt(name::bytea,'demo_sec_key') FROM demo2;
Result:postgres=> SELECT numb, pgp_sym_decrypt(name::bytea,'demo_sec_key') FROM demo2; numb | pgp_sym_decrypt ------+----------------- 1 | student01 2 | student02 (2 rows)
After inserting the encrypted key into the request command, the encrypted information in the name column has become available to the
methodist
user.NOTEIn this example, some columns were hidden.
If an incorrect encrypted key is used when accessing the table, the access request will be rejected.
SELECT numb, pgp_sym_decrypt(name::bytea,'not-a-demo_sec_key') FROM demo2;
postgres=> SELECT numb, pgp_sym_decrypt(name::bytea,'not-a-demo_sec_key') FROM demo2; ERROR: Wrong key or corrupt data