The Aerospike Knowledge Base has moved to https://support.aerospike.com. Content on https://discuss.aerospike.com is being migrated to either https://support.aerospike.com or https://docs.aerospike.com. Maintenance on articles stored in this repository ceased on December 31st 2022 and this article may be stale. If you have any questions, please do not hesitate to raise a case via https://support.aerospike.com.
How to use Mutual Authentication TLS (mTLS) in Java
Aerospike Server Enterprise supports standard TLS and mutual authentication TLS (mTLS). This article describes how to setup a Java application to connect to an Aerospike cluster configured to use mutual authentication TLS.
A fully functional example project can be found in the aerospike-tls-examples Github repository.
Keys and Certificates
For mutual authentication TLS both the client and server need to have their own private key and certificate. For this example, assume they are both signed by the same Certificate Authority (CA).
Installed on the Aerospike Server nodes:
- CA Certificate:
example.ca.crt
- Server Certificate:
example.server.crt
- Server Private Key:
example.server.key
Installed on the Client (Java) nodes:
- CA Certificate:
example.ca.crt
- Client Certificate:
example.client.crt
- Client Private Key:
example.client.key
Note that the private keys are sensitive and must be kept secure. Do not put the key for the server on client nodes nor the key for the client on the server nodes.
Aerospike Configuration
For simplicity, the example aerospike.conf
configuration below 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 will 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
Note: The
tls-authenticate-client
directive also allows for a value ofany
which will bypass the step in which the Common Name (CN)/Subject Alternative Names (SAN) are verified. See the tls-authenticate-client for more information.
Java Configuration
Add CA Certificate to Java TrustStore
The CA certificate needs to be imported into a Java TrustStore. It is a public certificate used to verify that the certificate presented by the Aerospike Server during the TLS handshake is signed by a trusted authority.
There are two ways to import the CA certificate into a Java TrustStore on the client nodes.
The first method is to import the CA certificate into the system-wide TrustStore of “trusted CA certificates” used by the Java runtime by default. As the procedure for installing a system-wide trusted CA certificate can vary by OS and JDK/JRE version, this article will not use the system-wide TrustStore. Moreover, default system-wide trusted CA certificates is not allowed by many Enterprise security requirements.
The second method is to install the CA certificate into a new Java TrustStore
which will to be used exclusively by the intended Java application. To do this,
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 will create a file named example.ca.jks
which is the CA
TrustStore the Java application will use.
Note: The above example followed Java convention of using “changeit” as the password. You SHOULD NOT use this password and instead choose a strong password governed by your organization’s password policy.
Verify the certificate is in the TrustStore using 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, 2020, trustedCertEntry,
Certificate fingerprint (SHA1): 85:99:36:F8:20:A7:42:AA:ED:E6:9B:7B:F1:B6:84:45:31:13:D0:43
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 will need to send its certificate to the server as well as a message encrypted using its private key. Since the Java application will need access to both the client certificate and the client private key these need to be imported into a Java KeyStore.
First, the CA certificate, the client certificate, and the client private key
need to all be concatenated together in that order. This creates a single chain
certificate. The following command will create a single chain certificate file
named example.client.chain.crt
:
cat example.ca.crt example.client.crt example.client.key > example.client.chain.crt
Next, the chain certificate needs to be converted to PKCS #12 format. This is
a standard format for storing cryptographic objects and is reccommended 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
Note: The above example followed Java convention of using “changeit” as the password. You SHOULD NOT use this password and instead choose a strong password governed by your organization’s password 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, 2020, PrivateKeyEntry,
Certificate fingerprint (SHA1): A3:63:D6:B0:3B:E9:7E:78:81:46:5F:D6:53:93:5D:57:27:1B:FE:6D
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 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
needs to 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.
To pass the TrustStore containing the CA certificate to the JVM use the
-Djavax.net.ssl.trustStore
argument:
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 repsecitvely:
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.
Keywords
TLS MUTUAL AUTH MAUTH JAVA
Timestamp
April 2020