Database Roles
CQL uses database roles to represent users and group of users. Syntactically, a role is defined by:
role_name ::= identifier | string
CREATE ROLE
Creating a role uses the CREATE ROLE
statement:
create_role_statement ::= CREATE ROLE [ IF NOT EXISTS ] role_name
[ WITH role_options# ]
role_options ::= role_option ( AND role_option)*
role_option ::= PASSWORD '=' string
| HASHED PASSWORD '=' string
| LOGIN '=' boolean
| SUPERUSER '=' boolean
| OPTIONS '=' map_literal
| ACCESS TO DATACENTERS set_literal
| ACCESS TO ALL DATACENTERS
| ACCESS FROM CIDRS set_literal
| ACCESS FROM ALL CIDRS
For instance:
CREATE ROLE new_role;
CREATE ROLE alice WITH PASSWORD = 'password_a' AND LOGIN = true;
CREATE ROLE alice WITH HASHED PASSWORD = '$2a$10$JSJEMFm6GeaW9XxT5JIheuEtPvat6i7uKbnTcxX3c1wshIIsGyUtG' AND LOGIN = true;
CREATE ROLE bob WITH PASSWORD = 'password_b' AND LOGIN = true AND SUPERUSER = true;
CREATE ROLE carlos WITH OPTIONS = { 'custom_option1' : 'option1_value', 'custom_option2' : 99 };
CREATE ROLE alice WITH PASSWORD = 'password_a' AND LOGIN = true AND ACCESS TO DATACENTERS {'DC1', 'DC3'};
CREATE ROLE alice WITH PASSWORD = 'password_a' AND LOGIN = true AND ACCESS TO ALL DATACENTERS;
CREATE ROLE bob WITH LOGIN = true and PASSWORD = 'password_d' AND ACCESS FROM CIDRS { 'region1', 'region2' };
CREATE ROLE hob WITH LOGIN = true and PASSWORD = 'password_c' AND ACCESS FROM ALL CIDRS;
By default roles do not possess LOGIN
privileges or SUPERUSER
status.
Permissions on database resources are granted to
roles; types of resources include keyspaces, tables, functions and roles
themselves. Roles may be granted to other roles to create hierarchical
permissions structures; in these hierarchies, permissions and
SUPERUSER
status are inherited, but the LOGIN
privilege is not.
If a role has the LOGIN
privilege, clients may identify as that role
when connecting. For the duration of that connection, the client will
acquire any roles and privileges granted to that role.
Only a client with with the CREATE
permission on the database roles
resource may issue CREATE ROLE
requests (see the
relevant section), unless the client is a
SUPERUSER
. Role management in Cassandra is pluggable and custom
implementations may support only a subset of the listed options.
Role names should be quoted if they contain non-alphanumeric characters.
Setting credentials for internal authentication
Use the WITH PASSWORD
clause to set a password for internal
authentication, enclosing the password in single quotation marks.
If internal authentication has not been set up or the role does not have
LOGIN
privileges, the WITH PASSWORD
clause is not necessary.
USE WITH HASHED PASSWORD
to provide the jBcrypt hashed password directly. See the hash_password
tool.
Restricting connections to specific datacenters
If a network_authorizer
has been configured, you can restrict login
roles to specific datacenters with the ACCESS TO DATACENTERS
clause
followed by a set literal of datacenters the user can access. Not
specifiying datacenters implicitly grants access to all datacenters. The
clause ACCESS TO ALL DATACENTERS
can be used for explicitness, but
there’s no functional difference.
Restricting connections from specific CIDR groups
If a cidr_authorizer
has been configured, you can restrict roles to login
only from specific regions, aka CIDR groups, with the ACCESS FROM CIDRS
clause
followed by a set literal of CIDR groups the user can access from. Not
specifying CIDR groups implicitly grants access from all CIDR groups. The
clause ACCESS FROM ALL CIDRS
can be used for explicitness, but there’s no
functional difference. This clause can be also be used to remove any CIDR
groups restrictions. Valid CIDR groups should be used with ACCESS FROM CIDRS
clause. nodetool list-cidrgroups
command can be used to see available CIDR groups
in the Cluster.
ALTER ROLE
Altering a role options uses the ALTER ROLE
statement:
alter_role_statement ::= ALTER ROLE [ IF EXISTS ] role_name WITH role_options
For example:
ALTER ROLE bob WITH PASSWORD = 'PASSWORD_B' AND SUPERUSER = false;
ALTER ROLE bob WITH HASHED PASSWORD = '$2a$10$JSJEMFm6GeaW9XxT5JIheuEtPvat6i7uKbnTcxX3c1wshIIsGyUtG' AND SUPERUSER = false;
ALTER ROLE rob WITH LOGIN = true and PASSWORD = 'password_c' AND ACCESS FROM ALL CIDRS;
ALTER ROLE hob WITH LOGIN = true and PASSWORD = 'password_d' AND ACCESS FROM CIDRS { 'region1' };
If the role does not exist, the statement will return an error, unless IF EXISTS
is used in which case the operation is a no-op.
USE WITH HASHED PASSWORD
to provide the jBcrypt hashed password directly. See the hash_password
tool.
Restricting connections to specific datacenters
If a network_authorizer
has been configured, you can restrict login
roles to specific datacenters with the ACCESS TO DATACENTERS
clause
followed by a set literal of datacenters the user can access. To remove
any data center restrictions, use the ACCESS TO ALL DATACENTERS
clause.
Restricting connections from specific CIDR groups
If a cidr_authorizer
has been configured, you can restrict roles to login
only from specific regions, aka CIDR groups, with the ACCESS FROM CIDRS
clause
followed by a set literal of CIDR groups the user can access from. Not
specifying CIDR groups implicitly grants access from all CIDR groups. The
clause ACCESS FROM ALL CIDRS
can be used for explicitness, but there’s no
functional difference. This clause can be also be used to remove any CIDR
groups restrictions. Valid CIDR groups should be used with ACCESS FROM CIDRS
clause. nodetool list-cidrgroups
command can be used to see available CIDR groups
in the Cluster.
Conditions on executing ALTER ROLE
statements:
-
a client must have
SUPERUSER
status to alter theSUPERUSER
status of another role -
a client cannot alter the
SUPERUSER
status of any role it currently holds -
a client can only modify certain properties of the role with which it identified at login (e.g.
PASSWORD
) -
to modify properties of a role, the client must be granted
ALTER
permission <cql-permissions>
on that role
DROP ROLE
Dropping a role uses the DROP ROLE
statement:
drop_role_statement ::= DROP ROLE [ IF EXISTS ] role_name
DROP ROLE
requires the client to have DROP
permission <cql-permissions>
on the role in question. In addition,
client may not DROP
the role with which it identified at login.
Finally, only a client with SUPERUSER
status may DROP
another
SUPERUSER
role.
Attempting to drop a role which does not exist results in an invalid
query condition unless the IF EXISTS
option is used. If the option is
used and the role does not exist the statement is a no-op.
DROP ROLE intentionally does not terminate any open user sessions. Currently connected sessions will remain connected and will retain the ability to perform any database actions which do not require authorization. However, if authorization is enabled, permissions of the dropped role are also revoked, subject to the caching options configured in cassandra-yaml file. Should a dropped role be subsequently recreated and have new permissions or roles` granted to it, any client sessions still connected will acquire the newly granted permissions and roles. |
GRANT ROLE
Granting a role to another uses the GRANT ROLE
statement:
grant_role_statement ::= GRANT role_name TO role_name
For example:
GRANT report_writer TO alice;
This statement grants the report_writer
role to alice
. Any
permissions granted to report_writer
are also acquired by alice
.
Roles are modelled as a directed acyclic graph, so circular grants are not permitted. The following examples result in error conditions:
GRANT role_a TO role_b;
GRANT role_b TO role_a;
GRANT role_a TO role_b;
GRANT role_b TO role_c;
GRANT role_c TO role_a;
REVOKE ROLE
Revoking a role uses the REVOKE ROLE
statement:
revoke_role_statement ::= REVOKE role_name FROM role_name
For example:
REVOKE report_writer FROM alice;
This statement revokes the report_writer
role from alice
. Any
permissions that alice
has acquired via the report_writer
role are
also revoked.
LIST ROLES
All the known roles (in the system or granted to specific role) can be
listed using the LIST ROLES
statement:
list_roles_statement ::= LIST ROLES [ OF role_name] [ NORECURSIVE ]
For instance:
LIST ROLES;
returns all known roles in the system, this requires DESCRIBE
permission on the database roles resource.
This example enumerates all roles granted to alice
, including those transitively
acquired:
LIST ROLES OF alice;
This example lists all roles directly granted to bob
without including any of the
transitively acquired ones:
LIST ROLES OF bob NORECURSIVE;
Users
Prior to the introduction of roles in Cassandra 2.2, authentication and
authorization were based around the concept of a USER
. For backward
compatibility, the legacy syntax has been preserved with USER
centric
statements becoming synonyms for the ROLE
based equivalents. In other
words, creating/updating a user is just a different syntax for
creating/updating a role.
CREATE USER
Creating a user uses the CREATE USER
statement:
create_user_statement ::= CREATE USER [ IF NOT EXISTS ] role_name
[ WITH [ HASHED ] PASSWORD string ]
[ user_option ]
user_option: SUPERUSER | NOSUPERUSER
For example:
CREATE USER alice WITH PASSWORD 'password_a' SUPERUSER;
CREATE USER bob WITH PASSWORD 'password_b' NOSUPERUSER;
CREATE USER bob WITH HASHED PASSWORD '$2a$10$JSJEMFm6GeaW9XxT5JIheuEtPvat6i7uKbnTcxX3c1wshIIsGyUtG' NOSUPERUSER;
The CREATE USER
command is equivalent to CREATE ROLE
where the LOGIN
option is true
.
So, the following pairs of statements are equivalent:
CREATE USER alice WITH PASSWORD 'password_a' SUPERUSER;
CREATE ROLE alice WITH PASSWORD = 'password_a' AND LOGIN = true AND SUPERUSER = true;
CREATE USER IF NOT EXISTS alice WITH PASSWORD 'password_a' SUPERUSER;
CREATE ROLE IF NOT EXISTS alice WITH PASSWORD = 'password_a' AND LOGIN = true AND SUPERUSER = true;
CREATE USER alice WITH PASSWORD 'password_a' NOSUPERUSER;
CREATE ROLE alice WITH PASSWORD = 'password_a' AND LOGIN = true AND SUPERUSER = false;
CREATE USER alice WITH PASSWORD 'password_a' NOSUPERUSER;
CREATE ROLE alice WITH PASSWORD = 'password_a' AND LOGIN = true;
CREATE USER alice WITH PASSWORD 'password_a';
CREATE ROLE alice WITH PASSWORD = 'password_a' AND LOGIN = true;
CREATE ROLE rob WITH LOGIN = true and PASSWORD = 'password_c' AND ACCESS FROM ALL CIDRS;
CREATE ROLE hob WITH LOGIN = true and PASSWORD = 'password_d' AND ACCESS FROM CIDRS { 'region1' };
ALTER USER
Altering the options of a user uses the ALTER USER
statement:
alter_user_statement ::= ALTER USER [ IF EXISTS ] role_name [ WITH [ HASHED ] PASSWORD string] [ user_option]
If the role does not exist, the statement will return an error, unless IF EXISTS
is used in which case the operation is a no-op.
For example:
ALTER USER alice WITH PASSWORD 'PASSWORD_A';
ALTER USER alice WITH HASHED PASSWORD '$2a$10$JSJEMFm6GeaW9XxT5JIheuEtPvat6i7uKbnTcxX3c1wshIIsGyUtG';
ALTER USER bob SUPERUSER;
DROP USER
Dropping a user uses the DROP USER
statement:
drop_user_statement ::= DROP USER [ IF EXISTS ] role_name
LIST USERS
Existing users can be listed using the LIST USERS
statement:
list_users_statement::= LIST USERS
Note that this statement is equivalent to LIST ROLES
, but only roles with the `LOGIN privilege are included in the output.
Data Control
Permissions
Permissions on resources are granted to roles; there are several different types of resources in Cassandra and each type is modelled hierarchically:
-
The hierarchy of Data resources, Keyspaces and Tables has the structure
ALL KEYSPACES
→KEYSPACE
→TABLE
. -
Function resources have the structure
ALL FUNCTIONS
→KEYSPACE
→FUNCTION
-
Resources representing roles have the structure
ALL ROLES
→ROLE
-
Resources representing JMX ObjectNames, which map to sets of MBeans/MXBeans, have the structure
ALL MBEANS
→MBEAN
Permissions can be granted at any level of these hierarchies and they
flow downwards. So granting a permission on a resource higher up the
chain automatically grants that same permission on all resources lower
down. For example, granting SELECT
on a KEYSPACE
automatically
grants it on all TABLES
in that KEYSPACE
. Likewise, granting a
permission on ALL FUNCTIONS
grants it on every defined function,
regardless of which keyspace it is scoped in. It is also possible to
grant permissions on all functions scoped to a particular keyspace.
Modifications to permissions are visible to existing client sessions; that is, connections need not be re-established following permissions changes.
The full set of available permissions is:
-
CREATE
-
ALTER
-
DROP
-
SELECT
-
MODIFY
-
AUTHORIZE
-
DESCRIBE
-
EXECUTE
-
UNMASK
-
SELECT_MASKED
Not all permissions are applicable to every type of resource. For
instance, EXECUTE
is only relevant in the context of functions or
mbeans; granting EXECUTE
on a resource representing a table is
nonsensical. Attempting to GRANT
a permission on resource to which it
cannot be applied results in an error response. The following
illustrates which permissions can be granted on which types of resource,
and which statements are enabled by that permission.
Permission | Resource | Operations |
---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Call getter methods on any mbean |
|
|
Call getter methods on any mbean matching a wildcard pattern |
|
|
Call getter methods on named mbean |
|
|
|
|
|
|
|
|
|
|
|
Call setter methods on any mbean |
|
|
Call setter methods on any mbean matching a wildcard pattern |
|
|
Call setter methods on named mbean |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Retrieve metadata about any mbean from the platform’s MBeanServer |
|
|
Retrieve metadata about any mbean matching a wildcard patter from the platform’s MBeanServer |
|
|
Retrieve metadata about a named mbean from the platform’s MBeanServer |
|
|
|
|
|
|
|
|
|
|
|
Execute operations on any mbean |
|
|
Execute operations on any mbean matching a wildcard pattern |
|
|
Execute operations on named mbean |
|
|
See the clear contents of masked columns on any table |
|
|
See the clear contents of masked columns on any table in keyspace |
|
|
See the clear contents of masked columns on the specified table |
|
|
|
|
|
|
|
|
|
GRANT PERMISSION
Granting a permission uses the GRANT PERMISSION
statement:
grant_permission_statement ::= GRANT permissions ON resource TO role_name
permissions ::= ALL [ PERMISSIONS ] | permission [ PERMISSION ]
permission ::= CREATE | ALTER | DROP | SELECT | MODIFY | AUTHORIZE | DESCRIBE | EXECUTE | UNMASK | SELECT_MASKED
resource ::= ALL KEYSPACES
| KEYSPACE keyspace_name
| [ TABLE ] table_name
| ALL ROLES
| ROLE role_name
| ALL FUNCTIONS [ IN KEYSPACE keyspace_name ]
| FUNCTION function_name '(' [ cql_type( ',' cql_type )* ] ')'
| ALL MBEANS
| ( MBEAN | MBEANS ) string
For example:
GRANT SELECT ON ALL KEYSPACES TO data_reader;
This example gives any user with the role data_reader
permission to execute
SELECT
statements on any table across all keyspaces:
GRANT MODIFY ON KEYSPACE keyspace1 TO data_writer;
To give any user with the role data_writer
permission to perform
UPDATE
, INSERT
, UPDATE
, DELETE
and TRUNCATE
queries on all
tables in the keyspace1
keyspace:
GRANT DROP ON keyspace1.table1 TO schema_owner;
To give any user with the schema_owner
role permissions to DROP
a specific
keyspace1.table1
:
GRANT EXECUTE ON FUNCTION keyspace1.user_function( int ) TO report_writer;
This command grants any user with the report_writer
role permission to execute
SELECT
, INSERT
and UPDATE
queries which use the function
keyspace1.user_function( int )
:
GRANT DESCRIBE ON ALL ROLES TO role_admin;
This grants any user with the role_admin
role permission to view any
and all roles in the system with a LIST ROLES
statement.
GRANT ALL
When the GRANT ALL
form is used, the appropriate set of permissions is
determined automatically based on the target resource.
Automatic Granting
When a resource is created, via a CREATE KEYSPACE
, CREATE TABLE
,
CREATE FUNCTION
, CREATE AGGREGATE
or CREATE ROLE
statement, the
creator (the role the database user who issues the statement is
identified as), is automatically granted all applicable permissions on
the new resource.
REVOKE PERMISSION
Revoking a permission from a role uses the REVOKE PERMISSION
statement:
revoke_permission_statement ::= REVOKE permissions ON resource FROM role_name
For example:
REVOKE SELECT ON ALL KEYSPACES FROM data_reader;
REVOKE MODIFY ON KEYSPACE keyspace1 FROM data_writer;
REVOKE DROP ON keyspace1.table1 FROM schema_owner;
REVOKE EXECUTE ON FUNCTION keyspace1.user_function( int ) FROM report_writer;
REVOKE DESCRIBE ON ALL ROLES FROM role_admin;
Because of their function in normal driver operations, certain tables
cannot have their SELECT
permissions revoked. The
following tables will be available to all authorized users regardless of
their assigned role:
* `system_schema.keyspaces`
* `system_schema.columns`
* `system_schema.tables`
* `system.local`
* `system.peers`
LIST PERMISSIONS
Listing granted permissions uses the LIST PERMISSIONS
statement:
list_permissions_statement ::= LIST permissions [ ON resource] [ OF role_name[ NORECURSIVE ] ]
For example:
LIST ALL PERMISSIONS OF alice;
Show all permissions granted to alice
, including those acquired
transitively from any other roles:
LIST ALL PERMISSIONS ON keyspace1.table1 OF bob;
Show all permissions on keyspace1.table1
granted to bob
, including
those acquired transitively from any other roles. This also includes any
permissions higher up the resource hierarchy which can be applied to
keyspace1.table1
. For example, should bob
have ALTER
permission on
keyspace1
, that would be included in the results of this query. Adding
the NORECURSIVE
switch restricts the results to only those permissions
which were directly granted to bob
or one of `bob’s roles:
LIST SELECT PERMISSIONS OF carlos;
Show any permissions granted to carlos
or any of carlos’s roles,
limited to `SELECT
permissions on any resource.