Skip to main content
Loading

Managing mTLS with a Java client

Aerospike Server Enterprise supports standard TLS and mutual authentication TLS (mTLS). This page describes how to configure a Java application to connect to an Aerospike cluster that uses mTLS.

You can find a fully-functional example project in the aerospike-tls-examples Github repository.

Keys and certificates

For mTLS, both the client and server must have their own private key and certificate. In the following example, they are both signed by the same Certificate Authority (CA).

Install the certificates and the key on the Aerospike Server nodes:

  • CA Certificate: example.ca.crt
  • Server Certificate: example.server.crt
  • Server Private Key: example.server.key

Install the certificates and the key on the Java client nodes:

  • CA Certificate: example.ca.crt
  • Client Certificate: example.client.crt
  • Client Private Key: example.client.key
Protect private keys

Protect your private keys, and never share them. Public keys are meant to be shared freely. Public keys encrypt; private keys decrypt. Anyone who acquires your private key can impersonate you.

Aerospike configuration

The following example aerospike.conf configuration shows only the stanzas and directives that are relevant for this TLS configuration:

network {
tls example.server {
ca-file /opt/aerospike/etc/certs/example.ca.crt
cert-file /opt/aerospike/etc/certs/example.server.crt
key-file /opt/aerospike/etc/private/example.server.key
}

service {
tls-address any
tls-port 4000
tls-name example.server
tls-authenticate-client example.client
}
}

The tls block in the network stanza defines the TLS configuration for the Aerospike Server certificate. This is used in both standard TLS as well as in mutual authentication TLS.

The name example.server is known as the TLS name. This must match the value of the Common Name (CN) or Subject Alternative Name (SAN) of the server certificate example.server.crt. It must also be referenced in the application code to connect to the cluster. The following command verifies that the certificate has the expected CN value in the subject:

openssl x509 -in example.server.crt -text -noout | grep -E -- "Subject:"
Subject: CN = example.server, O = "Aerospike, Inc.", C = US

The tls-authenticate-client directive specifies example.client. This must match the value of the Common Name (CN) or Subject Alternative Name (SAN) of the client certificate example.client.crt. The following command verifies that the certificate has the expected CN value in the subject:

openssl x509 -in example.client.crt -text -noout | grep -E -- "Subject:"
Subject: CN = example.client, O = "Aerospike, Inc.", C = US
Bypass CN and SAN verification

The tls-authenticate-client directive includes a value of any, which bypasses the step in which the Common Name (CN)/Subject Alternative Names (SAN) are verified.

Java client TLS configuration

Add CA certificate to Java TrustStore on client nodes

Import the CA certificate into a Java TrustStore on the client. The CA certificate is a public certificate which verifies that the certificate presented by the Aerospike Server is signed by a trusted authority.

There are two ways to import the CA certificate into a Java TrustStore.

The first method is to import the CA certificate into the default system-wide TrustStore of trusted CA certificates used by the Java runtime. This is not a best practice, and we do not recommend it. The procedure for installing a system-wide trusted CA certificate varies by operating system and JDK/JRE version. Default system-wide trusted CA certificates present security issues, and are not allowed by many enterprise security requirements.

The second method is to install the CA certificate into a new Java TrustStore, which will be used exclusively by the intended Java application. Use the Java keytool command-line utility to import example.ca.crt into a new Java TrustStore:

keytool -importcert -storetype jks -alias example.ca \
-keystore example.ca.jks -file example.ca.crt \
-storepass changeit

This command creates a new TrustStore named example.ca.jks.

Create a strong password

The previous example follows the Java convention of using "changeit" as the password. You SHOULD NOT use this password, and instead create a strong password governed by your organization's password policy.

Verify the certificate is in the TrustStore with the keystore -list command:

keytool -list -keystore example.ca.jks -storepass changeit
Keystore type: jks
Keystore provider: SUN

Your keystore contains 1 entry

