Select TLS Cipher Suites (Java)
When using TLS encryption with Aerospike Database Enterprise Edition (the server), Aerospike recommends that you explicitly specify the set of cipher suites to use during the TLS handshake. This ensures that the cipher suites that get the best performance are used, while satisfying your organization’s security requirements.
This is especially important with JVM-based applications because the default cipher suite list can vary between JVM environments, which may result in the application negotiating a cipher suite which has poor performance or weaker security.
Unlike public-facing servers like websites and web services, the server is generally deployed in an environment where the TLS client (the application) and the TLS server (Aerospike server) are both controlled by the same entity. In this kind of environment the list of supported cipher suites can be much more specific.
For example, we'll assume that an organization has identified the following four cipher suites as optimal in terms of security and performance:
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
There are two ways to ensure that Java applications use and prioritize this list in the specified order:
- Specify the allowed cipher suites in the Aerospike configuration.
- Specify the allowed cipher suites in Java applications.
These two approaches are not mutually exclusive. It is possible to use the Aerospike configuration to enforce the broadest set of acceptable ciphers and then further narrow the list direcly in applications that have specific requirements.
Aerospike recommends that you always specify at least one cipher suite list in the Aerospike configuration, excluding cipher suites which do not meet security or performance requirements.
Specifying cipher suites in the Aerospike configuration
You can specify a list of allowed cipher suites with the
cipher-suitedirective. However, because the server uses OpenSSL, the cipher suite name must be mapped from the [IANA notation](https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml) that Java uses to the OpenSSL notation that Aerospike uses.OpenSSL (Aerospike) | IANA (Java) |
---|---|
ECDHE-ECDSA-AES128-GCM-SHA256 | TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 |
ECDHE-ECDSA-AES256-GCM-SHA384 | TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 |
ECDHE-RSA-AES128-GCM-SHA256 | TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 |
ECDHE-RSA-AES256-GCM-SHA384 | TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 |
The following example aerospike.conf
configuration shows only the stanzas
and directives that are relevant for the cipher suite configuration:
network {
tls example.server {
cipher-suite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384
}
}
Specifying cipher suites in Java applications
You can specify a list of allowed cipher suites in the Aerospike Java Client
in the TlsPolicy
attached to the ClientPolicy
. For example, assume a new
security policy requires all new applications to only use AES256, but the
server still needs to accept AES128 ciphers from legacy applications.
New applications can further restrict the 4 cipher suites the server uses to just the AES256 variants:
ClientPolicy policy = new ClientPolicy();
policy.tlsPolicy = new TlsPolicy();
String[] ciphers = {
// IANA (Java) OpenSSL (Aerospike Server)
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", // ECDHE-ECDSA-AES256-GCM-SHA384
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384" // ECDHE-RSA-AES256-GCM-SHA384
};
policy.tlsPolicy.ciphers = ciphers;
Troubleshooting tips
Print available cipher suites
To see which cipher suites your Java environment supports and the
order of priority, use the getSupportedCipherSuites()
method of the
javax.net.ssl.SSLSocketFactory
object for the default SSL context. If
jrunscript
is available on the client nodes, you can run the following
one-liner from the command line:
jrunscript -e "java.util.Arrays.asList(javax.net.ssl.SSLContext.getDefault().getSocketFactory().getSupportedCipherSuites()).forEach(println)"
Alternatively, you can use the following Java command-line application:
package com.aerospike.examples;
import javax.net.ssl.SSLContext;
import java.security.NoSuchAlgorithmException;
public class Main {
public static void main(String[] args) {
System.out.println("Supported Cipher Suites:");
try {
String[] ciphers = SSLContext.getDefault().getSocketFactory().getSupportedCipherSuites();
for (int i = 1; i < ciphers.length; i++) {
System.out.println(" " + i + ". " + ciphers[i]);
}
} catch (NoSuchAlgorithmException e) {
System.out.println("Failed to get default SSL context.");
}
}
}
Many versions of the JDK prioritized CBC cipher suites over GCM ciphers. This is a common cause of poor performance. If the output of the above scripts show CBC cipher suites before the GCM cipher suites, it’s especially important to explicitly select the allowed cipher suites.
Check available ciphers from a client node
The nmap
command determines which cipher suites are available to the client with the ssl-enum-ciphers
script. This script probes the server node from a client application.
These examples configure the server to allow 4 ciphers;. Two of those ciphers are based on RSA-based certificates and the other 2 are based on ECDSA-based certificates. Which of the 4 cipher suites can be used depends on the type of certificate installed on the server nodes.
Assuming the server nodes have an ECDSA certificate, the output of the following command shows that only the 2 ECDSA-based certificates are available to the client as acceptable cipher suites.
nmap --script ssl-enum-ciphers -Pn -p 4000 192.168.105.20
Example output:
Starting Nmap 7.70 ( https://nmap.org ) at 2020-04-06 22:52 UTC
Nmap scan report for 192.168.105.20
Host is up (0.00046s latency).
PORT STATE SERVICE
4000/tcp open remoteanything
| ssl-enum-ciphers:
| TLSv1.2:
| ciphers:
| TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 (ecdh_x25519) - A
| TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 (ecdh_x25519) - A
| compressors:
| NULL
| cipher preference: server
|_ least strength: A
Nmap done: 1 IP address (1 host up) scanned in 0.22 seconds
Debug the TLS Handshake in Java
If a Java application is not able to connect to an Aerospike cluster over
TLS which you believe is configured correctly, you can pass the javax.net.debug
argument to the JVM when invoking the application to enable verbose logging of
each step of the TLS handshake. For example:
java -Djavax.net.debug=all -jar MyApplication.jar