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 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
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
.
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.