example.ca, Apr 5, 2022, trustedCertEntry,
Certificate fingerprint (SHA1): 85:99:36:F8:20:A7:42:AA:ED:E6:9B:7B

Note that the entry is listed as trustedCertEntry. This file can be stored on the filesystem with other public certificates.

Add client certificate chain to Java KeyStore

During the TLS handshake the client sends its certificate to the server, and a message encrypted with the client's private key. Since the Java application needs access to both the client certificate and the client private key, these must be imported into a Java KeyStore.

First, the CA certificate, the client certificate, and the client private key need to be concatenated together. This creates a single chain certificate. The following command will create a single chain certificate file named example.client.chain.crt. The certificates and key must be named in the same order as the example:

cat example.ca.crt example.client.crt example.client.key > example.client.chain.crt

Next, the chain certificate must be converted to PKCS #12 format. This is a standard format for storing cryptographic objects, and we recommend it over the proprietary Java KeyStore (jks) format. The following command will create a chain certificate file named example.client.chain.p12, which is the KeyStore file the Java application will use:

openssl pkcs12 -export -in example.client.chain.crt \
-out example.client.chain.p12 -password pass:"changeit" \
-name example.client -noiter -nomaciter

Remember to create a very strong password.

Verify the certificate is in the KeyStore using the keystore -list command:

keytool -list -keystore example.client.chain.p12 -storepass changeit
Keystore type: PKCS12
Keystore provider: SUN

Your keystore contains 1 entry

example.client, Apr 5, 2022, PrivateKeyEntry,
Certificate fingerprint (SHA1): A3:63:D6:B0:3B:E9:7E:78:81:46:5F

Note that the entry is listed as PrivateKeyEntry. This file should be stored on the filesystem securely with limited permissions. The user invoking the JVM will need read access.

Java application

When developing a Java application which connects to an Aerospike cluster using TLS, the application:

  • Must enable TLS in the client policy.
  • Must specify the host's TLS Name.
  • Must use the TrustStore with the CA certificate.
  • Must use the KeyStore with the client certificate chain (for mTLS only).
  • Should log Aerospike debug messages.
  • Should log debug messages during the TLS handshake when troubleshooting.

To enable TLS in the Aerospike Client, the ClientPolicy must have a TlsPolicy assigned to the tlsPolicy property:

ClientPolicy policy = new ClientPolicy();
policy.tlsPolicy = new TlsPolicy();

To specify the TLS name, instantiate Host objects with the constructor that accepts tlsName as the 2nd parameter:

Host[] hosts = new Host[] {
new Host("127.0.0.1", "example.server", 4000)
};

Remember that the TLS name must match the Common Name (CN) or Subject Alternative Name (SAN) in the server certificate, as well as the tls-name used in the Aerospike configuration file.

Use the -Djavax.net.ssl.trustStore argument to pass the TrustStore containing the CA certificate to the JVM:

java -Djavax.net.ssl.trustStore=example.ca.jks \
-jar aerospike-tls-example.jar

To pass the KeyStore and KeyStore password containing the client certificate chain to the JVM use the Djavax.net.ssl.keyStore and -Djavax.net.ssl.keyStorePassword arguments respectively:

java -Djavax.net.ssl.trustStore=example.ca.jks \
-Djavax.net.ssl.keyStore=example.client.p12 \
-Djavax.net.ssl.keyStorePassword=changeit \
-jar aerospike-tls-example.jar

To log Aerospike debug messages, see the Java Client logging usage.

To log debug messages during the TLS handshake pass the -Djavax.net.debug argument to the JVM:

java -Djavax.net.debug=all \
-Djavax.net.ssl.keyStore=example.client.p12 \
-Djavax.net.ssl.keyStorePassword=changeit \
-Djavax.net.ssl.trustStore=example.ca.jks \
-jar aerospike-tls-example.jar

See tls-example-java for a complete example.