Getting started with mTLS authenticators

When a certificate based authentication protocol like TLS is used for client and Internode connections, MutualTlsAuthenticator & MutualTlsInternodeAuthenticator can be used for the authentication by leveraging the client certificates from the SSL handshake.

After SSL handshake, identity from the client certificates is extracted and only authorized users will be granted access.

Before you start

Generate the certificate material you need before you enable mTLS:

  • one CA certificate that signs the server and client certificates

  • one server certificate and key for each Cassandra node

  • one client certificate and key for each user or service account

  • a truststore that contains the issuing CA

  • a keystore for each node

Keep the certificate identity format consistent with the validator you plan to use. If you use the SPIFFE validator, the SPIFFE ID must be present in the certificate SAN. If you use a CN-based validator, the CN must match the identity you want to map to a role.

What is an Identity

Operators can define their own identity for certificates by extracting some fields or information from the certificates. Implementing the interface MutualTlsCertificateValidator supports validating & extracting identities from the certificates that can be used by MutualTlsAuthenticator and MutualTlsInternodeAuthenticator to customize for the certificate conventions used in the deployment environment.

There is a default implementation of MutualTlsCertificateValidator with SPIFFE as the identity of the certificates.This requires spiffe to be present in the SAN of the certificate.

Instead of using SPIFFE based validator, a custom CN based validator that implements MutualTlsCertificateValidator could be configured by the operator if required.

Configuring mTLS authenticator for client connections

Note that the following steps uses SPIFFE identity as an example, If you are using a custom validator, use appropriate identity in place of spiffe://testdomain.com/testIdentifier/testValue.

STEP 1: Add authorized users to system_auth.identity_to_roles table

Note that only users with permissions to create/modify roles can add/remove identities. Client certificates with the identities in this table will be trusted by Cassandra.

ADD IDENTITY 'spiffe://testdomain.com/testIdentifier/testValue' TO ROLE 'read_only_user'

STEP 2: Configure Cassandra.yaml with right properties

Configure client_encryption_options for mTLS connections.

client_encryption_options:
  enabled: true
  optional: false
  keystore: conf/.keystore
  keystore_password: cassandra
  truststore: conf/.truststore
  truststore_password: cassandra
  require_client_auth: true // to enable mTLS

Configure the mTLS authenticator and validator for client connections. If you are implementing a custom validator, use that instead of the SPIFFE validator.

authenticator:
  class_name : org.apache.cassandra.auth.MutualTlsAuthenticator
  parameters :
    validator_class_name: org.apache.cassandra.auth.SpiffeCertificateValidator

STEP 3: Bounce the cluster

After the bounce, Cassandra accepts mTLS connections from the clients. If their identity is present in the identity_to_roles table, access is granted.

Verifying mTLS

Verify the setup with the same client toolchain you plan to use in production. Connect with cqlsh or a driver using the client certificate and key, run a simple query, and confirm that the mapped role can access the cluster. Repeat the connection attempt with a certificate whose identity is not present in identity_to_roles; the connection should be rejected.

Configuring mTLS with password fallback authenticator for client connections

Operators that wish to migrate cannot immediately change the configuration to require mTLS authentication as it will break existing non-mTLS based clients of the cluster. In order to make a smooth transition from non-mTLS based authentication to mTLS authentication, the operator can run Cassandra in optional mTLS mode and configure authenticator to be MutualTlsWithPasswordFallbackAuthenticator which can accept both certificate based and password based connections.

Below are the steps to configure Cassandra in optional mTLS mode with the fallback authenticator. Note that the following steps uses SPIFFE identity as an example, If you are using a custom validator, use appropriate identity in place of spiffe://testdomain.com/testIdentifier/testValue.

STEP 1: Add authorized users to system_auth.identity_to_roles table

Note that only users with permissions to create/modify roles can add/remove identities. Client certificates with the identities in this table will be trusted by Cassandra.

ADD IDENTITY 'spiffe://testdomain.com/testIdentifier/testValue' TO ROLE 'read_only_user'

STEP 2: Configure Cassandra.yaml with right properties

Configure client_encryption_options for mTLS connections. Note that require_client_auth is optional here.

client_encryption_options:
  enabled: true
  optional: true
  keystore: conf/.keystore
  keystore_password: cassandra
  truststore: conf/.truststore
  truststore_password: cassandra
  require_client_auth: optional // to enable mTLS in optional mode

Configure the fallback authenticator and validator for client connections. If you are implementing a custom validator, use that instead of the SPIFFE validator.

authenticator:
  class_name : org.apache.cassandra.auth.MutualTlsWithPasswordFallbackAuthenticator
  parameters :
    validator_class_name: org.apache.cassandra.auth.SpiffeCertificateValidator

STEP 3: Bounce the cluster

After the bounce, Cassandra accepts both mTLS and password-based connections from clients. Use this configuration only during the transition phase. Set require_client_auth to true once all clients use mTLS.

Configuring mTLS authenticator for Internode connections

The internode authenticator trusts certificates whose identities are present in internode_authenticator.parameters.trusted_peer_identities if configured.

Otherwise, it trusts connections which have the same identity as the node. When a node is making an outbound connection to another node, it uses the certificate configured in server_encryption_options.outbound_keystore. During the start of the node, identity is extracted from the outbound keystore and connections from other nodes who have the same identity will be trusted if trusted_peer_identities is not configured.

For example, if a node has testIdentity embedded in the certificate in the outbound keystore, it trusts connections from other nodes when their certificates have testIdentity embedded in them.

There is an optional configuration node_identity that can be used to verify identity extracted from the keystore to avoid any configuration errors.

STEP 1: Configure server_encryption_options in cassandra.yaml

server_encryption_options:
  internode_encryption: all
  optional: true
  keystore: conf/.keystore
  keystore_password: cassandra
  outbound_keystore: conf/.outbound_keystore
  outbound_keystore_password: cassandra
  require_client_auth: true  // for enabling mTLS
  truststore: conf/.truststore
  truststore_password: cassandra

STEP 2: Configure Internode Authenticator and Validator

Configure the mTLS internode authenticator and validator. If you are implementing a custom validator, use that instead of the SPIFFE validator.

internode_authenticator:
  class_name : org.apache.cassandra.auth.MutualTlsInternodeAuthenticator
  parameters :
    validator_class_name: org.apache.cassandra.auth.SpiffeCertificateValidator
    trusted_peer_identities : "spiffe1,spiffe2"

STEP 3: Bounce the cluster Once all nodes in the cluster are restarted, all internode communications are authenticated by mTLS.

Migration from existing password based authentication

  • For client connections, since the migration will not happen overnight, operators can run Cassandra in optional mTLS mode and use MutualTlsWithPasswordFallbackAuthenticator, which accepts both mTLS and password-based connections. Once all clients migrate to mTLS, turn off optional mode and set the authenticator to MutualTlsAuthenticator. From that point only mTLS client connections are accepted.

  • For Internode connections, while doing rolling upgrades from non-mTLS based configuration to mTLS based configuration, set server_encryption_options.optional: true for the new nodes so they can connect to old nodes that are still using non-mTLS based configuration during upgrade. After this, change the internode authenticator to MutualTlsInternodeAuthenticator and turn off the optional mode by setting server_encryption_options.optional: false.