Provide keystore_password_file and truststore_password_file options to read credentials from a file

patch by Maulin Vasavada; reviewed by Stefan Miklosovic, Maxwell Guo for CASSANDRA-13428
This commit is contained in:
maulin-vasavada 2025-02-17 20:06:11 -08:00 committed by Stefan Miklosovic
parent ca227d82ba
commit 37fe4b679c
No known key found for this signature in database
GPG Key ID: 32F35CB2F546D93E
20 changed files with 960 additions and 123 deletions

View File

@ -1,4 +1,5 @@
5.1
* Provide keystore_password_file and truststore_password_file options to read credentials from a file (CASSANDRA-13428)
* Unregistering a node should also remove it from tokenMap if it is there and recalculate the placements (CASSANDRA-20346)
* Fix PartitionUpdate.isEmpty deserialization issue to avoid potential EOFException (CASSANDRA-20345)
* Avoid adding LEFT nodes to tokenMap on upgrade from gossip (CASSANDRA-20344)

View File

@ -1723,6 +1723,10 @@ server_encryption_options:
# Set to a valid keystore if internode_encryption is dc, rack or all
keystore: conf/.keystore
#keystore_password: cassandra
# Optional configuration to specify password for keystore in a separate file
# When keystore_password and keystore_password_file both are specified, the keystore_password will take precedence
# The password in the file should be on the first line
#keystore_password_file: conf/keystore_passwordfile.txt
# Configure the way Cassandra creates SSL contexts.
# To use PEM-based key material, see org.apache.cassandra.security.PEMBasedSslContextFactory
# ssl_context_factory:
@ -1734,11 +1738,20 @@ server_encryption_options:
# to create SSLContext. By default, outbound_keystore is the same as keystore indicating mTLS is not enabled.
# outbound_keystore: conf/.keystore
# outbound_keystore_password: cassandra
# Optional configuration to specify password for keystore in a separate file
# When outbound_keystore_password and outbound_keystore_password_file both are specified,
# the outbound_keystore_password will take precedence
# The password in the file should be on the first line
#outbound_keystore_password_file: conf/outbound_keystore_passwordfile.txt
# Verify peer server certificates
require_client_auth: false
# Set to a valid trustore if require_client_auth is true
truststore: conf/.truststore
#truststore_password: cassandra
# Optional configuration to specify password for truststore in a separate file
# When truststore_password and truststore_password_file both are specified, the truststore_password will take precedence
# The password in the file should be on the first line
#truststore_password_file: conf/truststore_passwordfile.txt
# Verify that the host name in the certificate matches the connected host
require_endpoint_verification: false
# More advanced defaults:
@ -1780,6 +1793,10 @@ client_encryption_options:
# Set keystore and keystore_password to valid keystores if enabled is true
keystore: conf/.keystore
#keystore_password: cassandra
# Optional configuration to specify password for keystore in a separate file
# When keystore_password and keystore_password_file both are specified, the keystore_password will take precedence
# The password in the file should be on the first line
#keystore_password_file: conf/keystore_passwordfile.txt
# Configure the way Cassandra creates SSL contexts.
# To use PEM-based key material, see org.apache.cassandra.security.PEMBasedSslContextFactory
# ssl_context_factory:
@ -1794,6 +1811,10 @@ client_encryption_options:
# Set trustore and truststore_password if require_client_auth is true
# truststore: conf/.truststore
# truststore_password: cassandra
# Optional configuration to specify password for truststore in a separate file
# When truststore_password and truststore_password_file both are specified, the truststore_password will take precedence
# The password in the file should be on the first line
#truststore_password_file: conf/truststore_passwordfile.txt
# More advanced defaults:
# protocol: TLS
# store_type: JKS
@ -1844,8 +1865,16 @@ client_encryption_options:
# accepted_protocols: [TLSv1.2,TLSv1.3,TLSv1.1]
# keystore: conf/cassandra_ssl.keystore
# keystore_password: cassandra
# Optional configuration to specify password for keystore in a separate file
# When keystore_password and keystore_password_file both are specified, the keystore_password will take precedence
# The password in the file should be on the first line
# keystore_password_file: conf/keystore_passwordfile.txt
# truststore: conf/cassandra_ssl.truststore
# truststore_password: cassandra
# Optional configuration to specify password for truststore in a separate file
# When truststore_password and truststore_password_file both are specified, the truststore_password will take precedence
# The password in the file should be on the first line
# truststore_password_file: conf/truststore_passwordfile.txt
#
# jmx authentication and authorization options.
# authenticate: false

View File

@ -1613,6 +1613,10 @@ server_encryption_options:
# Set to a valid keystore if internode_encryption is dc, rack or all
keystore: conf/.keystore
#keystore_password: cassandra
# Optional configuration to specify password for keystore in a separate file
# When keystore_password and keystore_password_file both are specified, the keystore_password will take precedence
# The password in the file should be on the first line
#keystore_password_file: conf/keystore_passwordfile.txt
# Configure the way Cassandra creates SSL contexts.
# To use PEM-based key material, see org.apache.cassandra.security.PEMBasedSslContextFactory
# ssl_context_factory:
@ -1624,11 +1628,20 @@ server_encryption_options:
# to create SSLContext. By default, outbound_keystore is the same as keystore indicating mTLS is not enabled.
# outbound_keystore: conf/.keystore
# outbound_keystore_password: cassandra
# Optional configuration to specify password for keystore in a separate file
# When outbound_keystore_password and outbound_keystore_password_file both are specified,
# the outbound_keystore_password will take precedence
# The password in the file should be on the first line
#outbound_keystore_password_file: conf/outbound_keystore_passwordfile.txt
# Verify peer server certificates
require_client_auth: false
# Set to a valid trustore if require_client_auth is true
truststore: conf/.truststore
#truststore_password: cassandra
# Optional configuration to specify password for truststore in a separate file
# When truststore_password and truststore_password_file both are specified, the truststore_password will take precedence
# The password in the file should be on the first line
#truststore_password_file: conf/truststore_passwordfile.txt
# Verify that the host name in the certificate matches the connected host
require_endpoint_verification: false
# More advanced defaults:
@ -1663,6 +1676,10 @@ client_encryption_options:
# Set keystore and keystore_password to valid keystores if enabled is true
keystore: conf/.keystore
#keystore_password: cassandra
# Optional configuration to specify password for keystore in a separate file
# When keystore_password and keystore_password_file both are specified, the keystore_password will take precedence
# The password in the file should be on the first line
#keystore_password_file: conf/keystore_passwordfile.txt
# Configure the way Cassandra creates SSL contexts.
# To use PEM-based key material, see org.apache.cassandra.security.PEMBasedSslContextFactory
# ssl_context_factory:
@ -1677,6 +1694,10 @@ client_encryption_options:
# Set trustore and truststore_password if require_client_auth is true
# truststore: conf/.truststore
# truststore_password: cassandra
# Optional configuration to specify password for truststore in a separate file
# When truststore_password and truststore_password_file both are specified, the truststore_password will take precedence
# The password in the file should be on the first line
#truststore_password_file: conf/truststore_passwordfile.txt
# More advanced defaults:
# protocol: TLS
# store_type: JKS
@ -1718,8 +1739,16 @@ client_encryption_options:
# accepted_protocols: [TLSv1.2,TLSv1.3,TLSv1.1]
# keystore: conf/cassandra_ssl.keystore
# keystore_password: cassandra
# Optional configuration to specify password for keystore in a separate file
# When keystore_password and keystore_password_file both are specified, the keystore_password will take precedence
# The password in the file should be on the first line
# keystore_password_file: conf/keystore_passwordfile.txt
# truststore: conf/cassandra_ssl.truststore
# truststore_password: cassandra
# Optional configuration to specify password for truststore in a separate file
# When truststore_password and truststore_password_file both are specified, the truststore_password will take precedence
# The password in the file should be on the first line
# truststore_password_file: conf/truststore_passwordfile.txt
#
# jmx authentication and authorization options.
# authenticate: false

View File

@ -100,6 +100,28 @@ YAML!)
-----END CERTIFICATE-----
----
* Configuration: PEM private key's password specified via a file
[source,yaml]
----
client/server_encryption_options:
ssl_context_factory:
class_name: org.apache.cassandra.security.PEMBasedSslContextFactory
parameters:
private_key: |
-----BEGIN ENCRYPTED PRIVATE KEY----- OR -----BEGIN PRIVATE KEY-----
<your base64 encoded private key>
-----END ENCRYPTED PRIVATE KEY----- OR -----END PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
<your base64 encoded certificate chain>
-----END CERTIFICATE-----
trusted_certificates: |
-----BEGIN CERTIFICATE-----
<your base64 encoded certificate>
-----END CERTIFICATE-----
keystore_password_file: "<file having your password for the encrypted private key>"
----
* Configuration: PEM keys/certs defined in files
[source,yaml]
@ -112,6 +134,18 @@ YAML!)
truststore: <file path to the truststore file in the PEM format>
----
* Configuration: PEM private key's password specified via a file
[source,yaml]
----
client/server_encryption_options:
ssl_context_factory:
class_name: org.apache.cassandra.security.PEMBasedSslContextFactory
keystore: <file path to the keystore file in the PEM format with the private key and the certificate chain>
keystore_password_file: "<file having your password for the encrypted private key>"
truststore: <file path to the truststore file in the PEM format>
----
== SSL Certificate Hot Reloading
Beginning with Cassandra 4, Cassandra supports hot reloading of SSL
@ -590,11 +624,27 @@ jmx_encryption_options:
truststore_password: cassandra
----
Below is an example of configuring JMX SSL in `cassandra.yaml` with password files for keystore and truststore.
[source,yaml]
----
jmx_encryption_options:
enabled: true
cipher_suites: [TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256]
accepted_protocols: [TLSv1.2,TLSv1.3,TLSv1.1]
keystore: test/conf/cassandra_ssl_test.keystore
keystore_password_file: test/conf/keystore_passwordfile.txt
truststore: test/conf/cassandra_ssl_test.truststore
truststore_password: cassandra
truststore_password_file: test/conf/truststore_passwordfile.txt
----
Similar to `client/server_encryption_options`, you can specify PEM-based
key material or customize the SSL configuration using
`ssl_context_factory` in `jmx_encryption_options`.
Below is an example of configuring PEM based key material,
Below is an example of configuring PEM based key material. You can use `keystore_password_file`
configuration with in-line PEM as documented priorly in case you have stored the password for the
keystore in a file.
[source,yaml]
----
jmx_encryption_options:

View File

