Managing mTLS with a Java client
Aerospike Database Enterprise Edition 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 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 Database certificate.
This is used in both standard TLS as well as in mTLS.
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
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
The CA certificate is a public certificate which verifies that the certificate presented by the Aerospike Database is signed by a trusted authority.
Use the Java
keytool
command-line utility to importexample.ca.crt
into a new Java TrustStore that will be used exclusively by the intended Java application:keytool -importcert -storetype jks -alias example.ca \
-keystore example.ca.jks -file example.ca.crt \
-storepass changeitCreate a strong passwordThe previous example follows the Java convention of using "changeit" as the password. Change this to a strong password governed by your organization's password policy.
This command creates a new TrustStore named
example.ca.jks
.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:7BThe entry is listed as
trustedCertEntry
. This file can be stored on the filesystem with other public certificates.
Do not import the CA certificate into the default system-wide TrustStore of trusted CA certificates used by the Java runtime. Default system-wide trusted CA certificates present security issues, and are not allowed by many enterprise security requirements.
Add client certificate chain to Java KeyStore
During the TLS handshake, the client sends its certificate and a message encrypted with the client's private key to the server. Since the Java application needs access to both the client certificate and the client private key, these must be imported into a Java KeyStore.
The client certificate, the CA certificate, and the client private key must be concatenated together. This creates a single chain certificate. The following command creates 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.client.crt example.ca.crt example.client.key > example.client.chain.crt
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 creates 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 -nomaciterChange the password from
changeit
to a more secure password in compliance with your organization's security policy.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:5FPrivate key accessThe 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
A Java application that connects to an Aerospike cluster using TLS:
- 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 accept tlsName
as the second 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.