Overview
Cassandra has recently launced most awaiting feature "Role based access control (RBAC)" but there are very limited information available on web and people actually stuck at practicle scenarios viz.
1. How to migrate from legacy authentication to RBAC.
2. Is there any changes need to be made in cassandra.yaml file.
3. What table structure changes been made to system_auth keyspaces.
4. What about legacy table.
5. We have legacy table as well as new table also and creating a new user doesnt work.
6. What are the new commands for RBAC.
Here today i am trying to combined various web resources along with my test cases which might be helpful for you guys while implementing RBAC.
Few Web references:
- https://issues.apache.org/jira/browse/CASSANDRA-10904
- http://www.datastax.com/dev/blog/role-based-access-control-in-cassandra
- http://docs.datastax.com/en/latest-cql/cql/cql_reference/list_permissions_r.html
IMPORTANT FACTS:
- Legacy tables: users, credentials, permissions
- New tables: roles, role_members, role_permissions, resource_role_permissons_index
- Ensure following parameter is enabled in cassandra.yaml - “role_manager: CassandraRoleManager”
- During upgrade from an earlier version the upgrade of users to role based system happens automatically. The same can be verified in system.log Explained below in detail.
- The migration doesn’t impact existing users and their login as legacy tables are functioning till superuser doesn’t drop them.
- If we do not drop legacy tables system will have login discrepancy, old users will be working fine but if you create a new role it wont since system is still pointing to legacy tables.
- It is vital to drop legacy tables after verification of user/permission migration, this can be done in system.log as well as data of legacy and new table can be compared.
- As soon as legacy tables gets dropped Cassandra switch itself to new role bases system and any role being created going forward should be functioning (a node bounce is not required.)
- In order for database users to identify as a particular role at login, that role must have its LOGIN attribute set to true, this prevents users inadvertently logging in under the identity of a group.
- Another interesting aspect to this is that the creator of a role
(the role the database user who issues the CREATE ROLE statement is
logged in as), is automatically granted permissions on it. This enables
users with role-creation privileges to also manage the roles they
create, allowing them to ALTER, DROP, GRANT and REVOKE them. This
automatic granting of ‘ownership’ permissions isn’t limited to roles
either, it also applies to database objects such as keyspaces, tables
(and soon to user defined functions). This largely removes the
requirement to have any active superuser roles, which reduces the risk
of privilege escalation. See CASSANDRA-7216 and CASSANDRA-8650 for full details.
HOW TO:
The authentication & authorization subsystems have been redesigned to support role based access control (RBAC), resulting in a change to the schema of the system_auth keyspace. See below for more detail. For systems already using the internal auth implementations, the process for converting existing data during a rolling upgrade is straightforward. As each node is restarted, it will attempt to convert any data in the legacy tables into the new schema. Until enough nodes to satisfy the replication strategy for the system_auth keyspace are upgraded and so have the new schema, this conversion will fail with the failure being reported in the system log.System Log:
INFO [OptionalTasks:1] CassandraRoleManager.java:410 - Converting legacy users
INFO [OptionalTasks:1] CassandraRoleManager.java:420 - Completed conversion of legacy users
INFO [OptionalTasks:1] CassandraRoleManager.java:425 - Migrating legacy credentials data to new system table
INFO [OptionalTasks:1] CassandraRoleManager.java:438 - Completed conversion of legacy credentials
INFO [OptionalTasks:1] CassandraAuthorizer.java:396 - Converting legacy permissions data
INFO [OptionalTasks:1] CassandraAuthorizer.java:435 - Completed conversion of legacy permissions
statements during an upgrade is not supported. Once all nodes are upgraded, an operator with superuser privileges should drop the legacy tables, system_auth.users, system_auth.credentials and system_auth.permissions. Doing so will prompt Cassandra to switch over to the new tables without requiring any further intervention. While the legacy tables are present a restarted node will re-run the data conversion and report the outcome so that operators can verify that it is safe to drop them.
- Authentication & Authorization APIs have been updated to introduce roles. Roles and Permissions granted to them are inherited, supporting role based access control. The role concept supercedes that of users and CQL constructs such as CREATE USER are deprecated but retained for compatibility. The requirement to explicitly create Roles in Cassandra even when auth is handled by an external system has been removed, so authentication & authorization can be delegated to such systems in their entirety.
- In addition to the above, Roles are also first class resources and can be the subject of permissions. Users (roles) can now be granted permissions on other roles, including CREATE, ALTER, DROP & AUTHORIZE, which removesthe need for superuser privileges in order to perform user/role management operations.
- Creators of database resources (Keyspaces, Tables, Roles) are now automatically granted all permissions on them (if the IAuthorizer implementation supports this).
Various permission in RBAC:
GRANT
|
Object
|
CREATE
|
keyspace, table, function, role, index
|
ALTER
|
keyspace, table, function, role
|
DROP
|
keyspace, table, function, role, index
|
SELECT
|
keyspace, table
|
MODIFY (INSERT, UPDATE, DELETE, TRUNCATE)
|
keyspace, table
|
AUTHORIZE (GRANT PERMISSION, REVOKE
PERMISSION)
|
keyspace, table, function, role
|
DESCRIBE
|
LIST ROLES
|
EXECUTE (SELECT, INSERT, UPDATE)
|
functions
|
New commands can be found @ http://docs.datastax.com/en/latest-cql/cql/cql_reference/list_permissions_r.html
RBAC Implementation & Testing.
#Check existing roles.
admin@cqlsh:system_auth> LIST ROLES;
role | super | login | options
--------------------+--------
admin | True | True | {}
cassandra | True | True | {}
(2 rows)
#List all roles of user(role) admin.
admin@cqlsh:system_auth> LIST ROLES of admin;
role | super | login | options
----------------+--------
admin | True | True | {}
(1 rows)
#Create a login enabled super user role.. Ideally creating a user.
admin@cqlsh:system_auth> CREATE role nnishant WITH PASSWORD = 'abcd@123' AND LOGIN = true and SUPERUSER = true ;
admin@cqlsh:system_auth> LIST ROLES of nnishant;
InvalidRequest: code=2200 [Invalid query] message="<role nnishant> doesn't exist"
#Lets list out all the roles..so we can see nnishant here but wait.. Why it is showing super and login FALSE??
admin@cqlsh:system_auth> list roles;
role | super | login | options
--------------------+--------
admin | True | True | {}
cassandra | True | True | {}
nnishant | False | False | {}
(3 rows)
#Let's check in system table system_auth.roles, here it is showing it correctly? So where is the problem? Let me tell you if you try to login using “nnishant” through cqlsh it fails since till now cassandra has not started using new system tables.
admin@cqlsh:system_auth> SELECT * from roles; role | can_login | is_superuser | member_of | salted_hash ----------------------------------------------------------------------------------------------------- nnishant | True | True | null | $2a$10$ZgXpLYZ3.9QE5XwtHw6yQe5pB2AGpezSS9hayzPevBjprZ.JuDOnW admin | True | True | null | $2a$10$Fg4zH7yFm/IN8kg0dqPR3ODQkY83Oj8SFGy7R5hnSOzqanl9LZ8iC cassandra | True | True | null | $2a$10$EAPR.YFjULRORyc/amQXAuS2J2atefzrzT7JZPJ8uy25n7Q6nS9bm (3 rows)
#lets create another user test1 with login enabled and having superuser privileges.
admin@cqlsh:system_auth> create role test1 WITH PASSWORD = 'abcd@123' AND LOGIN = true AND SUPERUSER = true;
admin@cqlsh:system_auth> LIST ROLES of test1;
InvalidRequest: code=2200 [Invalid query] message="<role test1> doesn't exist"
So where is the problem??
#lets verify the tables in system_auth, tables highlighted in red are legacy tables and green ones are new tables.admin@cqlsh> USE system_auth; admin@cqlsh:system_auth> desc tables; role_members roles resource_role_permissons_index permissions users role_permissions credentials
#Lets drop the legacy tables; Please note; no need to bounce nodes after this operation, cassandra automatically and immediately switches to new tables.
admin@cqlsh:system_auth> DROP TABLE credentials; admin@cqlsh:system_auth> DROP TABLE permissions; admin@cqlsh:system_auth> DROP TABLE users; admin@cqlsh:system_auth> desc tables; role_members roles role_permissions resource_role_permissons_index
#now execute LIST ROLES one again.. BINGO we see correct data now.
admin@cqlsh:system_auth> LIST ROLES;
role | super | login | options
--------------------+--------
admin | True | True | {}
cassandra | True | True | {}
nnishant | True | True | {}
test1 | True | True | {}
(4 rows)
#This also shows correct data.
admin@cqlsh:system_auth> LIST ROLES of test1;
role | super | login | options
----------------+--------
test1 | True | True | {}
(1 rows)
admin@cqlsh:system_auth> exit
#Let's try to connect using user test1 which we had created. And we are in..
10:47 AM(cass@ubuntu:)/cassandra/data/system_auth: cqlsh -u test1
Password:
Connected to NAV at 127.0.0.1:9042.
[cqlsh 5.0.1 | Cassandra 2.2.4 | CQL spec 3.3.1 | Native protocol v4]
Use HELP for help.
Example on setting permission and user/role mapping.
#Create a password less role dedicated for DEV team.test1@cqlsh> create ROLE ROLE_DEV;
test1@cqlsh> LIST ROLES; role | super | login | options --------------------+-------- admin | True | True | {} cassandra | True | True | {} nnishant | True | True | {} role_dev | False | False | {} test1 | True | True | {} (5 rows) test1@cqlsh> LIST ROLES of role_dev; role | super | login | options -------------------+-------- role_dev | False | False | {} (1 rows)
#Grant select permission to ROLE_DEV against all keyspaces;
test1@cqlsh> GRANT SELECT ON ALL KEYSPACES TO role_dev;
test1@cqlsh> LIST ROLES of role_dev;
role | super | login | options
-------------------+--------
role_dev | False | False | {}
#Verify GRANT we have assigned to this role.
test1@cqlsh> LIST ALL PERMISSIONS OF role_dev; role | username | resource | permission --------------------------------+----------- role_dev | role_dev | <all keyspaces> | SELECT (1 rows)
#lets create user for DEV team with login enabled but no superuser.
test1@cqlsh> CREATE ROLE alex WITH PASSWORD = 'abcd@123' AND LOGIN = true ;
test1@cqlsh> LIST ROLES OF alex;
role | super | login | options
---------------+--------
alex | False | True | {}
(1 rows)
#Check if alex has any permission on database, note we havent assigned any till now and that’s what we get in result.
test1@cqlsh> LIST ALL PERMISSIONS OF alex; role | resource | permissions ------------------------- (0 rows)
#Now add DEV team user to its group (role_dev)
test1@cqlsh> GRANT role_dev to alex;
test1@cqlsh> LIST ALL PERMISSIONS OF alex; role | username | resource | permission --------------------------------+----------- role_dev | role_dev | <all keyspaces> | SELECT (1 rows)
Similarly we can add multiple team members to their respective groups. At the same time we can change the permission of entire group by executing a single command rather that executing it against each user.
For example:
We have 50 user mapped to dev group (role_dev). At this point all those 50 users has SELECT permission against ALL KEYSPACES but now there is a requirement to give MODIFY permission to all those 50 users on a specific keyspace "test", this can be simply achieved by executing below mentioned single command. So instead of executing grant against 50 users we achieved it by executing it against group. Another beauty of role based access control :)
admin@cqlsh> GRANT MODIFY ON Keyspace test to role_dev; admin@cqlsh> LIST ALL PERMISSIONS OF role_dev; role | username | resource | permission --------------------------------+----------- role_dev | role_dev | <all keyspaces> | SELECT role_dev | role_dev | <keyspace test> | MODIFY (2 rows) admin@cqlsh> LIST ALL PERMISSIONS OF alex; role | username | resource | permission --------------------------------+----------- role_dev | role_dev | <all keyspaces> | SELECT role_dev | role_dev | <keyspace test> | MODIFY
#Now let's login through dev user alex
test1@cqlsh> exit
10:58 AM(cass@ubuntu:)/cassandra/data/system_auth: cqlsh -u alex
Password:
Connected to NAV at 127.0.0.1:9042.
[cqlsh 5.0.1 | Cassandra 2.2.4 | CQL spec 3.3.1 | Native protocol v4]
Use HELP for help.
#let's check if roles are visible to alex? Yes he has access to view roles on which he has access but not all. Another level of security.
alex@cqlsh> LIST ROLES ;
role | super | login | options
-------------------+--------
alex | False | True | {}
role_dev | False | False | {}
(2 rows)
But wait if alex query to system table directly he can see everything.. Bingo we have a security breach.. And a bug obviously :)
So "ALL KEYSPACE" include system Keyspace too, until it doesn’t get fixed in coming version we should avoid using "ALL KEPSPACE" for any app users.
alex@cqlsh> select * from system_auth.roles; role | can_login | is_superuser | member_of | salted_hash -------------------------------------------------------------------------------------------------------- nnishant | True | True | null | $2a$10$ZgXpLYZ3.9QE5XwtHw6yQe5pB2AGpezSS9hayzPevBjprZ.JuDOnW admin | True | True | null | $2a$10$Fg4zH7yFm/IN8kg0dqPR3ODQkY83Oj8SFGy7R5hnSOzqanl9LZ8iC role_dev | False | False | null | null test1 | True | True | null | $2a$10$i3LeXdJ2y/8iMylHc8Ob6ebMWJOE9Rn3NWbxeokjreKRf4664dpT. cassandra | True | True | null | $2a$10$EAPR.YFjULRORyc/amQXAuS2J2atefzrzT7JZPJ8uy25n7Q6nS9bm alex | True | False | {'role_dev'} | $2a$10$Afre.n.by.Bg0Llf5txiS.9sswymcaZ9BsgbmLvi5IWbGsVJ8Msqi (6 rows)
Stay tuned guys....
0 comments:
Post a Comment