Setting row-level permissions
Row-level access control (RLAC) provides authorization to data within a table by matching a filter applied to a text-based partition key. RLAC provides more granular security for tables so that only authorized users are able to view or modify subsets of the data.
|
RLAC workflow
Configuring RLAC is a multi-step process:
-
Enable RLAC on the node.
By default, row level access control is disabled. To enable RLAC, set
allow_row_level_securitytotrueindse.yaml. For more information, see Enabling DSE Unified Authentication. -
Create a partition key filter for RLAC.
The filter can be defined on any text column in the primary key. You must have
MODIFYpermission on the table to do this. -
GRANTpermissions on roles using the filter.Different filters can be granted to any number of roles.
-
Tune the RLAC cache settings in
cassandra.yamlif needed.RLAC has a separate cache because it can be resource intensive to fetch RLAC permissions.
Restrict rows
|
Tables can have only one restriction.
Running multiple To check a table’s existing restrictions, use |
-
Select a column on the table for which you want to configure permissions. Set a UTF-8 partition key column. Only one filtering column per table is allowed:
RESTRICT ROWS ON [<keyspace_name>.]<table_name> USING <primary_key_text_column>;For example:
CREATE TABLE test.rlac(pk1 text, pk2 text, ck1 text, ck2 text, PRIMARY KEY ((pk1, pk2), ck1, ck2));RESTRICT ROWS ON test.rlac using ck1;Existing filters (if any) now filter on this column. The DESCRIBE TABLE command shows the row restriction.
-
Grant permissions with RLAC to roles, specifying the exact case-sensitive text string to match:
GRANT <permission> ON '<filtering_string>' ROWS IN [<keyspace_name>.]<table_name> TO <role_name>;The filter string must match the filter string used with the
RESTRICTcommand.The permission is applied to the role immediately, even for active sessions.
-
Use the
LISTcommand to verify the restriction on the role:LIST ALL PERMISSIONS OF <role_name>;
Unrestrict rows
The partition key to filter on using GRANT can be unselected from the table:
UNRESTRICT ROWS ON [<keyspace_name>.]<table_name>
USING <partition_key>;
Unrestricting the column does not grant access to all columns within the table; it invalidates existing filters only. Users that are granted access with a filter are unable to access any rows within the table. To grant permissions to all rows, grant permission on the table to the role.
You can also unrestrict rows using REVOKE.
Row permissions are stored based on the filtering string, so you must use the exact filtering string that you want to remove.
REVOKE <permission> on '<filtering_data>' ROWS IN <keyspace_name>.<table_name>;
Example
-
Select the
cyclist_namecolumn as the filtering column:RESTRICT ROWS ON cycling.cyclist_expenses USING cyclist_name ;Show the changes to the table:
DESC cycling.cyclist_expenses;The restrict statement appears at the end:
CREATE TABLE cycling.cyclist_expenses ( cyclist_name text, expense_id int, amount float, balance float static, description text, paid boolean, PRIMARY KEY (cyclist_name, expense_id) ) WITH CLUSTERING ORDER BY (expense_id ASC) AND bloom_filter_fp_chance = 0.01 AND caching = {'keys': 'ALL', 'rows_per_partition': 'NONE'} AND comment = '' AND compaction = {'class': 'org.apache.cassandra.db.compaction.SizeTieredCompactionStrategy', 'max_threshold': '32', 'min_threshold': '4'} AND compression = {'chunk_length_in_kb': '64', 'class': 'org.apache.cassandra.io.compress.LZ4Compressor'} AND crc_check_chance = 1.0 AND dclocal_read_repair_chance = 0.1 AND default_time_to_live = 0 AND gc_grace_seconds = 864000 AND max_index_interval = 2048 AND memtable_flush_period_in_ms = 0 AND min_index_interval = 128 AND read_repair_chance = 0.0 AND speculative_retry = '99PERCENTILE'; RESTRICT ROWS ON cycling.cyclist_expenses USING cyclist_name; -
Get a list of the primary keys to use in the filter:
SELECT DISTINCT cyclist_name FROM cycling.cyclist_expenses ;cyclist_name ---------------------- Marianne VOS Alex FRAME Steven KRUIKSWIJK Vera ADRIAN Michael MATTHEWS Anna VAN DER BREGGEN Paolo TIRALONGO (7 rows) -
Assign RLAC:
-
Allow role dantest1 to access expenses entered only by Paolo TIRALONGO:
GRANT SELECT ON 'Paolo TIRALONGO' ROWS IN cycling.cyclist_expenses TO dantest1; -
Allow role jane to access only Vera ADRIAN:
GRANT SELECT ON 'Vera ADRIAN' ROWS IN cycling.cyclist_expenses TO jane;
-
-
Verify permissions:
-
Check dantest1 permissions:
LIST ALL PERMISSIONS OF dantest1;In this example these are the permissions only for Dan:
role | username | resource | permission ----------+----------+------------------------------------------------------------+------------ dantest1 | dantest1 | 'Paolo TIRALONGO' rows IN <table cycling.cyclist_expenses> | SELECT -
Check jane permissions:
LIST ALL PERMISSIONS OF jane;In this example these are the permissions only for Jane:
role | username | resource | permission ----------+----------+------------------------------------------------------------+------------ jane | jane | 'Vera ADRIAN' rows IN <table cycling.cyclist_expenses> | SELECT
-
When Dan logs in and runs queries, only rows he has permission to access display in the results set:
-
Log in as dantest1:
cqlsh -p password -u dantest1 -
Run a query:
SELECT * FROM cycling.cyclist_expenses ;Only the records that exactly match the filter are displayed:
cyclist_name | expense_id | balance | amount | description | paid -----------------+------------+---------+--------+-------------+------ Paolo TIRALONGO | 11 | null | 10 | dinner | null Paolo TIRALONGO | 12 | null | 10 | dinner | null Paolo TIRALONGO | 24 | null | 10 | lunch | null Paolo TIRALONGO | 25 | null | 11 | dinner | null Paolo TIRALONGO | 26 | null | 12 | lunch | null Paolo TIRALONGO | 27 | null | 13 | lunch | null Paolo TIRALONGO | 28 | null | 14 | lunch | null Paolo TIRALONGO | 29 | null | 15 | dinner | null Paolo TIRALONGO | 30 | null | 16 | lunch | null Paolo TIRALONGO | 31 | null | 17 | dinner | null Paolo TIRALONGO | 32 | null | 18 | breakfast | null (11 rows)