@ -150,10 +150,12 @@ public class KubernetesSecretsSslContextFactory extends FileBasedSslContextFacto
public KubernetesSecretsSslContextFactory()
{
keystoreContext = new FileBasedStoreContext(getString(EncryptionOptions.ConfigKey.KEYSTORE.toString(), KEYSTORE_PATH_VALUE),
getValueFromEnv(KEYSTORE_PASSWORD_ENV_VAR_NAME, DEFAULT_KEYSTORE_PASSWORD));
getValueFromEnv(KEYSTORE_PASSWORD_ENV_VAR_NAME, DEFAULT_KEYSTORE_PASSWORD),
null);
trustStoreContext = new FileBasedStoreContext(getString(EncryptionOptions.ConfigKey.TRUSTSTORE.toString(), TRUSTSTORE_PATH_VALUE),
getValueFromEnv(TRUSTSTORE_PASSWORD_ENV_VAR_NAME, DEFAULT_TRUSTSTORE_PASSWORD));
getValueFromEnv(TRUSTSTORE_PASSWORD_ENV_VAR_NAME, DEFAULT_TRUSTSTORE_PASSWORD),
null);
keystoreLastUpdatedTime = System.nanoTime();
keystoreUpdatedTimeSecretKeyPath = getString(ConfigKeys.KEYSTORE_UPDATED_TIMESTAMP_PATH,
@ -168,11 +170,13 @@ public class KubernetesSecretsSslContextFactory extends FileBasedSslContextFacto
super(parameters);
keystoreContext = new FileBasedStoreContext(getString(EncryptionOptions.ConfigKey.KEYSTORE.toString(), KEYSTORE_PATH_VALUE),
getValueFromEnv(getString(ConfigKeys.KEYSTORE_PASSWORD_ENV_VAR,
KEYSTORE_PASSWORD_ENV_VAR_NAME), DEFAULT_KEYSTORE_PASSWORD));
KEYSTORE_PASSWORD_ENV_VAR_NAME), DEFAULT_KEYSTORE_PASSWORD),
null);
trustStoreContext = new FileBasedStoreContext(getString(EncryptionOptions.ConfigKey.TRUSTSTORE.toString(), TRUSTSTORE_PATH_VALUE),
getValueFromEnv(getString(ConfigKeys.TRUSTSTORE_PASSWORD_ENV_VAR,
TRUSTSTORE_PASSWORD_ENV_VAR_NAME), DEFAULT_TRUSTSTORE_PASSWORD));
TRUSTSTORE_PASSWORD_ENV_VAR_NAME), DEFAULT_TRUSTSTORE_PASSWORD),
null);
keystoreLastUpdatedTime = System.nanoTime();
keystoreUpdatedTimeSecretKeyPath = getString(ConfigKeys.KEYSTORE_UPDATED_TIMESTAMP_PATH,
KEYSTORE_UPDATED_TIMESTAMP_PATH_VALUE);

View File

