This page is meant as a template for writing a CEP. To create a CIP choose Tools->Copy on this page and modify with your content and replace the heading with the next CIP number and a description of your issue. Replace anything in italics with your own description.

Status

Current stateDRAFT

Discussion threadhere

JIRAhere

Released: -

Please keep the discussion on the mailing list rather than commenting on the wiki (wiki discussions get unwieldy fast).

Motivation

Cassandra currently doesn’t have any certificate based authenticator for both client connections and internode connections. If one wants to use certificate based authentication protocol like TLS, in which clients send their certificates for the TLS handshake, we can leverage the information from the client certificate to identify a client. Using this authentication mechanism one can avoid the pain of password generations, sharing and rotation.

Audience

  • Users and operators of clusters who wants to use mTLS for client communications and internode communications
  • Cassandra developers who wants to contribute to authentication related areas

Goals

  • To introduce certificate based mTLS authenticators for internode and client connections MutualTlsAuthenticator,MutualTlsInternodeAuthenticator & MutualTlsWithPasswordFallbackAuthenticator for optional mode operation
  • Implement a reference implementation of MutualTlsCertificateValidator called SpiffeCertificateValidator whose identity is SPIFFE that is embedded in SAN of the client certificate. One can implement their own CertificateValidator to match their needs and configure it in Cassandra.yaml

Implementation and Proposed Changes

  • Certificate Identities → An identity is a unique string that can be extracted from various fields of a client certificate EX: Identity of a certificate can be CN of the certificate, An identifier like SPIFFE that can be embedded in SAN of the certificate or it could be a combination of several other custom fields from the certificates
  • New interface MutualTlsCertificateValidator is introduced so that one can define their own identity of certificates and validation checks that are to be performed on the certificates. The class that implements the interface provides the logic to extract identities from certificates and validation checks
  • SpiffeCertificateValidator A reference Implementation of MutualTlsCertificateValidator that can extract identities in the form of SPIFFE. This can be used for both client connections and internode connections

MutualTlsAuthenticator for client connections

How to use this authenticator?
It can be configured in cassandra.yaml in the authenticator section. Below is the configuration with SpiffeCertificateValidator for which the identity is SPIFFE, but one can provide their own implementation of MutualTlsCertificateValidator and can configure it for the validator_class_name

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

As part of the MutualTlsAuthenticator implementation, added a new table system_auth.identity_to_role to store authorized identities for each role. Only client certificates with on of these identities will be given access.
EX:

IdentityRole
ID1Role1
ID2Role1
ID3Role2
ID3Role3


During a client connection after SSL/TLS handshake the following happens

  1. MutualTlsAuthenticator extracts identity of the client certificate using the validator configured for validator_class_name in cassandra.yaml for authenticator
  2. Checks if the extracted client identity is present in the identity_to_role table or not. The table is cached in IdentityCache to avoid making a database call on each request
  3. If the identity is present, grant the access otherwise reject the connection

MutualTlsWithPasswordFallbackAuthenticator

When C* is running in optional mTLS mode, it accepts both certificate based & password based connections, which will be during transition from password based authentication to certificate based authentication. One can configure the authenticator to be MutualTlsWithPasswordFallbackAuthenticator which can authenticate both certificate based users and username/password based users. This will be very helpful during the transition phase where migrating clients to mTLS might take several days.
One can configure this authenticator by configuring cassandra.yaml like the following

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

Authorized mTLS users should be added to system_auth.identity_to_role similar to MutualTlsAuthenticator & authorized usernames&password should be added to system_auth.identity_to_role

MutualTlsAuthenticator for internode connections

It can be configured in cassandra.yaml in the internode_authenticator section. Below is the configuration with SpiffeCertificateValidator for which the identity is SPIFFE, but one can provide their own implementation of MutualTlsCertificateValidator and can configure it for the validator_class_name

internode_authenticator:
class_name : org.apache.cassandra.auth.MutualTlsInternodeAuthenticator
parameters :
validator_class_name: org.apache.cassandra.auth.SpiffeCertificateValidator
   trusted_peer_identities: "spiffe1,spiffe2"
  node_identity: "spiffe1"
  • MutualTlsInternodeAuthenticator
    • Trusts all identities configured in trusted_peer_identities  if configured and ignores all other configurations
    • otherwise, it extracts identity from outbound_keystore of server_encryption_options (the identity that the node uses for making outbound connections) and trusts connections with that identity
    • optionally  node_identity  can be configured in the yaml, to validate extracted identity from the outbound keystore, if it doesn't match C* will not start
  • After the SSL/TLS handshake for internode connections, identity is extracted from other node’s certificate using the validator configured for validator_class_name in cassandra.yaml for internode_authenticator

New Cqlsh commands to add identities

Adding the following Cqlsh commands to add add/remove identities to the system_auth.identity_to_role table.

ADD IDENTITY 'testIdentity' TO ROLE 'testRole';
DROP IDENTITY 'testIdentity';

Both the above statements require the users to have appropriate permissions to add/drop identities.

New or Changed Public Interfaces

Added a new Interface MutualTlsCertificateValidator to make the validation and identity extraction of certificates pluggable

/**
* Interface for certificate validation and authorization for mTLS authenticators.
*
* This interface can be implemented to provide logic for extracting custom identities from client certificates
* to uniquely identify the certificates. It can also be used to provide custom authorization logic to authenticate
* clients using client certificates during mTLS connections.
*/
public interface MutualTlsCertificateValidator
{
/**
* Perform any checks that are to be performed on the certificate before making authorization check to grant the
* access to the client during mTLS connection.
*
* For example
* - Verifying CA information
* - Checking CN information
* - Validating Issuer information
* - Checking organization information etc
*
*
@param clientCertificateChain client certificate chain
*
@return returns if the certificate is valid or not
*/
boolean isValidCertificate(Certificate[] clientCertificateChain);

/**
* This method should provide logic to extract identity out of a certificate to perform mTLS authentication.
*
* An example of identity could be the following
* - an identifier in SAN of the certificate like SPIFFE
* - CN of the certificate
* - any other fields in the certificate can be combined and be used as indentifier of the certificate
*
*
@param clientCertificateChain client certificate chain
*
@return identifier extracted from certificate
*
@throws AuthenticationException when identity cannot be extracted
*/
String identity(Certificate[] clientCertificateChain) throws AuthenticationException;

}

Compatibility, Deprecation, and Migration Plan

During migrations, these proposed changes should not create any issues. MutualTlsAuthenticators will be used only when an operator configures authenticator & InternodeAuthenticator sections of cassandra.yaml file with MutualTlsAutheticator & MutualTlsInternodeAuthenticator. However care should be taken to configure server_encryption_options & client_encryption_options appropriately. For example If we do not enable SSL and configure the authenticator to be MutualTlsAuthenticator, the authenticator will throw a configuration exception and will not start C* instance. MutualTlsAuthenticators should be enabled only when require_client_auth setting is true in both server_encryption_options & client_encryption_options

During rolling upgrades, there might be TLS/SSL issues because of nodes running in mixed, new nodes will fail to connect to old nodes on which mTLS is not enabled. CASSANDRA-17923 was added to address the issue during upgrades. We added fallback to other authentication strategies, when we run C* with optional mode in server_encryption_options

Test Plan

JUnit tests are added in the patch by generating self-signed certificates. further verification can be done by testing using CCM


  • No labels