Enabling JMX authentication and authorization

Steps to enable remote JMX connections.

By default, JMX security is disabled and accessible only from localhost without authentication as shown in the following lines from the cassandra-env.ps1 file:
if [ "$LOCAL_JMX" = "yes" ]; then
  $env:JVM_OPTS="$env:$JVM_OPTS -Dcassandra.jmx.local.port=$JMX_PORT -XX:+DisableExplicitGC"

Configuring JMX authentication and authorization can be accomplished using local password and access files to set the usernames, passwords and access permissions. In Cassandra 3.6 and later, Cassandra's internal authentication and authorization can optionally be configured for JMX security.

These two methods work for remote authentication and authorization; the difference is just the location of the configuration settings in the cassandra-env.ps1 file. Local configuration is placed within the if ["$LOCAL_JMX" = "yes']; then block in the file, whereas remote configuration is placed with the else block.

Procedure

AUTHENTICATION AND AUTHORIZATION USING LOCAL FILES

  • By default, JMX security is disabled and accessible only from localhost as shown in the following lines from the cassandra-env.ps1 file:
    if [ "$LOCAL_JMX" = "yes" ]; then
      $env:JVM_OPTS="$env:$JVM_OPTS -Dcassandra.jmx.local.port=$JMX_PORT -XX:+DisableExplicitGC"
  • Change $LOCAL_JMX to no. Add the following lines in the remote block in the cassandra-env.ps1 file:
    $env:JVM_OPTS="$env:JVM_OPTS -Dcom.sun.management.jmxremote.authenticate=true"
    $env:JVM_OPTS="$env:JVM_OPTS -Dcom.sun.management.jmxremote.password.file=/etc/cassandra/jmxremote.password"
    $env:JVM_OPTS="$env:JVM_OPTS -Dcom.sun.management.jmxremote.access.file=/etc/cassandra/jmxremote.access"
  • Create a password file and add the user and password for JMX-compliant utilities, specifying the credentials for your environment. The default location of the password file in the cassandra-env.ps1 is /etc/cassandra/jmxremote.password.
    cassandra cassandra
    <new_superuser> <new_superuser_password>
    <some_other_user> <some_other_user_password>
    controlRole someOtherHardToRememberPassword
    Important: The default superuser account is a security hazard! This account is used only for the purposes of illustration.
  • For the user running Cassandra, change permission of jmxremote.password to read only.
  • Create an access file and enter the following information. The default location of the access file in the cassandra-env.ps1 is /etc/cassandra/jmxremote.access.
    cassandra readwrite
    <new_superuser> readwrite
    <some_other_user> readonly
    controlRole readwrite \
    create javax.management.monitor.,javax.management.timer. \
    unregister
    Important: The default superuser account is a security hazard! This account is used only for the purposes of illustration.
    The readonly permission allows the JMX client to read an MBean's attributes and receive notifications. The readwrite permission allows the JMX client to set attributes, invoke operations, and create and remove MBeans, in addition to reading an MBean's attributes and receives notifications.
  • For the user running Cassandra, change permission of jmxremote.access to read only.
  • Restart Cassandra to make the change effective.
  • Check that nodetool status requires the username and password in order to execute. The command should fail without authentication if everything is configured correctly.
    C:\> %CASSANDRA_HOME%\bin\nodetool status
  • Run nodetool status with the cassandra user and password.
    C:\> %CASSANDRA_HOME%\bin\nodetool -u cassandra -pw cassandra status

AUTHENTICATION AND AUTHORIZATION WITH CASSANDRA INTERNALS - CASSANDRA 3.6 AND LATER

  • By default, JMX security is disabled and accessible only from localhost as shown in the following lines from the cassandra-env.ps1 file:
    if [ "$LOCAL_JMX" = "yes" ]; then
      $env:JVM_OPTS="$env:$JVM_OPTS -Dcassandra.jmx.local.port=$JMX_PORT -XX:+DisableExplicitGC"
  • Comment out the existing line and add or uncomment the following lines in either the local or remote block in the cassandra-env.ps1 file:
    $env:JVM_OPTS="$env:JVM_OPTS -Dcom.sun.management.jmxremote.authenticate=true"
    $env:JVM_OPTS="$env:JVM_OPTS -Dcassandra.jmx.remote.login.config=CassandraLogin"'
    $env:JVM_OPTS="$env:JVM_OPTS -Djava.security.auth.login.config=$CASSANDRA_HOME/conf/cassandra-jaas.config"
    $env:JVM_OPTS="$env:JVM_OPTS -Dcassandra.jmx.authorizer=org.apache.cassandra.auth.jmx.AuthorizationProxy"
  • And comment out the following lines in the cassandra-env.ps1 file:
    $env:JVM_OPTS="$env:JVM_OPTS -Dcom.sun.management.jmxremote.password.file=/etc/cassandra/jmxremote.password"
    $env:JVM_OPTS="$env:JVM_OPTS -Dcom.sun.management.jmxremote.access.file=/etc/cassandra/jmxremote.access"
  • Change authentication in the cassandra.yaml file to PasswordAuthenticator.
    authenticator: PasswordAuthenticator
  • Change authorization in the cassandra.yaml file to CassandraAuthorizer.
    authorizer: CassandraAuthorizer
  • Restart Cassandra to make the change effective.
  • Check that nodetool status requires the username and password in order to execute. The command should fail without authentication if everything is configured correctly.
    $ nodetool -u cassandra -pw cassandra status
    The location of the cassandra-env.ps1 is:
    Windows 3.0 installations C:\Program Files\DataStax Community\apache-cassandra\conf\cassandra-env.ps1
    Windows 3.x installations C:\Program Files\DataStax-DDC\apache-cassandra\conf\cassandra-env.ps1
    CASSANDRA_HOME
    Windows 3.0 installations C:\Program Files\Datastax Community\apache-cassandra\
    Windows 3.x installations C:\Program Files\Datastax-DDC\apache-cassandra\
    On a standard Windows installation, the installation wizard creates %CASSANDRA_HOME% as an environment variable.
  • Cassandra authorization can be used to grant and revoke permissions to database objects, including MBeans.

SPECIFYING JMX AUTHENTICATION ON COMMAND LINE

  • Generally, JMX settings are inserted into the cassandra-env.ps1 file. However, these options can be specified at the command line:
    cassandra -Dcom.sun.management.jmxremote.authenticate=true
      -Dcom.sun.management.jmxremote.password.file=\etc\cassandra\jmxremote.password

Example

If you run nodetool status without user and password when authentication and authorization are configured, you'll see an error similar to:
Exception in thread "main" java.lang.SecurityException: Authentication failed! Credentials required
at com.sun.jmx.remote.security.JMXPluggableAuthenticator.authenticationFailure(Unknown Source)
at com.sun.jmx.remote.security.JMXPluggableAuthenticator.authenticate(Unknown Source)
at sun.management.jmxremote.ConnectorBootstrap$AccessFileCheckerAuthenticator.authenticate(Unknown Source)
at javax.management.remote.rmi.RMIServerImpl.doNewClient(Unknown Source)
at javax.management.remote.rmi.RMIServerImpl.newClient(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at sun.rmi.server.UnicastServerRef.dispatch(Unknown Source)
at sun.rmi.transport.Transport$1.run(Unknown Source)
at sun.rmi.transport.Transport$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.Transport.serviceCall(Unknown Source)
at sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown Source)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(Unknown Source)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(Unknown Source)
at sun.rmi.transport.StreamRemoteCall.executeCall(Unknown Source)
at sun.rmi.server.UnicastRef.invoke(Unknown Source)
at javax.management.remote.rmi.RMIServerImpl_Stub.newClient(Unknown Source)
at javax.management.remote.rmi.RMIConnector.getConnection(Unknown Source)
at javax.management.remote.rmi.RMIConnector.connect(Unknown Source)
at javax.management.remote.JMXConnectorFactory.connect(Unknown Source)
at org.apache.cassandra.tools.NodeProbe.connect(NodeProbe.java:146)
at org.apache.cassandra.tools.NodeProbe.<init>(NodeProbe.java:116)
at org.apache.cassandra.tools.NodeCmd.main(NodeCmd.java:1099)