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 toMutualTlsAuthenticator. 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: truefor 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 toMutualTlsInternodeAuthenticatorand turn off the optional mode by settingserver_encryption_options.optional: false.