@ -114,9 +114,13 @@ public class EncryptionOptions
public final String keystore;
@Nullable
public final String keystore_password;
@Nullable
public final String keystore_password_file;
public final String truststore;
@Nullable
public final String truststore_password;
@Nullable
public final String truststore_password_file;
public final List<String> cipher_suites;
protected String protocol;
protected List<String> accepted_protocols;
@ -153,10 +157,13 @@ public class EncryptionOptions
{
KEYSTORE("keystore"),
KEYSTORE_PASSWORD("keystore_password"),
KEYSTORE_PASSWORD_FILE("keystore_password_file"),
OUTBOUND_KEYSTORE("outbound_keystore"),
OUTBOUND_KEYSTORE_PASSWORD("outbound_keystore_password"),
OUTBOUND_KEYSTORE_PASSWORD_FILE("outbound_keystore_password_file"),
TRUSTSTORE("truststore"),
TRUSTSTORE_PASSWORD("truststore_password"),
TRUSTSTORE_PASSWORD_FILE("truststore_password_file"),
CIPHER_SUITES("cipher_suites"),
PROTOCOL("protocol"),
ACCEPTED_PROTOCOLS("accepted_protocols"),
@ -199,8 +206,10 @@ public class EncryptionOptions
new HashMap<>());
keystore = "conf/.keystore";
keystore_password = null;
keystore_password_file = null;
truststore = "conf/.truststore";
truststore_password = null;
truststore_password_file = null;
cipher_suites = null;
protocol = null;
accepted_protocols = null;
@ -214,18 +223,22 @@ public class EncryptionOptions
certificate_validity_warn_threshold = null;
}
public EncryptionOptions(ParameterizedClass ssl_context_factory, String keystore, String keystore_password,
String truststore, String truststore_password, List<String> cipher_suites,
String protocol, List<String> accepted_protocols, String algorithm, String store_type,
String require_client_auth, boolean require_endpoint_verification, Boolean enabled,
Boolean optional, DurationSpec.IntMinutesBound max_certificate_validity_period,
public EncryptionOptions(ParameterizedClass ssl_context_factory,
String keystore, String keystore_password, String keystore_password_file,
String truststore, String truststore_password, String truststore_password_file,
List<String> cipher_suites, String protocol, List<String> accepted_protocols,
String algorithm, String store_type, String require_client_auth,
boolean require_endpoint_verification, Boolean enabled, Boolean optional,
DurationSpec.IntMinutesBound max_certificate_validity_period,
DurationSpec.IntMinutesBound certificate_validity_warn_threshold)
{
this.ssl_context_factory = ssl_context_factory;
this.keystore = keystore;
this.keystore_password = keystore_password;
this.keystore_password_file = keystore_password_file;
this.truststore = truststore;
this.truststore_password = truststore_password;
this.truststore_password_file = truststore_password_file;
this.cipher_suites = cipher_suites;
this.protocol = protocol;
this.accepted_protocols = accepted_protocols;
@ -244,8 +257,10 @@ public class EncryptionOptions
ssl_context_factory = options.ssl_context_factory;
keystore = options.keystore;
keystore_password = options.keystore_password;
keystore_password_file = options.keystore_password_file;
truststore = options.truststore;
truststore_password = options.truststore_password;
truststore_password_file = options.truststore_password_file;
cipher_suites = options.cipher_suites;
protocol = options.protocol;
accepted_protocols = options.accepted_protocols;
@ -324,8 +339,10 @@ public class EncryptionOptions
*/
putSslContextFactoryParameter(sslContextFactoryParameters, ConfigKey.KEYSTORE, this.keystore);
putSslContextFactoryParameter(sslContextFactoryParameters, ConfigKey.KEYSTORE_PASSWORD, this.keystore_password);
putSslContextFactoryParameter(sslContextFactoryParameters, ConfigKey.KEYSTORE_PASSWORD_FILE, this.keystore_password_file);
putSslContextFactoryParameter(sslContextFactoryParameters, ConfigKey.TRUSTSTORE, this.truststore);
putSslContextFactoryParameter(sslContextFactoryParameters, ConfigKey.TRUSTSTORE_PASSWORD, this.truststore_password);
putSslContextFactoryParameter(sslContextFactoryParameters, ConfigKey.TRUSTSTORE_PASSWORD_FILE, this.truststore_password_file);
putSslContextFactoryParameter(sslContextFactoryParameters, ConfigKey.CIPHER_SUITES, this.cipher_suites);
putSslContextFactoryParameter(sslContextFactoryParameters, ConfigKey.PROTOCOL, this.protocol);
putSslContextFactoryParameter(sslContextFactoryParameters, ConfigKey.ACCEPTED_PROTOCOLS, this.accepted_protocols);
@ -502,56 +519,72 @@ public class EncryptionOptions
public EncryptionOptions withSslContextFactory(ParameterizedClass sslContextFactoryClass)
{
return new EncryptionOptions(sslContextFactoryClass, keystore, keystore_password, truststore,
truststore_password, cipher_suites, protocol, accepted_protocols, algorithm,
return new EncryptionOptions(sslContextFactoryClass, keystore, keystore_password, keystore_password_file, truststore,
truststore_password, truststore_password_file, cipher_suites, protocol, accepted_protocols, algorithm,
store_type, require_client_auth, require_endpoint_verification, enabled,
optional, max_certificate_validity_period, max_certificate_validity_period).applyConfig();
}
public EncryptionOptions withKeyStore(String keystore)
{
return new EncryptionOptions(ssl_context_factory, keystore, keystore_password, truststore,
truststore_password, cipher_suites, protocol, accepted_protocols, algorithm,
return new EncryptionOptions(ssl_context_factory, keystore, keystore_password, keystore_password_file, truststore,
truststore_password, truststore_password_file, cipher_suites, protocol, accepted_protocols, algorithm,
store_type, require_client_auth, require_endpoint_verification, enabled,
optional, max_certificate_validity_period, max_certificate_validity_period).applyConfig();
}
public EncryptionOptions withKeyStorePassword(String keystore_password)
{
return new EncryptionOptions(ssl_context_factory, keystore, keystore_password, truststore,
truststore_password, cipher_suites, protocol, accepted_protocols, algorithm,
return new EncryptionOptions(ssl_context_factory, keystore, keystore_password, keystore_password_file, truststore,
truststore_password, truststore_password_file, cipher_suites, protocol, accepted_protocols, algorithm,
store_type, require_client_auth, require_endpoint_verification, enabled,
optional, max_certificate_validity_period, max_certificate_validity_period).applyConfig();
}
public EncryptionOptions withKeyStorePasswordFile(String keystore_password_file)
{
return new EncryptionOptions(ssl_context_factory, keystore, keystore_password, keystore_password_file, truststore,
truststore_password, truststore_password_file, cipher_suites, protocol, accepted_protocols, algorithm,
store_type, require_client_auth, require_endpoint_verification, enabled,
optional, max_certificate_validity_period, max_certificate_validity_period).applyConfig();
}
public EncryptionOptions withTrustStore(String truststore)
{
return new EncryptionOptions(ssl_context_factory, keystore, keystore_password, truststore,
truststore_password, cipher_suites, protocol, accepted_protocols, algorithm,
return new EncryptionOptions(ssl_context_factory, keystore, keystore_password, keystore_password_file, truststore,
truststore_password, truststore_password_file, cipher_suites, protocol, accepted_protocols, algorithm,
store_type, require_client_auth, require_endpoint_verification, enabled,
optional, max_certificate_validity_period, max_certificate_validity_period).applyConfig();
}
public EncryptionOptions withTrustStorePassword(String truststore_password)
{
return new EncryptionOptions(ssl_context_factory, keystore, keystore_password, truststore,
truststore_password, cipher_suites, protocol, accepted_protocols, algorithm,
return new EncryptionOptions(ssl_context_factory, keystore, keystore_password, keystore_password_file, truststore,
truststore_password, truststore_password_file, cipher_suites, protocol, accepted_protocols, algorithm,
store_type, require_client_auth, require_endpoint_verification, enabled,
optional, max_certificate_validity_period, max_certificate_validity_period).applyConfig();
}
public EncryptionOptions withTrustStorePasswordFile(String truststore_password_file)
{
return new EncryptionOptions(ssl_context_factory, keystore, keystore_password, keystore_password_file, truststore,
truststore_password, truststore_password_file, cipher_suites, protocol, accepted_protocols, algorithm,
store_type, require_client_auth, require_endpoint_verification, enabled,
optional, max_certificate_validity_period, max_certificate_validity_period).applyConfig();
}
public EncryptionOptions withCipherSuites(List<String> cipher_suites)
{
return new EncryptionOptions(ssl_context_factory, keystore, keystore_password, truststore,
truststore_password, cipher_suites, protocol, accepted_protocols, algorithm,
return new EncryptionOptions(ssl_context_factory, keystore, keystore_password, keystore_password_file, truststore,
truststore_password, truststore_password_file, cipher_suites, protocol, accepted_protocols, algorithm,
store_type, require_client_auth, require_endpoint_verification, enabled,
optional, max_certificate_validity_period, max_certificate_validity_period).applyConfig();
}
public EncryptionOptions withCipherSuites(String... cipher_suites)
{
return new EncryptionOptions(ssl_context_factory, keystore, keystore_password, truststore,
truststore_password, ImmutableList.copyOf(cipher_suites), protocol,
return new EncryptionOptions(ssl_context_factory, keystore, keystore_password, keystore_password_file, truststore,
truststore_password, truststore_password_file, ImmutableList.copyOf(cipher_suites), protocol,
accepted_protocols, algorithm, store_type, require_client_auth,
require_endpoint_verification, enabled, optional, max_certificate_validity_period,
max_certificate_validity_period).applyConfig();
@ -559,8 +592,8 @@ public class EncryptionOptions
public EncryptionOptions withProtocol(String protocol)
{
return new EncryptionOptions(ssl_context_factory, keystore, keystore_password, truststore,
truststore_password, cipher_suites, protocol, accepted_protocols, algorithm,
return new EncryptionOptions(ssl_context_factory, keystore, keystore_password, keystore_password_file, truststore,
truststore_password, truststore_password_file, cipher_suites, protocol, accepted_protocols, algorithm,
store_type, require_client_auth, require_endpoint_verification, enabled,
optional, max_certificate_validity_period, max_certificate_validity_period).applyConfig();
}
@ -568,8 +601,8 @@ public class EncryptionOptions
public EncryptionOptions withAcceptedProtocols(List<String> accepted_protocols)
{
return new EncryptionOptions(ssl_context_factory, keystore, keystore_password, truststore,
truststore_password, cipher_suites, protocol, accepted_protocols == null ? null :
return new EncryptionOptions(ssl_context_factory, keystore, keystore_password, keystore_password_file, truststore,
truststore_password, truststore_password_file, cipher_suites, protocol, accepted_protocols == null ? null :
ImmutableList.copyOf(accepted_protocols),
algorithm, store_type, require_client_auth, require_endpoint_verification,
enabled, optional, max_certificate_validity_period, max_certificate_validity_period).applyConfig();
@ -578,64 +611,64 @@ public class EncryptionOptions
public EncryptionOptions withAlgorithm(String algorithm)
{
return new EncryptionOptions(ssl_context_factory, keystore, keystore_password, truststore,
truststore_password, cipher_suites, protocol, accepted_protocols, algorithm,
return new EncryptionOptions(ssl_context_factory, keystore, keystore_password, keystore_password_file, truststore,
truststore_password, truststore_password_file, cipher_suites, protocol, accepted_protocols, algorithm,
store_type, require_client_auth, require_endpoint_verification, enabled,
optional, max_certificate_validity_period, max_certificate_validity_period).applyConfig();
}
public EncryptionOptions withStoreType(String store_type)
{
return new EncryptionOptions(ssl_context_factory, keystore, keystore_password, truststore,
truststore_password, cipher_suites, protocol, accepted_protocols, algorithm,
return new EncryptionOptions(ssl_context_factory, keystore, keystore_password, keystore_password_file, truststore,
truststore_password, truststore_password_file, cipher_suites, protocol, accepted_protocols, algorithm,
store_type, require_client_auth, require_endpoint_verification, enabled,
optional, max_certificate_validity_period, max_certificate_validity_period).applyConfig();
}
public EncryptionOptions withRequireClientAuth(ClientAuth require_client_auth)
{
return new EncryptionOptions(ssl_context_factory, keystore, keystore_password, truststore,
truststore_password, cipher_suites, protocol, accepted_protocols, algorithm,
return new EncryptionOptions(ssl_context_factory, keystore, keystore_password, keystore_password_file, truststore,
truststore_password, truststore_password_file, cipher_suites, protocol, accepted_protocols, algorithm,
store_type, require_client_auth.value, require_endpoint_verification, enabled,
optional, max_certificate_validity_period, max_certificate_validity_period).applyConfig();
}
public EncryptionOptions withRequireEndpointVerification(boolean require_endpoint_verification)
{
return new EncryptionOptions(ssl_context_factory, keystore, keystore_password, truststore,
truststore_password, cipher_suites, protocol, accepted_protocols, algorithm,
return new EncryptionOptions(ssl_context_factory, keystore, keystore_password, keystore_password_file, truststore,
truststore_password, truststore_password_file, cipher_suites, protocol, accepted_protocols, algorithm,
store_type, require_client_auth, require_endpoint_verification, enabled,
optional, max_certificate_validity_period, max_certificate_validity_period).applyConfig();
}
public EncryptionOptions withEnabled(boolean enabled)
{
return new EncryptionOptions(ssl_context_factory, keystore, keystore_password, truststore,
truststore_password, cipher_suites, protocol, accepted_protocols, algorithm,
return new EncryptionOptions(ssl_context_factory, keystore, keystore_password, keystore_password_file, truststore,
truststore_password, truststore_password_file, cipher_suites, protocol, accepted_protocols, algorithm,
store_type, require_client_auth, require_endpoint_verification, enabled,
optional, max_certificate_validity_period, max_certificate_validity_period).applyConfig();
}
public EncryptionOptions withOptional(Boolean optional)
{
return new EncryptionOptions(ssl_context_factory, keystore, keystore_password, truststore,
truststore_password, cipher_suites, protocol, accepted_protocols, algorithm,
return new EncryptionOptions(ssl_context_factory, keystore, keystore_password, keystore_password_file, truststore,
truststore_password, truststore_password_file, cipher_suites, protocol, accepted_protocols, algorithm,
store_type, require_client_auth, require_endpoint_verification, enabled,
optional, max_certificate_validity_period, max_certificate_validity_period).applyConfig();
}
public EncryptionOptions withMaxCertificateValidityPeriod(DurationSpec.IntMinutesBound maxCertificateValidityPeriod)
{
return new EncryptionOptions(ssl_context_factory, keystore, keystore_password, truststore,
truststore_password, cipher_suites, protocol, accepted_protocols, algorithm,
return new EncryptionOptions(ssl_context_factory, keystore, keystore_password, keystore_password_file, truststore,
truststore_password, truststore_password_file, cipher_suites, protocol, accepted_protocols, algorithm,
store_type, require_client_auth, require_endpoint_verification, enabled,
optional, maxCertificateValidityPeriod, certificate_validity_warn_threshold).applyConfig();
}
public EncryptionOptions withCertificateValidityWarnThreshold(DurationSpec.IntMinutesBound certificateValidityWarnThreshold)
{
return new EncryptionOptions(ssl_context_factory, keystore, keystore_password, truststore,
truststore_password, cipher_suites, protocol, accepted_protocols, algorithm,
return new EncryptionOptions(ssl_context_factory, keystore, keystore_password, keystore_password_file, truststore,
truststore_password, truststore_password_file, cipher_suites, protocol, accepted_protocols, algorithm,
store_type, require_client_auth, require_endpoint_verification, enabled,
optional, max_certificate_validity_period, certificateValidityWarnThreshold).applyConfig();
}
@ -659,8 +692,10 @@ public class EncryptionOptions
require_endpoint_verification == opt.require_endpoint_verification &&
Objects.equals(keystore, opt.keystore) &&
Objects.equals(keystore_password, opt.keystore_password) &&
Objects.equals(keystore_password_file, opt.keystore_password_file) &&
Objects.equals(truststore, opt.truststore) &&
Objects.equals(truststore_password, opt.truststore_password) &&
Objects.equals(truststore_password_file, opt.truststore_password_file) &&
Objects.equals(protocol, opt.protocol) &&
Objects.equals(accepted_protocols, opt.accepted_protocols) &&
Objects.equals(algorithm, opt.algorithm) &&
@ -679,8 +714,10 @@ public class EncryptionOptions
int result = 0;
result += 31 * (keystore == null ? 0 : keystore.hashCode());
result += 31 * (keystore_password == null ? 0 : keystore_password.hashCode());
result += 31 * (keystore_password_file == null ? 0 : keystore_password_file.hashCode());
result += 31 * (truststore == null ? 0 : truststore.hashCode());
result += 31 * (truststore_password == null ? 0 : truststore_password.hashCode());
result += 31 * (truststore_password_file == null ? 0 : truststore_password_file.hashCode());
result += 31 * (protocol == null ? 0 : protocol.hashCode());
result += 31 * (accepted_protocols == null ? 0 : accepted_protocols.hashCode());
result += 31 * (algorithm == null ? 0 : algorithm.hashCode());
@ -707,6 +744,8 @@ public class EncryptionOptions
public final String outbound_keystore;
@Nullable
public final String outbound_keystore_password;
@Nullable
public final String outbound_keystore_password_file;
public ServerEncryptionOptions()
{
@ -714,11 +753,13 @@ public class EncryptionOptions
this.legacy_ssl_storage_port_enabled = false;
this.outbound_keystore = null;
this.outbound_keystore_password = null;
this.outbound_keystore_password_file = null;
}
public ServerEncryptionOptions(ParameterizedClass sslContextFactoryClass, String keystore,
String keystore_password,String outbound_keystore,
String outbound_keystore_password, String truststore, String truststore_password,
String keystore_password, String keystore_password_file, String outbound_keystore,
String outbound_keystore_password, String outbound_keystore_password_file,
String truststore, String truststore_password, String truststore_password_file,
List<String> cipher_suites, String protocol, List<String> accepted_protocols,
String algorithm, String store_type, String require_client_auth,
boolean require_endpoint_verification, Boolean optional,
@ -726,13 +767,15 @@ public class EncryptionOptions
DurationSpec.IntMinutesBound maxCertificateAgeMinutes,
DurationSpec.IntMinutesBound certificateValidityWarnThreshold)
{
super(sslContextFactoryClass, keystore, keystore_password, truststore, truststore_password, cipher_suites,
super(sslContextFactoryClass, keystore, keystore_password, keystore_password_file,
truststore, truststore_password, truststore_password_file, cipher_suites,
protocol, accepted_protocols, algorithm, store_type, require_client_auth, require_endpoint_verification,
null, optional, maxCertificateAgeMinutes, certificateValidityWarnThreshold);
this.internode_encryption = internode_encryption;
this.legacy_ssl_storage_port_enabled = legacy_ssl_storage_port_enabled;
this.outbound_keystore = outbound_keystore;
this.outbound_keystore_password = outbound_keystore_password;
this.outbound_keystore_password_file = outbound_keystore_password_file;
}
public ServerEncryptionOptions(ServerEncryptionOptions options)
@ -742,6 +785,7 @@ public class EncryptionOptions
this.legacy_ssl_storage_port_enabled = options.legacy_ssl_storage_port_enabled;
this.outbound_keystore = options.outbound_keystore;
this.outbound_keystore_password = options.outbound_keystore_password;
this.outbound_keystore_password_file = options.outbound_keystore_password_file;
}
@Override
@ -750,6 +794,7 @@ public class EncryptionOptions
super.fillSslContextParams(sslContextFactoryParameters);
putSslContextFactoryParameter(sslContextFactoryParameters, ConfigKey.OUTBOUND_KEYSTORE, this.outbound_keystore);
putSslContextFactoryParameter(sslContextFactoryParameters, ConfigKey.OUTBOUND_KEYSTORE_PASSWORD, this.outbound_keystore_password);
putSslContextFactoryParameter(sslContextFactoryParameters, ConfigKey.OUTBOUND_KEYSTORE_PASSWORD_FILE, this.outbound_keystore_password_file);
}
@Override
@ -845,7 +890,8 @@ public class EncryptionOptions
return internode_encryption == opt.internode_encryption &&
legacy_ssl_storage_port_enabled == opt.legacy_ssl_storage_port_enabled &&
Objects.equals(outbound_keystore, opt.outbound_keystore) &&
Objects.equals(outbound_keystore_password, opt.outbound_keystore_password);
Objects.equals(outbound_keystore_password, opt.outbound_keystore_password) &&
Objects.equals(outbound_keystore_password_file, opt.outbound_keystore_password_file);
}
/**
@ -861,15 +907,17 @@ public class EncryptionOptions
result += 31 * Boolean.hashCode(legacy_ssl_storage_port_enabled);
result += 31 * (outbound_keystore == null ? 0 : outbound_keystore.hashCode());
result += 31 * (outbound_keystore_password == null ? 0 : outbound_keystore_password.hashCode());
result += 31 * (outbound_keystore_password_file == null ? 0 : outbound_keystore_password_file.hashCode());
return result;
}
@Override
public ServerEncryptionOptions withSslContextFactory(ParameterizedClass sslContextFactoryClass)
{
return new ServerEncryptionOptions(sslContextFactoryClass, keystore, keystore_password,
outbound_keystore, outbound_keystore_password, truststore,
truststore_password, cipher_suites, protocol, accepted_protocols,
return new ServerEncryptionOptions(sslContextFactoryClass, keystore, keystore_password, keystore_password_file,
outbound_keystore, outbound_keystore_password, outbound_keystore_password_file,
truststore, truststore_password, truststore_password_file,
cipher_suites, protocol, accepted_protocols,
algorithm, store_type, require_client_auth,
require_endpoint_verification, optional, internode_encryption,
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
@ -879,9 +927,10 @@ public class EncryptionOptions
@Override
public ServerEncryptionOptions withKeyStore(String keystore)
{
return new ServerEncryptionOptions(ssl_context_factory, keystore, keystore_password,
outbound_keystore, outbound_keystore_password, truststore,
truststore_password, cipher_suites, protocol, accepted_protocols,
return new ServerEncryptionOptions(ssl_context_factory, keystore, keystore_password, keystore_password_file,
outbound_keystore, outbound_keystore_password, outbound_keystore_password_file,
truststore, truststore_password, truststore_password_file,
cipher_suites, protocol, accepted_protocols,
algorithm, store_type, require_client_auth,
require_endpoint_verification, optional, internode_encryption,
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
@ -891,9 +940,23 @@ public class EncryptionOptions
@Override
public ServerEncryptionOptions withKeyStorePassword(String keystore_password)
{
return new ServerEncryptionOptions(ssl_context_factory, keystore, keystore_password,
outbound_keystore, outbound_keystore_password, truststore,
truststore_password, cipher_suites, protocol, accepted_protocols,
return new ServerEncryptionOptions(ssl_context_factory, keystore, keystore_password, keystore_password_file,
outbound_keystore, outbound_keystore_password, outbound_keystore_password_file,
truststore, truststore_password, truststore_password_file,
cipher_suites, protocol, accepted_protocols,
algorithm, store_type, require_client_auth,
require_endpoint_verification, optional, internode_encryption,
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
max_certificate_validity_period).applyConfigInternal();
}
@Override
public ServerEncryptionOptions withKeyStorePasswordFile(String keystore_password_file)
{
return new ServerEncryptionOptions(ssl_context_factory, keystore, keystore_password, keystore_password_file,
outbound_keystore, outbound_keystore_password, outbound_keystore_password_file,
truststore, truststore_password, truststore_password_file,
cipher_suites, protocol, accepted_protocols,
algorithm, store_type, require_client_auth,
require_endpoint_verification, optional, internode_encryption,
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
@ -903,9 +966,10 @@ public class EncryptionOptions
@Override
public ServerEncryptionOptions withTrustStore(String truststore)
{
return new ServerEncryptionOptions(ssl_context_factory, keystore, keystore_password,
outbound_keystore, outbound_keystore_password, truststore,
truststore_password, cipher_suites, protocol, accepted_protocols,
return new ServerEncryptionOptions(ssl_context_factory, keystore, keystore_password, keystore_password_file,
outbound_keystore, outbound_keystore_password, outbound_keystore_password_file,
truststore, truststore_password, truststore_password_file,
cipher_suites, protocol, accepted_protocols,
algorithm, store_type, require_client_auth,
require_endpoint_verification, optional, internode_encryption,
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
@ -915,9 +979,23 @@ public class EncryptionOptions
@Override
public ServerEncryptionOptions withTrustStorePassword(String truststore_password)
{
return new ServerEncryptionOptions(ssl_context_factory, keystore, keystore_password,
outbound_keystore, outbound_keystore_password, truststore,
truststore_password, cipher_suites, protocol, accepted_protocols,
return new ServerEncryptionOptions(ssl_context_factory, keystore, keystore_password, keystore_password_file,
outbound_keystore, outbound_keystore_password, outbound_keystore_password_file,
truststore, truststore_password, truststore_password_file,
cipher_suites, protocol, accepted_protocols,
algorithm, store_type, require_client_auth,
require_endpoint_verification, optional, internode_encryption,
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
max_certificate_validity_period).applyConfigInternal();
}
@Override
public ServerEncryptionOptions withTrustStorePasswordFile(String truststore_password_file)
{
return new ServerEncryptionOptions(ssl_context_factory, keystore, keystore_password, keystore_password_file,
outbound_keystore, outbound_keystore_password, outbound_keystore_password_file,
truststore, truststore_password, truststore_password_file,
cipher_suites, protocol, accepted_protocols,
algorithm, store_type, require_client_auth,
require_endpoint_verification, optional, internode_encryption,
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
@ -927,9 +1005,10 @@ public class EncryptionOptions
@Override
public ServerEncryptionOptions withCipherSuites(List<String> cipher_suites)
{
return new ServerEncryptionOptions(ssl_context_factory, keystore, keystore_password,
outbound_keystore, outbound_keystore_password, truststore,
truststore_password, cipher_suites, protocol, accepted_protocols,
return new ServerEncryptionOptions(ssl_context_factory, keystore, keystore_password, keystore_password_file,
outbound_keystore, outbound_keystore_password, outbound_keystore_password_file,
truststore, truststore_password, truststore_password_file,
cipher_suites, protocol, accepted_protocols,
algorithm, store_type, require_client_auth,
require_endpoint_verification, optional, internode_encryption,
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
@ -939,10 +1018,11 @@ public class EncryptionOptions
@Override
public ServerEncryptionOptions withCipherSuites(String... cipher_suites)
{
return new ServerEncryptionOptions(ssl_context_factory, keystore, keystore_password,
outbound_keystore, outbound_keystore_password, truststore,
truststore_password, Arrays.asList(cipher_suites), protocol,
accepted_protocols, algorithm, store_type, require_client_auth,
return new ServerEncryptionOptions(ssl_context_factory, keystore, keystore_password, keystore_password_file,
outbound_keystore, outbound_keystore_password, outbound_keystore_password_file,
truststore, truststore_password, truststore_password_file,
Arrays.asList(cipher_suites), protocol, accepted_protocols,
algorithm, store_type, require_client_auth,
require_endpoint_verification, optional, internode_encryption,
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
max_certificate_validity_period).applyConfigInternal();
@ -951,9 +1031,10 @@ public class EncryptionOptions
@Override
public ServerEncryptionOptions withProtocol(String protocol)
{
return new ServerEncryptionOptions(ssl_context_factory, keystore, keystore_password,
outbound_keystore, outbound_keystore_password, truststore,
truststore_password, cipher_suites, protocol, accepted_protocols,
return new ServerEncryptionOptions(ssl_context_factory, keystore, keystore_password, keystore_password_file,
outbound_keystore, outbound_keystore_password, outbound_keystore_password_file,
truststore, truststore_password, truststore_password_file,
cipher_suites, protocol, accepted_protocols,
algorithm, store_type, require_client_auth,
require_endpoint_verification, optional, internode_encryption,
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
@ -963,9 +1044,10 @@ public class EncryptionOptions
@Override
public ServerEncryptionOptions withAcceptedProtocols(List<String> accepted_protocols)
{
return new ServerEncryptionOptions(ssl_context_factory, keystore, keystore_password,
outbound_keystore, outbound_keystore_password, truststore,
truststore_password, cipher_suites, protocol, accepted_protocols,
return new ServerEncryptionOptions(ssl_context_factory, keystore, keystore_password, keystore_password_file,
outbound_keystore, outbound_keystore_password, outbound_keystore_password_file,
truststore, truststore_password, truststore_password_file,
cipher_suites, protocol, accepted_protocols,
algorithm, store_type, require_client_auth,
require_endpoint_verification, optional, internode_encryption,
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
@ -975,9 +1057,10 @@ public class EncryptionOptions
@Override
public ServerEncryptionOptions withAlgorithm(String algorithm)
{
return new ServerEncryptionOptions(ssl_context_factory, keystore, keystore_password,
outbound_keystore, outbound_keystore_password, truststore,
truststore_password, cipher_suites, protocol, accepted_protocols,
return new ServerEncryptionOptions(ssl_context_factory, keystore, keystore_password, keystore_password_file,
outbound_keystore, outbound_keystore_password, outbound_keystore_password_file,
truststore, truststore_password, truststore_password_file,
cipher_suites, protocol, accepted_protocols,
algorithm, store_type, require_client_auth,
require_endpoint_verification, optional, internode_encryption,
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
@ -987,9 +1070,10 @@ public class EncryptionOptions
@Override
public ServerEncryptionOptions withStoreType(String store_type)
{
return new ServerEncryptionOptions(ssl_context_factory, keystore, keystore_password,
outbound_keystore, outbound_keystore_password, truststore,
truststore_password, cipher_suites, protocol, accepted_protocols,
return new ServerEncryptionOptions(ssl_context_factory, keystore, keystore_password, keystore_password_file,
outbound_keystore, outbound_keystore_password, outbound_keystore_password_file,
truststore, truststore_password, truststore_password_file,
cipher_suites, protocol, accepted_protocols,
algorithm, store_type, require_client_auth,
require_endpoint_verification, optional, internode_encryption,
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
@ -999,9 +1083,10 @@ public class EncryptionOptions
@Override
public ServerEncryptionOptions withRequireClientAuth(ClientAuth require_client_auth)
{
return new ServerEncryptionOptions(ssl_context_factory, keystore, keystore_password,
outbound_keystore, outbound_keystore_password, truststore,
truststore_password, cipher_suites, protocol, accepted_protocols,
return new ServerEncryptionOptions(ssl_context_factory, keystore, keystore_password, keystore_password_file,
outbound_keystore, outbound_keystore_password, outbound_keystore_password_file,
truststore, truststore_password, truststore_password_file,
cipher_suites, protocol, accepted_protocols,
algorithm, store_type, require_client_auth.value,
require_endpoint_verification, optional, internode_encryption,
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
@ -1011,9 +1096,10 @@ public class EncryptionOptions
@Override
public ServerEncryptionOptions withRequireEndpointVerification(boolean require_endpoint_verification)
{
return new ServerEncryptionOptions(ssl_context_factory, keystore, keystore_password,
outbound_keystore, outbound_keystore_password, truststore,
truststore_password, cipher_suites, protocol, accepted_protocols,
return new ServerEncryptionOptions(ssl_context_factory, keystore, keystore_password, keystore_password_file,
outbound_keystore, outbound_keystore_password, outbound_keystore_password_file,
truststore, truststore_password, truststore_password_file,
cipher_suites, protocol, accepted_protocols,
algorithm, store_type, require_client_auth,
require_endpoint_verification, optional, internode_encryption,
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
@ -1022,9 +1108,10 @@ public class EncryptionOptions
public ServerEncryptionOptions withOptional(boolean optional)
{
return new ServerEncryptionOptions(ssl_context_factory, keystore, keystore_password,
outbound_keystore, outbound_keystore_password, truststore,
truststore_password, cipher_suites, protocol, accepted_protocols,
return new ServerEncryptionOptions(ssl_context_factory, keystore, keystore_password, keystore_password_file,
outbound_keystore, outbound_keystore_password, outbound_keystore_password_file,
truststore, truststore_password, truststore_password_file,
cipher_suites, protocol, accepted_protocols,
algorithm, store_type, require_client_auth,
require_endpoint_verification, optional, internode_encryption,
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
@ -1033,9 +1120,10 @@ public class EncryptionOptions
public ServerEncryptionOptions withInternodeEncryption(InternodeEncryption internode_encryption)
{
return new ServerEncryptionOptions(ssl_context_factory, keystore, keystore_password,
outbound_keystore, outbound_keystore_password, truststore,
truststore_password, cipher_suites, protocol, accepted_protocols,
return new ServerEncryptionOptions(ssl_context_factory, keystore, keystore_password, keystore_password_file,
outbound_keystore, outbound_keystore_password, outbound_keystore_password_file,
truststore, truststore_password, truststore_password_file,
cipher_suites, protocol, accepted_protocols,
algorithm, store_type, require_client_auth,
require_endpoint_verification, optional, internode_encryption,
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
@ -1044,9 +1132,10 @@ public class EncryptionOptions
public ServerEncryptionOptions withLegacySslStoragePort(boolean enable_legacy_ssl_storage_port)
{
return new ServerEncryptionOptions(ssl_context_factory, keystore, keystore_password,
outbound_keystore, outbound_keystore_password, truststore,
truststore_password, cipher_suites, protocol, accepted_protocols,
return new ServerEncryptionOptions(ssl_context_factory, keystore, keystore_password, keystore_password_file,
outbound_keystore, outbound_keystore_password, outbound_keystore_password_file,
truststore, truststore_password, truststore_password_file,
cipher_suites, protocol, accepted_protocols,
algorithm, store_type, require_client_auth,
require_endpoint_verification, optional, internode_encryption,
enable_legacy_ssl_storage_port, max_certificate_validity_period,
@ -1055,9 +1144,10 @@ public class EncryptionOptions
public ServerEncryptionOptions withOutboundKeystore(String outboundKeystore)
{
return new ServerEncryptionOptions(ssl_context_factory, keystore, keystore_password,
outboundKeystore, outbound_keystore_password, truststore,
truststore_password, cipher_suites, protocol, accepted_protocols,
return new ServerEncryptionOptions(ssl_context_factory, keystore, keystore_password, keystore_password_file,
outboundKeystore, outbound_keystore_password, outbound_keystore_password_file,
truststore, truststore_password, truststore_password_file,
cipher_suites, protocol, accepted_protocols,
algorithm, store_type, require_client_auth,
require_endpoint_verification, optional, internode_encryption,
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
@ -1066,21 +1156,34 @@ public class EncryptionOptions
public ServerEncryptionOptions withOutboundKeystorePassword(String outboundKeystorePassword)
{
return new ServerEncryptionOptions(ssl_context_factory, keystore, keystore_password,
outbound_keystore, outboundKeystorePassword, truststore,
truststore_password, cipher_suites, protocol, accepted_protocols,
return new ServerEncryptionOptions(ssl_context_factory, keystore, keystore_password, keystore_password_file,
outbound_keystore, outboundKeystorePassword, outbound_keystore_password_file,
truststore, truststore_password, truststore_password_file,
cipher_suites, protocol, accepted_protocols,
algorithm, store_type, require_client_auth,
require_endpoint_verification, optional, internode_encryption,
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
max_certificate_validity_period).applyConfigInternal();
}
public ServerEncryptionOptions withOutboundKeystorePasswordFile(String outboundKeystorePasswordFile)
{
return new ServerEncryptionOptions(ssl_context_factory, keystore, keystore_password, keystore_password_file,
outbound_keystore, outbound_keystore_password, outboundKeystorePasswordFile,
truststore, truststore_password, truststore_password_file,
cipher_suites, protocol, accepted_protocols,
algorithm, store_type, require_client_auth,
require_endpoint_verification, optional, internode_encryption,
legacy_ssl_storage_port_enabled, max_certificate_validity_period,
max_certificate_validity_period).applyConfigInternal();
}
@Override
public ServerEncryptionOptions withMaxCertificateValidityPeriod(DurationSpec.IntMinutesBound maxCertificateValidityPeriod)
{
return new ServerEncryptionOptions(ssl_context_factory, keystore, keystore_password,
outbound_keystore, outbound_keystore_password, truststore,
truststore_password, cipher_suites, protocol, accepted_protocols,
return new ServerEncryptionOptions(ssl_context_factory, keystore, keystore_password, keystore_password_file,
outbound_keystore, outbound_keystore_password, outbound_keystore_password_file,
truststore, truststore_password, truststore_password_file,
cipher_suites, protocol, accepted_protocols,
algorithm, store_type, require_client_auth,
require_endpoint_verification, optional, internode_encryption,
legacy_ssl_storage_port_enabled, maxCertificateValidityPeriod,

View File

@ -194,11 +194,17 @@ public class JMXServerOptions
boolean sslEnabled = COM_SUN_MANAGEMENT_JMXREMOTE_SSL.getBoolean();
// CASSANDRA-13428: Support for specifying password file for keystores is only added to the `encryption_options`
// in the `cassandra.yaml`. Since the JMX SSL Config can also leverage it as per CASSANDRA-18508, password file
// support is not added to the JMX SSL configuration via the system properties. Hence, `null` is used as
// the password file arguments for the keystore and the truststore while constructing the encryption options here.
EncryptionOptions encryptionOptions = new EncryptionOptions(new ParameterizedClass("org.apache.cassandra.security.DefaultSslContextFactory", new HashMap<>()),
keystore,
keystorePassword,
null,
truststore,
truststorePassword,
null,
cipherSuites,
null, // protocol
acceptedProtocols,

View File

@ -36,9 +36,13 @@ import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.cassandra.exceptions.ConfigurationException;
import org.apache.cassandra.io.util.File;
import org.apache.cassandra.io.util.FileUtils;
import org.apache.cassandra.utils.Clock;
import static java.lang.String.format;
/**
* Abstract implementation for {@link ISslContextFactory} using file based, standard keystore format with the ability
* to hot-reload the files upon file changes (detected by the {@code last modified timestamp}).
@ -60,18 +64,19 @@ public abstract class FileBasedSslContextFactory extends AbstractSslContextFacto
public FileBasedSslContextFactory()
{
keystoreContext = new FileBasedStoreContext("conf/.keystore", "cassandra");
outboundKeystoreContext = new FileBasedStoreContext("conf/.keystore", "cassandra");
trustStoreContext = new FileBasedStoreContext("conf/.truststore", "cassandra");
keystoreContext = new FileBasedStoreContext("conf/.keystore", "cassandra", null);
outboundKeystoreContext = new FileBasedStoreContext("conf/.keystore", "cassandra", null);
trustStoreContext = new FileBasedStoreContext("conf/.truststore", "cassandra", null);
}
public FileBasedSslContextFactory(Map<String, Object> parameters)
{
super(parameters);
keystoreContext = new FileBasedStoreContext(getString("keystore"), getString("keystore_password"));
keystoreContext = new FileBasedStoreContext(getString("keystore"), getString("keystore_password"), getString("keystore_password_file"));
outboundKeystoreContext = new FileBasedStoreContext(StringUtils.defaultString(getString("outbound_keystore"), keystoreContext.filePath),
StringUtils.defaultString(getString("outbound_keystore_password"), keystoreContext.password));
trustStoreContext = new FileBasedStoreContext(getString("truststore"), getString("truststore_password"));
StringUtils.defaultString(getString("outbound_keystore_password"), keystoreContext.password),
StringUtils.defaultString(getString("outbound_keystore_password_file"), keystoreContext.passwordFilePath));
trustStoreContext = new FileBasedStoreContext(getString("truststore"), getString("truststore_password"), getString("truststore_password_file"));
}
@Override
@ -135,7 +140,7 @@ public abstract class FileBasedSslContextFactory extends AbstractSslContextFacto
if (password == null)
{
String keyName = isOutboundKeystore ? "outbound_" : "";
final String msg = String.format("'%skeystore_password' must be specified", keyName);
final String msg = format("'%skeystore_password' must be specified", keyName);
throw new IllegalArgumentException(msg);
}
}
@ -278,11 +283,13 @@ public abstract class FileBasedSslContextFactory extends AbstractSslContextFacto
public volatile boolean checkedExpiry = false;
public String filePath;
public String password;
public String passwordFilePath;
public FileBasedStoreContext(String keystore, String keystorePassword)
public FileBasedStoreContext(String keystoreFilePath, String keystorePassword, String keystorePasswordFilePath)
{
this.filePath = keystore;
this.password = keystorePassword;
this.filePath = keystoreFilePath;
this.passwordFilePath = keystorePasswordFilePath;
this.password = resolvePassword(keystoreFilePath, keystorePassword, keystorePasswordFilePath);
}
protected boolean hasKeystore()
@ -294,5 +301,38 @@ public abstract class FileBasedSslContextFactory extends AbstractSslContextFacto
{
return StringUtils.isEmpty(password) || keyPassword.equals(password);
}
private static String resolvePassword(String keystoreFilePath, String password, String passwordFilePath)
{
if (password != null)
return password;
if (StringUtils.isEmpty(passwordFilePath))
return null;
File keystorePasswordFile = new File(passwordFilePath);
if (!keystorePasswordFile.exists())
{
final String msg = format("keystore password file %s does not exist", keystorePasswordFile.path());
throw new ConfigurationException(msg);
}
try
{
// we expect a password to be on the first line
List<String> lines = FileUtils.readLines(keystorePasswordFile);
if (lines.isEmpty())
return "";
return lines.get(0);
}
catch (RuntimeException e)
{
throw new ConfigurationException(format("'Failed to read keystore password from the %s for %s",
keystorePasswordFile, keystoreFilePath),
e);
}
}
}
}

View File

@ -0,0 +1,74 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#
# Testing for pluggable ssl_context_factory option for client and server encryption options with a valid and a missing
# implementation classes.
#
cluster_name: Test Cluster
# memtable_allocation_type: heap_buffers
memtable_allocation_type: offheap_objects
commitlog_sync: batch
commitlog_segment_size: 5MiB
commitlog_directory: build/test/cassandra/commitlog
# commitlog_compression:
# - class_name: LZ4Compressor
cdc_raw_directory: build/test/cassandra/cdc_raw
cdc_enabled: false
hints_directory: build/test/cassandra/hints
partitioner: org.apache.cassandra.dht.ByteOrderedPartitioner
listen_address: 127.0.0.1
storage_port: 7012
ssl_storage_port: 17012
start_native_transport: true
native_transport_port: 9042
column_index_size: 4KiB
saved_caches_directory: build/test/cassandra/saved_caches
data_file_directories:
- build/test/cassandra/data
disk_access_mode: mmap_index_only
seed_provider:
- class_name: org.apache.cassandra.locator.SimpleSeedProvider
parameters:
- seeds: "127.0.0.1:7012"
endpoint_snitch: org.apache.cassandra.locator.SimpleSnitch
dynamic_snitch: true
jmx_server_options:
enabled: true
jmx_encryption_options:
enabled: true
cipher_suites: [TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256]
accepted_protocols: [TLSv1.2,TLSv1.3,TLSv1.1]
keystore: test/conf/cassandra_ssl_test.keystore
keystore_password_file: test/conf/cassandra_ssl_test_keystore_passwordfile.txt
truststore: test/conf/cassandra_ssl_test.truststore
truststore_password_file: test/conf/cassandra_ssl_test_truststore_passwordfile.txt
incremental_backups: true
concurrent_compactors: 4
compaction_throughput: 0MiB/s
row_cache_class_name: org.apache.cassandra.cache.OHCProvider
row_cache_size: 16MiB
user_defined_functions_enabled: true
scripted_user_defined_functions_enabled: false
prepared_statements_cache_size: 1MiB
corrupted_tombstone_strategy: exception
stream_entire_sstables: true
stream_throughput_outbound: 24MiB/s
sasi_indexes_enabled: true
materialized_views_enabled: true
file_cache_enabled: true

View File

@ -0,0 +1,152 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#
# Testing for pluggable ssl_context_factory option for client and server encryption options with a valid and a missing
# implementation classes.
#
cluster_name: Test Cluster
# memtable_allocation_type: heap_buffers
memtable_allocation_type: offheap_objects
commitlog_sync: periodic
commitlog_sync_period: 10s
commitlog_segment_size: 5MiB
commitlog_directory: build/test/cassandra/commitlog
# commitlog_compression:
# - class_name: LZ4Compressor
cdc_raw_directory: build/test/cassandra/cdc_raw
cdc_enabled: false
hints_directory: build/test/cassandra/hints
partitioner: org.apache.cassandra.dht.ByteOrderedPartitioner
listen_address: 127.0.0.1
storage_port: 7012
ssl_storage_port: 17012
start_native_transport: true
native_transport_port: 9042
column_index_size: 4KiB
saved_caches_directory: build/test/cassandra/saved_caches
data_file_directories:
- build/test/cassandra/data
disk_access_mode: mmap_index_only
seed_provider:
- class_name: org.apache.cassandra.locator.SimpleSeedProvider
parameters:
- seeds: "127.0.0.1:7012"
endpoint_snitch: org.apache.cassandra.locator.SimpleSnitch
dynamic_snitch: true
client_encryption_options:
ssl_context_factory:
class_name: org.apache.cassandra.security.PEMBasedSslContextFactory
parameters:
private_key: |
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIE6jAcBgoqhkiG9w0BDAEDMA4ECOWqSzq5PBIdAgIFxQSCBMjXsCK30J0aT3J/
g5kcbmevTOY1pIhJGbf5QYYrMUPiuDK2ydxIbiPzoTE4/S+OkCeHhlqwn/YydpBl
xgjZZ1Z5rLJHO27d2biuESqanDiBVXYuVmHmaifRnFy0uUTFkStB5mjVZEiJgO29
L83hL60uWru71EVuVriC2WCfmZ/EXp6wyYszOqCFQ8Quk/rDO6XuaBl467MJbx5V
sucGT6E9XKNd9hB14/Izb2jtVM5kqKxoiHpz1na6yhEYJiE5D1uOonznWjBnjwB/
f0x+acpDfVDoJKTlRdz+DEcbOF7mb9lBVVjP6P/AAsmQzz6JKwHjvCrjYfQmyyN8
RI4KRQnWgm4L3dtByLqY8HFU4ogisCMCgI+hZQ+OKMz/hoRO540YGiPcTRY3EOUR
0bd5JxU6tCJDMTqKP9aSL2KmLoiLowdMkSPz7TCzLsZ2bGJemuCfpAs4XT1vXCHs
evrUbOnh8et1IA8mZ9auThfqsZtNagJLEXA6hWIKp1FfVL3Q49wvMKZt4eTn/zwU
tLL0m5yPo6/HAaOA3hbm/oghZS0dseshXl7PZrmZQtvYnIvjyoxEL7ducYDQCDP6
wZ7Nzyh1QZAauSS15hl3vLFRZCA9hWAVgwQAviTvhB342O0i9qI7TQkcHk+qcTPN
K+iGNbFZ8ma1izXNKSJ2PgI/QqFNIeJWvZrb9PhJRmaZVsTJ9fERm1ewpebZqkVv
zMqMhlKgx9ggAaSKgnGZkwXwB6GrSbbzUrwRCKm3FieD1QE4VVYevaadVUU75GG5
mrFKorJEH7kFZlic8OTjDksYnHbcgU36XZrGEXa2+ldVeGKL3CsXWciaQRcJg8yo
WQDjZpcutGI0eMJWCqUkv8pYZC2/wZU4htCve5nVJUU4t9uuo9ex7lnwlLWPvheQ
jUBMgzSRsZ+zwaIusvufAAxiKK/cJm4ubZSZPIjBbfd4U7VPxtirP4Accydu7EK6
eG/MZwtAMFNJxfxUR+/aYzJU/q1ePw7fWVHrpt58t/22CX2SJBEiUGmSmuyER4Ny
DPw6d6mhvPUS1jRhIZ9A81ht8MOX7VL5uVp307rt7o5vRpV1mo0iPiRHzGscMpJn
AP36klEAUNTf0uLTKZa7KHiwhn5iPmsCrENHkOKJjxhRrqHjD2wy3YHs3ow2voyY
Ua4Cids+c1hvRkNEDGNHm4+rKGFOGOsG/ZU7uj/6gflO4JXxNGiyTLflqMdWBvow
Zd7hk1zCaGAAn8nZ0hPweGxQ4Q30I9IBZrimGxB0vjiUqNio9+qMf33dCHFJEuut
ZGJMaUGVaPhXQcTy4uD5hzsPZV5xcsU4H3vBYyBcZgrusJ6OOgkuZQaU7p8rWQWr
bUEVbXuZdwEmxsCe7H/vEVv5+aA4sF4kWnMMFL7/LIYaiEzkTqdJlRv/KyJJgcAH
hg2BvR3XTAq8wiX0C98CdmTbsx2eyQdj5tCU606rEohFLKUxWkJYAKxCiUbxGGpI
RheVmxkef9ErxJiq7hsAsGrSJvMtJuDKIasnD14SOEwD/7jRAq6WdL9VLpxtzlOw
pWnIl8kUCO3WoaG9Jf+ZTIv2hnxJhaSzYrdXzGPNnaWKhBlwnXJRvQEdrIxZOimP
FujZhqbKUDbYAcqTkoQ=
-----END ENCRYPTED PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIDkTCCAnmgAwIBAgIETxH5JDANBgkqhkiG9w0BAQsFADB5MRAwDgYDVQQGEwdV
bmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYD
VQQKEwdVbmtub3duMRQwEgYDVQQLDAtzc2xfdGVzdGluZzEZMBcGA1UEAxMQQXBh
Y2hlIENhc3NhbmRyYTAeFw0xNjAzMTgyMTI4MDJaFw0xNjA2MTYyMTI4MDJaMHkx
EDAOBgNVBAYTB1Vua25vd24xEDAOBgNVBAgTB1Vua25vd24xEDAOBgNVBAcTB1Vu
a25vd24xEDAOBgNVBAoTB1Vua25vd24xFDASBgNVBAsMC3NzbF90ZXN0aW5nMRkw
FwYDVQQDExBBcGFjaGUgQ2Fzc2FuZHJhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
MIIBCgKCAQEAjkmVX/HS49cS8Hn6o26IGwMIcEV3d7ZhH0GNcx8rnSRd10dU9F6d
ugSjbwGFMcWUQzYNejN6az0Wb8JIQyXRPTWjfgaWTyVGr0bGTnxg6vwhzfI/9jzy
q59xv29OuSY1dxmY31f0pZ9OOw3mabWksjoO2TexfKoxqsRHJ8PrM1f8E84Z4xo2
TJXGzpuIxRkAJ+sVDqKEAhrKAfRYMSgdJ7zRt8VXv9ngjX20uA2m092NcH0Kmeto
TmuWUtK8E/qcN7ULN8xRWNUn4hu6mG6mayk4XliGRqI1VZupqh+MgNqHznuTd0bA
YrQsFPw9HaZ2hvVnJffJ5l7njAekZNOL+wIDAQABoyEwHzAdBgNVHQ4EFgQUcdiD
N6aylI91kAd34Hl2AzWY51QwDQYJKoZIhvcNAQELBQADggEBAG9q29ilUgCWQP5v
iHkZHj10gXGEoMkdfrPBf8grC7dpUcaw1Qfku/DJ7kPvMALeEsmFDk/t78roeNbh
IYBLJlzI1HZN6VPtpWQGsqxltAy5XN9Xw9mQM/tu70ShgsodGmE1UoW6eE5+/GMv
6Fg+zLuICPvs2cFNmWUvukN5LW146tJSYCv0Q/rCPB3m9dNQ9pBxrzPUHXw4glwG
qGnGddXmOC+tSW5lDLLG1BRbKv4zxv3UlrtIjqlJtZb/sQMT6WtG2ihAz7SKOBHa
HOWUwuPTetWIuJCKP7P4mWWtmSmjLy+BFX5seNEngn3RzJ2L8uuTJQ/88OsqgGru
n3MVF9w=
-----END CERTIFICATE-----
trusted_certificates: |
-----BEGIN CERTIFICATE-----
MIIDkTCCAnmgAwIBAgIETxH5JDANBgkqhkiG9w0BAQsFADB5MRAwDgYDVQQGEwdV
bmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYD
VQQKEwdVbmtub3duMRQwEgYDVQQLDAtzc2xfdGVzdGluZzEZMBcGA1UEAxMQQXBh
Y2hlIENhc3NhbmRyYTAeFw0xNjAzMTgyMTI4MDJaFw0xNjA2MTYyMTI4MDJaMHkx
EDAOBgNVBAYTB1Vua25vd24xEDAOBgNVBAgTB1Vua25vd24xEDAOBgNVBAcTB1Vu
a25vd24xEDAOBgNVBAoTB1Vua25vd24xFDASBgNVBAsMC3NzbF90ZXN0aW5nMRkw
FwYDVQQDExBBcGFjaGUgQ2Fzc2FuZHJhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
MIIBCgKCAQEAjkmVX/HS49cS8Hn6o26IGwMIcEV3d7ZhH0GNcx8rnSRd10dU9F6d
ugSjbwGFMcWUQzYNejN6az0Wb8JIQyXRPTWjfgaWTyVGr0bGTnxg6vwhzfI/9jzy
q59xv29OuSY1dxmY31f0pZ9OOw3mabWksjoO2TexfKoxqsRHJ8PrM1f8E84Z4xo2
TJXGzpuIxRkAJ+sVDqKEAhrKAfRYMSgdJ7zRt8VXv9ngjX20uA2m092NcH0Kmeto
TmuWUtK8E/qcN7ULN8xRWNUn4hu6mG6mayk4XliGRqI1VZupqh+MgNqHznuTd0bA
YrQsFPw9HaZ2hvVnJffJ5l7njAekZNOL+wIDAQABoyEwHzAdBgNVHQ4EFgQUcdiD
N6aylI91kAd34Hl2AzWY51QwDQYJKoZIhvcNAQELBQADggEBAG9q29ilUgCWQP5v
iHkZHj10gXGEoMkdfrPBf8grC7dpUcaw1Qfku/DJ7kPvMALeEsmFDk/t78roeNbh
IYBLJlzI1HZN6VPtpWQGsqxltAy5XN9Xw9mQM/tu70ShgsodGmE1UoW6eE5+/GMv
6Fg+zLuICPvs2cFNmWUvukN5LW146tJSYCv0Q/rCPB3m9dNQ9pBxrzPUHXw4glwG
qGnGddXmOC+tSW5lDLLG1BRbKv4zxv3UlrtIjqlJtZb/sQMT6WtG2ihAz7SKOBHa
HOWUwuPTetWIuJCKP7P4mWWtmSmjLy+BFX5seNEngn3RzJ2L8uuTJQ/88OsqgGru
n3MVF9w=
-----END CERTIFICATE-----
keystore_password_file: test/conf/cassandra_ssl_test_keystore_passwordfile.txt
server_encryption_options:
ssl_context_factory:
class_name: org.apache.cassandra.security.PEMBasedSslContextFactory
internode_encryption: none
keystore: test/conf/cassandra_ssl_test.keystore.pem
keystore_password_file: test/conf/cassandra_ssl_test_keystore_passwordfile.txt
truststore: test/conf/cassandra_ssl_test.truststore.pem
incremental_backups: true
concurrent_compactors: 4
compaction_throughput: 0MiB/s
row_cache_class_name: org.apache.cassandra.cache.OHCProvider
row_cache_size: 16MiB
user_defined_functions_enabled: true
scripted_user_defined_functions_enabled: false
prepared_statements_cache_size: 1MiB
corrupted_tombstone_strategy: exception
stream_entire_sstables: true
stream_throughput_outbound: 24MiB/s
sasi_indexes_enabled: true
materialized_views_enabled: true
file_cache_enabled: true

View File

@ -0,0 +1 @@
cassandra

View File

@ -0,0 +1 @@
cassandra

View File

@ -0,0 +1 @@
cassandra

View File

@ -81,6 +81,54 @@ public class EncryptionOptionsEqualityTest
assertEquals(encryptionOptions1.hashCode(), encryptionOptions2.hashCode());
}
@Test
public void testKeystoreOptionsWithPasswordFile() {
EncryptionOptions encryptionOptions1 =
new EncryptionOptions()
.withStoreType("JKS")
.withKeyStore(TlsTestUtils.SERVER_KEYSTORE_PATH)
.withKeyStorePasswordFile(TlsTestUtils.SERVER_KEYSTORE_PASSWORD_FILE)
.withTrustStore(TlsTestUtils.SERVER_TRUSTSTORE_PATH)
.withTrustStorePasswordFile(TlsTestUtils.SERVER_TRUSTSTORE_PASSWORD_FILE)
.withProtocol("TLSv1.1")
.withRequireClientAuth(REQUIRED)
.withRequireEndpointVerification(false);
EncryptionOptions encryptionOptions2 =
new EncryptionOptions()
.withStoreType("JKS")
.withKeyStore(TlsTestUtils.SERVER_KEYSTORE_PATH)
.withKeyStorePasswordFile(TlsTestUtils.SERVER_KEYSTORE_PASSWORD_FILE)
.withTrustStore(TlsTestUtils.SERVER_TRUSTSTORE_PATH)
.withTrustStorePasswordFile(TlsTestUtils.SERVER_TRUSTSTORE_PASSWORD_FILE)
.withProtocol("TLSv1.1")
.withRequireClientAuth(REQUIRED)
.withRequireEndpointVerification(false);
assertEquals(encryptionOptions1, encryptionOptions2);
assertEquals(encryptionOptions1.hashCode(), encryptionOptions2.hashCode());
}
@Test
public void testMismatchForKeystoreOptionsWithPasswordFile()
{
EncryptionOptions.ServerEncryptionOptions encryptionOptions1 = createServerEncryptionOptions();
EncryptionOptions.ServerEncryptionOptions encryptionOptions2 = createServerEncryptionOptions();
encryptionOptions1 = encryptionOptions1
.withKeyStore(TlsTestUtils.SERVER_KEYSTORE_PATH)
.withKeyStorePassword(null)
.withKeyStorePasswordFile(TlsTestUtils.SERVER_KEYSTORE_PASSWORD_FILE);
encryptionOptions2 = encryptionOptions2
.withKeyStore(TlsTestUtils.SERVER_KEYSTORE_PATH)
.withKeyStorePassword(null)
.withKeyStorePasswordFile(TlsTestUtils.SERVER_TRUSTSTORE_PASSWORD_FILE);
assertNotEquals(encryptionOptions1, encryptionOptions2);
assertNotEquals(encryptionOptions1.hashCode(), encryptionOptions2.hashCode());
}
@Test
public void testSameCustomSslContextFactoryImplementation() {

View File

@ -61,8 +61,8 @@ public class EncryptionOptionsTest
{
return new EncryptionOptionsTestCase(new EncryptionOptions(new ParameterizedClass("org.apache.cassandra.security.DefaultSslContextFactory",
new HashMap<>()),
keystorePath, "dummypass",
"dummytruststore", "dummypass",
keystorePath, "dummypass", null,
"dummytruststore", "dummypass", null,
Collections.emptyList(), null, null, null, "JKS", "false", false, enabled, optional, null, null)
.applyConfig(),
expected,
@ -75,8 +75,8 @@ public class EncryptionOptionsTest
{
return new EncryptionOptionsTestCase(new EncryptionOptions(new ParameterizedClass("org.apache.cassandra.security.DefaultSslContextFactory",
customSslContextFactoryParams),
keystorePath, "dummypass",
"dummytruststore", "dummypass",
keystorePath, "dummypass", null,
"dummytruststore", "dummypass", null,
Collections.emptyList(), null, null, null, "JKS", "false", false, enabled, optional, null, null)
.applyConfig(),
expected,
@ -127,7 +127,10 @@ public class EncryptionOptionsTest
EncryptionOptions.TlsEncryptionPolicy expected)
{
return new ServerEncryptionOptionsTestCase(new EncryptionOptions.ServerEncryptionOptions(new ParameterizedClass("org.apache.cassandra.security.DefaultSslContextFactory",
new HashMap<>()), keystorePath, "dummypass", keystorePath, "dummypass", "dummytruststore", "dummypass",
new HashMap<>()),
keystorePath, "dummypass", null,
keystorePath, "dummypass", null,
"dummytruststore", "dummypass", null,
Collections.emptyList(), null, null, null, "JKS", "false", false, optional, internodeEncryption, false, null, null)
.applyConfig(),
expected,

View File

@ -31,6 +31,7 @@ import org.junit.Test;
import org.apache.cassandra.config.EncryptionOptions;
import org.apache.cassandra.config.ParameterizedClass;
import org.apache.cassandra.distributed.shared.WithProperties;
import org.apache.cassandra.exceptions.ConfigurationException;
import org.apache.cassandra.transport.TlsTestUtils;
import static org.apache.cassandra.config.CassandraRelevantProperties.CASSANDRA_CONFIG;
@ -89,7 +90,7 @@ public class FileBasedSslContextFactoryTest
}
/**
* Tests that empty {@code keystore_password} and {@code outbound_keystore_password} is allowed.
* Tests that empty {@code keystore_password} and {@code outbound_keystore_password} are allowed.
*/
@Test
public void testEmptyKeystorePasswords() throws SSLException
@ -103,7 +104,7 @@ public class FileBasedSslContextFactoryTest
Assert.assertEquals("org.apache.cassandra.security.FileBasedSslContextFactoryTest$TestFileBasedSSLContextFactory",
localEncryptionOptions.ssl_context_factory.class_name);
Assert.assertEquals("keystore_password must be empty", "", localEncryptionOptions.keystore_password);
Assert.assertEquals("outbound_keystore_password must empty", "", localEncryptionOptions.outbound_keystore_password);
Assert.assertEquals("outbound_keystore_password must be empty", "", localEncryptionOptions.outbound_keystore_password);
TestFileBasedSSLContextFactory sslContextFactory =
(TestFileBasedSSLContextFactory) localEncryptionOptions.sslContextFactoryInstance;
@ -112,6 +113,46 @@ public class FileBasedSslContextFactoryTest
sslContextFactory.buildTrustManagerFactory();
}
@Test
public void testKeystorePasswordFile() throws SSLException
{
// Here we only override password configuration and specify password_file configuration since keystore paths
// are already loaded in the `encryptionOptions`
EncryptionOptions.ServerEncryptionOptions localEncryptionOptions = encryptionOptions
.withKeyStorePassword(null)
.withKeyStorePasswordFile(TlsTestUtils.SERVER_KEYSTORE_PASSWORD_FILE)
.withOutboundKeystorePassword(null)
.withOutboundKeystorePasswordFile(TlsTestUtils.SERVER_OUTBOUND_KEYSTORE_PASSWORD_FILE)
.withTrustStorePassword(null)
.withTrustStorePasswordFile(TlsTestUtils.SERVER_TRUSTSTORE_PASSWORD_FILE);
Assert.assertEquals("org.apache.cassandra.security.FileBasedSslContextFactoryTest$TestFileBasedSSLContextFactory",
localEncryptionOptions.ssl_context_factory.class_name);
TestFileBasedSSLContextFactory sslContextFactory =
(TestFileBasedSSLContextFactory) localEncryptionOptions.sslContextFactoryInstance;
sslContextFactory.buildKeyManagerFactory();
sslContextFactory.buildTrustManagerFactory();
}
/**
* Tests for missing password configuration and non-existance file specified in the password_file configuration.
* @throws SSLException
*/
@Test(expected = ConfigurationException.class)
public void testBadKeystorePasswordFile() throws SSLException
{
// Here we only override password configuration and specify password_file configuration since keystore paths
// are already loaded in the `encryptionOptions`
encryptionOptions
.withKeyStorePassword(null)
.withKeyStorePasswordFile("/path/to/non-existance-password-file")
.withOutboundKeystorePassword(null)
.withOutboundKeystorePasswordFile("/path/to/non-existance-password-file")
.withTrustStorePassword(null)
.withTrustStorePasswordFile("/path/to/non-existance-password-file");
}
/**
* Tests that an absent keystore_password for the {@code keystore} is disallowed.
*/

View File

@ -0,0 +1,80 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.cassandra.security;
import org.junit.Test;
import org.apache.cassandra.exceptions.ConfigurationException;
import static org.junit.Assert.assertEquals;
public class FileBasedStoreContextTest
{
/**
* Tests default behavior without keystore password file specified.
*/
@Test
public void testPasswordConfiguration()
{
FileBasedSslContextFactory.FileBasedStoreContext wrapper = new FileBasedSslContextFactory.FileBasedStoreContext("test/conf/cassandra_ssl_test.keystore", "cassandra", null);
assertEquals("Password must be loaded from the direct configuration", "cassandra", wrapper.password);
}
/**
* Tests behavior when password for keystore is specified via a password file.
*/
@Test
public void testPasswordFileConfiguration()
{
FileBasedSslContextFactory.FileBasedStoreContext wrapper = new FileBasedSslContextFactory.FileBasedStoreContext("test/conf/cassandra_ssl_test.keystore", null, "test/conf/cassandra_ssl_test_keystore_passwordfile.txt");
assertEquals("Password must be loaded from the password file", "cassandra", wrapper.password);
}
/**
* Tests when password for keystore is specified via password configuration and a password file both.
*/
@Test
public void testPasswordAndPasswordFileConfiguration()
{
String expectedPassword = "cassandra123";
FileBasedSslContextFactory.FileBasedStoreContext wrapper = new FileBasedSslContextFactory.FileBasedStoreContext("test/conf/cassandra_ssl_test.keystore", expectedPassword, "test/conf/cassandra_ssl_test_keystore_passwordfile.txt");
assertEquals("Password configuration must take precedence", expectedPassword, wrapper.password);
}
/**
* Tests behavior when a non-existing password file is specified for keystore's password and password configuration
* is {@code null}.
*/
@Test(expected = ConfigurationException.class)
public void testMissingPasswordFile()
{
new FileBasedSslContextFactory.FileBasedStoreContext("test/conf/cassandra_ssl_test.keystore", null, "passwordfile-that-doesnotexist");
}
/**
* Tests behavior when non-null empty password is specified in the password configuration.
* The empty password via the configuration must take precedence in this case.
*/
@Test
public void testBlankPasswordConfiguration()
{
FileBasedSslContextFactory.FileBasedStoreContext wrapper = new FileBasedSslContextFactory.FileBasedStoreContext("test/conf/cassandra_ssl_test.keystore", "", "test/conf/cassandra_ssl_test_keystore_passwordfile.txt");
assertEquals("Password must be loaded from the direct configuration", "", wrapper.password);
}
}

View File

@ -0,0 +1,83 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.cassandra.security;
import javax.net.ssl.SSLException;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.apache.cassandra.config.Config;
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.distributed.shared.WithProperties;
import static org.apache.cassandra.config.CassandraRelevantProperties.CASSANDRA_CONFIG;
import static org.junit.Assert.assertEquals;
public class PEMBasedSslContextFactoryConfigWithPasswordFileTest
{
static WithProperties properties;
@BeforeClass
public static void setupDatabaseDescriptor()
{
properties = new WithProperties().set(CASSANDRA_CONFIG, "cassandra-pem-sslcontextfactory-with-passwordfile.yaml");
}
@AfterClass
public static void tearDownDatabaseDescriptor()
{
properties.close();
}
@Test
public void testHappyPathInlinePEM() throws SSLException
{
Config config = DatabaseDescriptor.loadConfig();
config.client_encryption_options.applyConfig();
assertEquals("org.apache.cassandra.security.PEMBasedSslContextFactory",
config.client_encryption_options.ssl_context_factory.class_name);
assertEquals(config.client_encryption_options.ssl_context_factory.class_name,
config.client_encryption_options.sslContextFactoryInstance.getClass().getName());
PEMBasedSslContextFactory sslContextFactory =
(PEMBasedSslContextFactory) config.client_encryption_options.sslContextFactoryInstance;
sslContextFactory.buildKeyManagerFactory();
sslContextFactory.buildTrustManagerFactory();
}
@Test
public void testHappyPathFileBasedPEM() throws SSLException
{
Config config = DatabaseDescriptor.loadConfig();
config.server_encryption_options.applyConfig();
assertEquals("org.apache.cassandra.security.PEMBasedSslContextFactory",
config.server_encryption_options.ssl_context_factory.class_name);
assertEquals(config.server_encryption_options.ssl_context_factory.class_name,
config.server_encryption_options.sslContextFactoryInstance.getClass().getName());
PEMBasedSslContextFactory sslContextFactory =
(PEMBasedSslContextFactory) config.server_encryption_options.sslContextFactoryInstance;
sslContextFactory.buildKeyManagerFactory();
sslContextFactory.buildTrustManagerFactory();
}
}

View File

@ -58,16 +58,19 @@ public class TlsTestUtils
public static String SERVER_KEYSTORE_PATH_PEM = "test/conf/cassandra_ssl_test.keystore.pem";
public static String SERVER_KEYSTORE_PATH_UNENCRYPTED_PEM = "test/conf/cassandra_ssl_test.unencrypted_keystore.pem";
public static String SERVER_KEYSTORE_PASSWORD = "cassandra";
public static String SERVER_KEYSTORE_PASSWORD_FILE = "test/conf/cassandra_ssl_test_keystore_passwordfile.txt";
public static String SERVER_KEYSTORE_ENDPOINT_VERIFY_PATH = "test/conf/cassandra_ssl_test_endpoint_verify.keystore";
public static String SERVER_KEYSTORE_ENDPOINT_VERIFY_PASSWORD = "cassandra";
public static String SERVER_OUTBOUND_KEYSTORE_PATH = "test/conf/cassandra_ssl_test_outbound.keystore";
public static String SERVER_OUTBOUND_KEYSTORE_PASSWORD = "cassandra";
public static String SERVER_OUTBOUND_KEYSTORE_PASSWORD_FILE = "test/conf/cassandra_ssl_test_outbound_keystore_password.txt";
public static String SERVER_TRUSTSTORE_PATH = "test/conf/cassandra_ssl_test.truststore";
public static String SERVER_TRUSTSTORE_PEM_PATH = "test/conf/cassandra_ssl_test.truststore.pem";
public static String SERVER_TRUSTSTORE_PASSWORD = "cassandra";
public static String SERVER_TRUSTSTORE_PASSWORD_FILE = "test/conf/cassandra_ssl_test_truststore_passwordfile.txt";
// To regenerate:
// 1. generate keystore

View File

@ -0,0 +1,88 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.cassandra.utils.jmx;
import java.net.InetAddress;
import java.util.Map;
import javax.management.remote.rmi.RMIConnectorServer;
import javax.net.ssl.SSLException;
import javax.rmi.ssl.SslRMIServerSocketFactory;
import org.apache.commons.lang3.StringUtils;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.config.JMXServerOptions;
import org.apache.cassandra.distributed.shared.WithProperties;
import org.apache.cassandra.utils.JMXServerUtils;
import static org.apache.cassandra.config.CassandraRelevantProperties.CASSANDRA_CONFIG;
import static org.apache.cassandra.config.CassandraRelevantProperties.COM_SUN_MANAGEMENT_JMXREMOTE_SSL;
import static org.apache.cassandra.config.CassandraRelevantProperties.JAVAX_RMI_SSL_CLIENT_ENABLED_CIPHER_SUITES;
import static org.apache.cassandra.config.CassandraRelevantProperties.JAVAX_RMI_SSL_CLIENT_ENABLED_PROTOCOLS;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
/**
* Tests for JMX SSL configuration specified in the cassandra.yaml using jmx_encryption_options with password files for
* keystore and truststores as applicable.
* @see JMXSslConfiguredWithYamlFileOptionsTest
*/
public class JMXSslConfiguredWithYamlFileOptionsAndPasswordFileTest
{
static WithProperties properties;
@BeforeClass
public static void setupDatabaseDescriptor()
{
properties = new WithProperties().set(CASSANDRA_CONFIG, "cassandra-jmx-sslconfig-with-passwordfile.yaml");
DatabaseDescriptor.daemonInitialization();
}
@AfterClass
public static void tearDownDatabaseDescriptor()
{
properties.close();
}
@Test
public void testYamlFileJmxEncryptionOptions() throws SSLException
{
JMXServerOptions serverOptions = DatabaseDescriptor.getJmxServerOptions();
String expectedProtocols = StringUtils.join(serverOptions.jmx_encryption_options.getAcceptedProtocols(), ",");
String expectedCipherSuites = StringUtils.join(serverOptions.jmx_encryption_options.cipherSuitesArray(), ",");
InetAddress serverAddress = InetAddress.getLoopbackAddress();
try (WithProperties ignored = JMXSslPropertiesUtil.use(false))
{
Map<String, Object> env = JMXServerUtils.configureJmxSocketFactories(serverAddress, serverOptions);
assertTrue("com.sun.management.jmxremote.ssl must be true", COM_SUN_MANAGEMENT_JMXREMOTE_SSL.getBoolean());
assertNotNull("ServerSocketFactory must not be null", env.get(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE));
assertTrue("RMI_SERVER_SOCKET_FACTORY must be of JMXSslRMIServerSocketFactory type", env.get(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE) instanceof SslRMIServerSocketFactory);
assertNotNull("ClientSocketFactory must not be null", env.get(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE));
assertNotNull("com.sun.jndi.rmi.factory.socket must be set in the env", env.get("com.sun.jndi.rmi.factory.socket"));
assertEquals("javax.rmi.ssl.client.enabledProtocols must match", expectedProtocols, JAVAX_RMI_SSL_CLIENT_ENABLED_PROTOCOLS.getString());
assertEquals("javax.rmi.ssl.client.enabledCipherSuites must match", expectedCipherSuites, JAVAX_RMI_SSL_CLIENT_ENABLED_CIPHER_SUITES.getString());
}
}
}