| = Security |
| |
| There are three main components to the security features provided by |
| Cassandra: |
| |
| * TLS/SSL encryption for client and inter-node communication |
| * Client authentication |
| * Authorization |
| |
| By default, these features are disabled as Cassandra is configured to |
| easily find and be found by other members of a cluster. In other words, |
| an out-of-the-box Cassandra installation presents a large attack surface |
| for a bad actor. Enabling authentication for clients using the binary |
| protocol is not sufficient to protect a cluster. Malicious users able to |
| access internode communication and JMX ports can still: |
| |
| * Craft internode messages to insert users into authentication schema |
| * Craft internode messages to truncate or drop schema |
| * Use tools such as `sstableloader` to overwrite `system_auth` tables |
| * Attach to the cluster directly to capture write traffic |
| |
| Correct configuration of all three security components should negate |
| theses vectors. Therefore, understanding Cassandra's security features |
| is crucial to configuring your cluster to meet your security needs. |
| |
| == TLS/SSL Encryption |
| |
| Cassandra provides secure communication between a client machine and a |
| database cluster and between nodes within a cluster. Enabling encryption |
| ensures that data in flight is not compromised and is transferred |
| securely. The options for client-to-node and node-to-node encryption are |
| managed separately and may be configured independently. |
| |
| In both cases, the JVM defaults for supported protocols and cipher |
| suites are used when encryption is enabled. These can be overidden using |
| the settings in `cassandra.yaml`, but this is not recommended unless |
| there are policies in place which dictate certain settings or a need to |
| disable vulnerable ciphers or protocols in cases where the JVM cannot be |
| updated. |
| |
| FIPS compliant settings can be configured at the JVM level and should |
| not involve changing encryption settings in cassandra.yaml. See |
| https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/FIPS.html[the |
| java document on FIPS] for more details. |
| |
| For information on generating the keystore and truststore files used in |
| SSL communications, see the |
| http://download.oracle.com/javase/6/docs/technotes/guides/security/jsse/JSSERefGuide.html#CreateKeystore[java |
| documentation on creating keystores] |
| |
| == SSL Certificate Hot Reloading |
| |
| Beginning with Cassandra 4, Cassandra supports hot reloading of SSL |
| Certificates. If SSL/TLS support is enabled in Cassandra, the node |
| periodically polls the Trust and Key Stores specified in cassandra.yaml. |
| When the files are updated, Cassandra will reload them and use them for |
| subsequent connections. Please note that the Trust & Key Store passwords |
| are part of the yaml so the updated files should also use the same |
| passwords. The default polling interval is 10 minutes. |
| |
| Certificate Hot reloading may also be triggered using the |
| `nodetool reloadssl` command. Use this if you want to Cassandra to |
| immediately notice the changed certificates. |
| |
| === Inter-node Encryption |
| |
| The settings for managing inter-node encryption are found in |
| `cassandra.yaml` in the `server_encryption_options` section. To enable |
| inter-node encryption, change the `internode_encryption` setting from |
| its default value of `none` to one value from: `rack`, `dc` or `all`. |
| |
| === Client to Node Encryption |
| |
| The settings for managing client to node encryption are found in |
| `cassandra.yaml` in the `client_encryption_options` section. There are |
| two primary toggles here for enabling encryption, `enabled` and |
| `optional`. |
| |
| * If neither is set to `true`, client connections are entirely |
| unencrypted. |
| * If `enabled` is set to `true` and `optional` is set to `false`, all |
| client connections must be secured. |
| * If both options are set to `true`, both encrypted and unencrypted |
| connections are supported using the same port. Client connections using |
| encryption with this configuration will be automatically detected and |
| handled by the server. |
| |
| As an alternative to the `optional` setting, separate ports can also be |
| configured for secure and unsecure connections where operational |
| requirements demand it. To do so, set `optional` to false and use the |
| `native_transport_port_ssl` setting in `cassandra.yaml` to specify the |
| port to be used for secure client communication. |
| |
| [[operation-roles]] |
| == Roles |
| |
| Cassandra uses database roles, which may represent either a single user |
| or a group of users, in both authentication and permissions management. |
| Role management is an extension point in Cassandra and may be configured |
| using the `role_manager` setting in `cassandra.yaml`. The default |
| setting uses `CassandraRoleManager`, an implementation which stores role |
| information in the tables of the `system_auth` keyspace. |
| |
| See also the xref:cql/security.adoc#database-roles[`CQL documentation on roles`]. |
| |
| == Authentication |
| |
| Authentication is pluggable in Cassandra and is configured using the |
| `authenticator` setting in `cassandra.yaml`. Cassandra ships with two |
| options included in the default distribution. |
| |
| By default, Cassandra is configured with `AllowAllAuthenticator` which |
| performs no authentication checks and therefore requires no credentials. |
| It is used to disable authentication completely. Note that |
| authentication is a necessary condition of Cassandra's permissions |
| subsystem, so if authentication is disabled, effectively so are |
| permissions. |
| |
| The default distribution also includes `PasswordAuthenticator`, which |
| stores encrypted credentials in a system table. This can be used to |
| enable simple username/password authentication. |
| |
| [[password-authentication]] |
| === Enabling Password Authentication |
| |
| Before enabling client authentication on the cluster, client |
| applications should be pre-configured with their intended credentials. |
| When a connection is initiated, the server will only ask for credentials |
| once authentication is enabled, so setting up the client side config in |
| advance is safe. In contrast, as soon as a server has authentication |
| enabled, any connection attempt without proper credentials will be |
| rejected which may cause availability problems for client applications. |
| Once clients are setup and ready for authentication to be enabled, |
| follow this procedure to enable it on the cluster. |
| |
| Pick a single node in the cluster on which to perform the initial |
| configuration. Ideally, no clients should connect to this node during |
| the setup process, so you may want to remove it from client config, |
| block it at the network level or possibly add a new temporary node to |
| the cluster for this purpose. On that node, perform the following steps: |
| |
| [arabic] |
| . Open a `cqlsh` session and change the replication factor of the |
| `system_auth` keyspace. By default, this keyspace uses |
| `SimpleReplicationStrategy` and a `replication_factor` of 1. It is |
| recommended to change this for any non-trivial deployment to ensure that |
| should nodes become unavailable, login is still possible. Best practice |
| is to configure a replication factor of 3 to 5 per-DC. |
| |
| [source,cql] |
| ---- |
| ALTER KEYSPACE system_auth WITH replication = {'class': 'NetworkTopologyStrategy', 'DC1': 3, 'DC2': 3}; |
| ---- |
| |
| [arabic, start=2] |
| . Edit `cassandra.yaml` to change the `authenticator` option like so: |
| |
| [source,yaml] |
| ---- |
| authenticator: PasswordAuthenticator |
| ---- |
| |
| [arabic, start=3] |
| . Restart the node. |
| . Open a new `cqlsh` session using the credentials of the default |
| superuser: |
| |
| [source,bash] |
| ---- |
| $ cqlsh -u cassandra -p cassandra |
| ---- |
| |
| [arabic, start=5] |
| . During login, the credentials for the default superuser are read with |
| a consistency level of `QUORUM`, whereas those for all other users |
| (including superusers) are read at `LOCAL_ONE`. In the interests of |
| performance and availability, as well as security, operators should |
| create another superuser and disable the default one. This step is |
| optional, but highly recommended. While logged in as the default |
| superuser, create another superuser role which can be used to bootstrap |
| further configuration. |
| |
| [source,cql] |
| ---- |
| # create a new superuser |
| CREATE ROLE dba WITH SUPERUSER = true AND LOGIN = true AND PASSWORD = 'super'; |
| ---- |
| |
| [arabic, start=6] |
| . Start a new cqlsh session, this time logging in as the new_superuser |
| and disable the default superuser. |
| |
| [source,cql] |
| ---- |
| ALTER ROLE cassandra WITH SUPERUSER = false AND LOGIN = false; |
| ---- |
| |
| [arabic, start=7] |
| . Finally, set up the roles and credentials for your application users |
| with xref:cql/security.adoc#create-role[`CREATE ROLE`] statements. |
| |
| At the end of these steps, the one node is configured to use password |
| authentication. To roll that out across the cluster, repeat steps 2 and |
| 3 on each node in the cluster. Once all nodes have been restarted, |
| authentication will be fully enabled throughout the cluster. |
| |
| Note that using `PasswordAuthenticator` also requires the use of |
| xref:cql/security.adoc#operation-roles[`CassandraRoleManager`]. |
| |
| See also: `setting-credentials-for-internal-authentication`, |
| xref:cql/security.adoc#create-role[`CREATE ROLE`], |
| xref:cql/security.adoc#alter-role[`ALTER ROLE`], |
| xref:xref:cql/security.adoc#alter-keyspace[`ALTER KEYSPACE`] and |
| xref:cql/security.adoc#grant-permission[`GRANT PERMISSION`]. |
| |
| == Authorization |
| |
| Authorization is pluggable in Cassandra and is configured using the |
| `authorizer` setting in `cassandra.yaml`. Cassandra ships with two |
| options included in the default distribution. |
| |
| By default, Cassandra is configured with `AllowAllAuthorizer` which |
| performs no checking and so effectively grants all permissions to all |
| roles. This must be used if `AllowAllAuthenticator` is the configured |
| authenticator. |
| |
| The default distribution also includes `CassandraAuthorizer`, which does |
| implement full permissions management functionality and stores its data |
| in Cassandra system tables. |
| |
| === Enabling Internal Authorization |
| |
| Permissions are modelled as a whitelist, with the default assumption |
| that a given role has no access to any database resources. The |
| implication of this is that once authorization is enabled on a node, all |
| requests will be rejected until the required permissions have been |
| granted. For this reason, it is strongly recommended to perform the |
| initial setup on a node which is not processing client requests. |
| |
| The following assumes that authentication has already been enabled via |
| the process outlined in `password-authentication`. Perform these steps |
| to enable internal authorization across the cluster: |
| |
| [arabic] |
| . On the selected node, edit `cassandra.yaml` to change the `authorizer` |
| option like so: |
| |
| [source,yaml] |
| ---- |
| authorizer: CassandraAuthorizer |
| ---- |
| |
| [arabic, start=2] |
| . Restart the node. |
| . Open a new `cqlsh` session using the credentials of a role with |
| superuser credentials: |
| |
| [source,bash] |
| ---- |
| $ cqlsh -u dba -p super |
| ---- |
| |
| [arabic, start=4] |
| . Configure the appropriate access privileges for your clients using |
| link:cql.html#grant-permission[GRANT PERMISSION] statements. On the |
| other nodes, until configuration is updated and the node restarted, this |
| will have no effect so disruption to clients is avoided. |
| |
| [source,cql] |
| ---- |
| GRANT SELECT ON ks.t1 TO db_user; |
| ---- |
| |
| [arabic, start=5] |
| . Once all the necessary permissions have been granted, repeat steps 1 |
| and 2 for each node in turn. As each node restarts and clients |
| reconnect, the enforcement of the granted permissions will begin. |
| |
| See also: xref:cql/security.adoc#grant-permission[`GRANT PERMISSION`], |
| xref:cql/security.adoc#grant-all[`GRANT ALL`] and |
| xref:cql/security.adoc#revoke-permission[`REVOKE PERMISSION`]. |
| |
| [[auth-caching]] |
| == Caching |
| |
| Enabling authentication and authorization places additional load on the |
| cluster by frequently reading from the `system_auth` tables. |
| Furthermore, these reads are in the critical paths of many client |
| operations, and so has the potential to severely impact quality of |
| service. To mitigate this, auth data such as credentials, permissions |
| and role details are cached for a configurable period. The caching can |
| be configured (and even disabled) from `cassandra.yaml` or using a JMX |
| client. The JMX interface also supports invalidation of the various |
| caches, but any changes made via JMX are not persistent and will be |
| re-read from `cassandra.yaml` when the node is restarted. |
| |
| Each cache has 3 options which can be set: |
| |
| Validity Period:: |
| Controls the expiration of cache entries. After this period, entries |
| are invalidated and removed from the cache. |
| Refresh Rate:: |
| Controls the rate at which background reads are performed to pick up |
| any changes to the underlying data. While these async refreshes are |
| performed, caches will continue to serve (possibly) stale data. |
| Typically, this will be set to a shorter time than the validity |
| period. |
| Max Entries:: |
| Controls the upper bound on cache size. |
| |
| The naming for these options in `cassandra.yaml` follows the convention: |
| |
| * `<type>_validity_in_ms` |
| * `<type>_update_interval_in_ms` |
| * `<type>_cache_max_entries` |
| |
| Where `<type>` is one of `credentials`, `permissions`, or `roles`. |
| |
| As mentioned, these are also exposed via JMX in the mbeans under the |
| `org.apache.cassandra.auth` domain. |
| |
| == JMX access |
| |
| Access control for JMX clients is configured separately to that for CQL. |
| For both authentication and authorization, two providers are available; |
| the first based on standard JMX security and the second which integrates |
| more closely with Cassandra's own auth subsystem. |
| |
| The default settings for Cassandra make JMX accessible only from |
| localhost. To enable remote JMX connections, edit `cassandra-env.sh` (or |
| `cassandra-env.ps1` on Windows) to change the `LOCAL_JMX` setting to |
| `no`. Under the standard configuration, when remote JMX connections are |
| enabled, `standard JMX authentication <standard-jmx-auth>` is also |
| switched on. |
| |
| Note that by default, local-only connections are not subject to |
| authentication, but this can be enabled. |
| |
| If enabling remote connections, it is recommended to also use |
| xref:operating/security.adoc#jmx-with-ssl[`SSL`] connections. |
| |
| Finally, after enabling auth and/or SSL, ensure that tools which use |
| JMX, such as xref:tools/nodetool/nodetools.adoc[`nodetool`] are correctly configured and working |
| as expected. |
| |
| === Standard JMX Auth |
| |
| Users permitted to connect to the JMX server are specified in a simple |
| text file. The location of this file is set in `cassandra-env.sh` by the |
| line: |
| |
| [source,bash] |
| ---- |
| JVM_OPTS="$JVM_OPTS -Dcom.sun.management.jmxremote.password.file=/etc/cassandra/jmxremote.password" |
| ---- |
| |
| Edit the password file to add username/password pairs: |
| |
| [source,none] |
| ---- |
| jmx_user jmx_password |
| ---- |
| |
| Secure the credentials file so that only the user running the Cassandra |
| process can read it : |
| |
| [source,bash] |
| ---- |
| $ chown cassandra:cassandra /etc/cassandra/jmxremote.password |
| $ chmod 400 /etc/cassandra/jmxremote.password |
| ---- |
| |
| Optionally, enable access control to limit the scope of what defined |
| users can do via JMX. Note that this is a fairly blunt instrument in |
| this context as most operational tools in Cassandra require full |
| read/write access. To configure a simple access file, uncomment this |
| line in `cassandra-env.sh`: |
| |
| [source,bash] |
| ---- |
| #JVM_OPTS="$JVM_OPTS -Dcom.sun.management.jmxremote.access.file=/etc/cassandra/jmxremote.access" |
| ---- |
| |
| Then edit the access file to grant your JMX user readwrite permission: |
| |
| [source,none] |
| ---- |
| jmx_user readwrite |
| ---- |
| |
| Cassandra must be restarted to pick up the new settings. |
| |
| See also : |
| http://docs.oracle.com/javase/7/docs/technotes/guides/management/agent.html#gdenv[Using |
| File-Based Password Authentication In JMX] |
| |
| === Cassandra Integrated Auth |
| |
| An alternative to the out-of-the-box JMX auth is to useeCassandra's own |
| authentication and/or authorization providers for JMX clients. This is |
| potentially more flexible and secure but it come with one major caveat. |
| Namely that it is not available until [.title-ref]#after# a node has |
| joined the ring, because the auth subsystem is not fully configured |
| until that point However, it is often critical for monitoring purposes |
| to have JMX access particularly during bootstrap. So it is recommended, |
| where possible, to use local only JMX auth during bootstrap and then, if |
| remote connectivity is required, to switch to integrated auth once the |
| node has joined the ring and initial setup is complete. |
| |
| With this option, the same database roles used for CQL authentication |
| can be used to control access to JMX, so updates can be managed |
| centrally using just `cqlsh`. Furthermore, fine grained control over |
| exactly which operations are permitted on particular MBeans can be |
| acheived via xref:cql/security.adoc#grant-permission[`GRANT PERMISSION`]. |
| |
| To enable integrated authentication, edit `cassandra-env.sh` to |
| uncomment these lines: |
| |
| [source,bash] |
| ---- |
| #JVM_OPTS="$JVM_OPTS -Dcassandra.jmx.remote.login.config=CassandraLogin" |
| #JVM_OPTS="$JVM_OPTS -Djava.security.auth.login.config=$CASSANDRA_HOME/conf/cassandra-jaas.config" |
| ---- |
| |
| And disable the JMX standard auth by commenting this line: |
| |
| [source,bash] |
| ---- |
| JVM_OPTS="$JVM_OPTS -Dcom.sun.management.jmxremote.password.file=/etc/cassandra/jmxremote.password" |
| ---- |
| |
| To enable integrated authorization, uncomment this line: |
| |
| [source,bash] |
| ---- |
| #JVM_OPTS="$JVM_OPTS -Dcassandra.jmx.authorizer=org.apache.cassandra.auth.jmx.AuthorizationProxy" |
| ---- |
| |
| Check standard access control is off by ensuring this line is commented |
| out: |
| |
| [source,bash] |
| ---- |
| #JVM_OPTS="$JVM_OPTS -Dcom.sun.management.jmxremote.access.file=/etc/cassandra/jmxremote.access" |
| ---- |
| |
| With integrated authentication and authorization enabled, operators can |
| define specific roles and grant them access to the particular JMX |
| resources that they need. For example, a role with the necessary |
| permissions to use tools such as jconsole or jmc in read-only mode would |
| be defined as: |
| |
| [source,cql] |
| ---- |
| CREATE ROLE jmx WITH LOGIN = false; |
| GRANT SELECT ON ALL MBEANS TO jmx; |
| GRANT DESCRIBE ON ALL MBEANS TO jmx; |
| GRANT EXECUTE ON MBEAN 'java.lang:type=Threading' TO jmx; |
| GRANT EXECUTE ON MBEAN 'com.sun.management:type=HotSpotDiagnostic' TO jmx; |
| |
| # Grant the role with necessary permissions to use nodetool commands (including nodetool status) in read-only mode |
| GRANT EXECUTE ON MBEAN 'org.apache.cassandra.db:type=EndpointSnitchInfo' TO jmx; |
| GRANT EXECUTE ON MBEAN 'org.apache.cassandra.db:type=StorageService' TO jmx; |
| |
| # Grant the jmx role to one with login permissions so that it can access the JMX tooling |
| CREATE ROLE ks_user WITH PASSWORD = 'password' AND LOGIN = true AND SUPERUSER = false; |
| GRANT jmx TO ks_user; |
| ---- |
| |
| Fine grained access control to individual MBeans is also supported: |
| |
| [source,cql] |
| ---- |
| GRANT EXECUTE ON MBEAN 'org.apache.cassandra.db:type=Tables,keyspace=test_keyspace,table=t1' TO ks_user; |
| GRANT EXECUTE ON MBEAN 'org.apache.cassandra.db:type=Tables,keyspace=test_keyspace,table=*' TO ks_owner; |
| ---- |
| |
| This permits the `ks_user` role to invoke methods on the MBean |
| representing a single table in `test_keyspace`, while granting the same |
| permission for all table level MBeans in that keyspace to the `ks_owner` |
| role. |
| |
| Adding/removing roles and granting/revoking of permissions is handled |
| dynamically once the initial setup is complete, so no further restarts |
| are required if permissions are altered. |
| |
| See also: xref:cql/security.adoc#permissions[`Permissions`]. |
| |
| === JMX With SSL |
| |
| JMX SSL configuration is controlled by a number of system properties, |
| some of which are optional. To turn on SSL, edit the relevant lines in |
| `cassandra-env.sh` (or `cassandra-env.ps1` on Windows) to uncomment and |
| set the values of these properties as required: |
| |
| `com.sun.management.jmxremote.ssl`:: |
| set to true to enable SSL |
| `com.sun.management.jmxremote.ssl.need.client.auth`:: |
| set to true to enable validation of client certificates |
| `com.sun.management.jmxremote.registry.ssl`:: |
| enables SSL sockets for the RMI registry from which clients obtain the |
| JMX connector stub |
| `com.sun.management.jmxremote.ssl.enabled.protocols`:: |
| by default, the protocols supported by the JVM will be used, override |
| with a comma-separated list. Note that this is not usually necessary |
| and using the defaults is the preferred option. |
| `com.sun.management.jmxremote.ssl.enabled.cipher.suites`:: |
| by default, the cipher suites supported by the JVM will be used, |
| override with a comma-separated list. Note that this is not usually |
| necessary and using the defaults is the preferred option. |
| `javax.net.ssl.keyStore`:: |
| set the path on the local filesystem of the keystore containing server |
| private keys and public certificates |
| `javax.net.ssl.keyStorePassword`:: |
| set the password of the keystore file |
| `javax.net.ssl.trustStore`:: |
| if validation of client certificates is required, use this property to |
| specify the path of the truststore containing the public certificates |
| of trusted clients |
| `javax.net.ssl.trustStorePassword`:: |
| set the password of the truststore file |
| |
| See also: |
| http://docs.oracle.com/javase/7/docs/technotes/guides/management/agent.html#gdemv[Oracle |
| Java7 Docs], |
| https://www.lullabot.com/articles/monitor-java-with-jmx[Monitor Java |
| with JMX] |