VoltDB hashes usernames and passwords both within the database server and while passing them across the network. However, the network communication itself is not encrypted by default. You can enable Transport Layer Security (TLS) — the recommended upgrade from Secure Socket Layer (SSL) communication — for the HTTP port, which affects the Volt Management Center and the JSON interface. You can also extend TLS encryption to all external interfaces (HTTP, client, and admin), the internal interface, and the port used for database replication (DR) for more thorough security. The following sections summarize how to enable TLS for the servers in a cluster, including:
Configuring TLS encryption on the server
Choosing which ports to encrypt
Using the VoltDB command line utilities with TLS
Implementing TLS communication in Java client applications
Configuring Database Replication (DR) using TLS
TLS, like its predecessor SSL, uses certificates to validate the authenticity of the communication. You can either use a certificate created by a commercial certificate provider (such as Digitcert, GeoTrust, or Symantec) or you can create your own certificate. If you use a commercial provider, that provider also handles the authentication of the certificate. If you create a local or self-signed certificate, you need to provide the certificate and authentication to the server and clients yourself.
If you choose to use a locally created certificate, you must first generate the certificate key store and trust store. You can create a local certificate using the Java keytool utility. Creating the key store and trust store requires several steps including:
Creating a key store and password
Creating a key signing request
Creating and signing the certificate
Importing the certificate into the key store
Creating the associated trust store
Creating a PEM formatted trust store, for databases hosted in Kubernetes
There are a number of different options when performing this task. It is important to understand how these options affect the resulting certificate. Be sure to familiarize yourself with the documentation of the keytool utility before creating your own certificate. The following example uses some common options to generate a self-signed certificate key store and trust store.
$ keytool -genkeypair -keystore mykey.jks \ -storepass topsecret -alias mydb \ -keyalg rsa -storetype jks \ -validity 365 -keysize 2048 $ keytool -certreq -keystore mykey.jks \ -storepass topsecret -alias mydb -keyalg rsa -file mykey.csr $ keytool -gencert -keystore mykey.jks \ -storepass topsecret -alias mydb \ -infile mykey.csr -outfile mydb.cert \ -validity 365 $ keytool -import -keystore mykey.jks \ -storepass topsecret -alias mydb \ -file mydb.cert $ keytool -import -keystore mytrust.jks \ -storepass topsecret -alias mycert \ -storetype jks -file mydb.cert $ keytool -export -keystore mykey.jks \ -storepass topsecret -alias mydb \ -keypass topsecret -rfc -file mycert.pem
Once you create the key store and the trust store, you can reference them in the database configuration file to enable TLS when initializing the database root directory. For example:
<ssl enabled="true" external="true"> <keystore path="/etc/ssl/local/mykey.jks" password="topsecret"/> <truststore path="/etc/ssl/local/mytrust.jks" password="topsecret"/> </ssl>
If you are purchasing a commercial certificate, rather than creating a self-signed certificate in Step #3, you send the key request created in Step #2 to the certificate authority and they will provide you with a signed certificate to use in the subsequent step. That is, you import the certificate they provide you into your keystore in Step #4. Since you are using a trusted authority for authentication, you can in most cases skip Steps 5 & 6, since Java should recognize the authorization.
If TLS encryption is enabled, the HTTP is always encrypted. You can selectively choose to encrypt other ports as well. You specify which ports to encrypt using attributes of the <ssl> element:
External ports (external), including the client and admin ports
Internal ports (internal), used for intra-cluster communication between the nodes of the cluster
Extranet ports (dr), including the replication port used for DR
For each type of port, you specify that the ports are either enabled ("true") or disabled ("false"). The default is false. For example, the following configuration enables TLS encryption on the external, internal, and DR ports:
<ssl enabled="true" external="true" internal="true" dr="true"> <keystore path="/etc/ssl/local/mydb.keystore" password="mypasswd"/> <truststore path="/etc/ssl/local/mydb.truststore" password="mypasswd"/> </ssl>
Note that if you enable TLS encryption for the DR port, other clusters replicating from this cluster must include the appropriate client configuration when they enable DR. See Section 12.7.5, “Configuring Database Replication (DR) With TLS/SSL” for information on setting up TLS when configuring DR.
Also, enabling TLS encryption on the internal port means that all intra-cluster communication must be encrypted and decrypted as it passes between nodes. Consequently, any operations that require interactions between cluster nodes (such as K-safety or multi-partition transactions) may take longer and therefore impact overall latency. Be sure to benchmark your application with and without TLS encryption before enabling internal port encryption on production systems.
Finally, it is important to note that all ports where TLS is enabled and all the servers within a single cluster use the same certificate.
Once you enable TLS for the external interfaces on your database servers, you must also enable TLS on the command line utilities so they use the appropriate protocols to connect to the servers. (The voltdb utility is the one exception. Since it only operates on the local server it does not require a network connection.)
When invoking the command line utilities, such as voltadmin and sqlcmd, you
--ssl option to activate encryption with TLS-enabled VoltDB servers. If the servers are using a
commercially-provided certificate, you can specify the
--ssl option without an argument. For
$ sqlcmd --ssl
If the servers are using a local or self-signed certificate you must also specify a Java properties file as an
argument to the
--ssl option. For example:
$ sqlcmd --ssl=localcert.txt
The properties file must declare two properties that specify the path to the trust store and the trust store
password, respectively. So, using the trust store generated by the example in Section 12.7.1, “Configuring TLS/SSL on the VoltDB Server”, the
localcert.txt file could be:
Just as the command line tools must specify how to connect to an TLS-enabled server, client applications must also
establish an appropriate connection. Using the VoltDB Java API, you can enable TLS by setting the appropriate attributes
of the client configuration. Specifically, if you are using a self-signed certificate, you must provide the path to the
trust store and its password. You can do this using either the .setTrustStore() or .setTrustStoreConfigFromPropertyFile().
For example, the following two commands are equivalent, assuming the
localcert.txt file matches the
properties file described in Section 12.7.3, “Using the VoltDB Command Line Utilities with TLS/SSL”:
clientConfig.setTrustStore("/etc/ssl/local/mydb.truststore", "mypasswd"); clientConfig.setTrustStoreConfigFromPropertyFile("localcert.txt");
After setting the trust store properties you can enable TLS communication using the .enableSSL() method and create the client connection. For example:
ClientConfig clientConfig = new ClientConfig("JDoe", "JDsPasswd"); clientConfig.setTrustStoreConfigFromPropertyFile("localcert.txt"); clientConfig.enableSSL(); client = ClientFactory.createClient(clientConfig);
When using a commercially generated certificate, you do not need to specify the trust store and can use just the .enableSSL() method.
When using TLS encryption on the DR port, the DR snapshots and binary logs are encrypted as they pass from the producer cluster to the consumer cluster. This means that the producer must not only have TLS enabled for the DR port, but the consumer cluster must use the appropriate TLS credentials when it contacts the producer.
So, for example, in passive DR, the master cluster must have TLS enabled for the DR port and the replica must be configured to use TLS when connecting to the master. In XDCR, you enable TLS for all clusters in the XDCR relationship. So each cluster must both enable TLS for its DR port as well as configure TLS for its connections to the other clusters.
Section 12.7.1, “Configuring TLS/SSL on the VoltDB Server” describes how to enable TLS encryption for the DR port, which must be done
before the cluster starts. To configure TLS connectivity at the other end, you add the
ssl attribute to the
<connection> element within the
DR configuration. The value of the
ssl attribute is either blank — for
commercial certificates — or the path to a Java properties file specifying the trust store and password for the
remote cluster(s) when using a locally-generated certificate. These attribute values are the same as the
--ssl argument you use when running the command line utilities described in Section 12.7.3, “Using the VoltDB Command Line Utilities with TLS/SSL”.
For example, when configuring TLS encryption for passive DR, the master cluster must enable TLS on the DR port and
the replica must specify use of TLS in the
<connection> element. The respective
configuration files might look like this:
<ssl enabled="true" dr="true"> <keystore path="/etc/ssl/local/mydb.keystore" password="mypasswd"/> <truststore path="/etc/ssl/local/mydb.truststore" password="mypasswd"/> </ssl>
<dr id="2" role="replica"> <connection source="MasterSvrA,MasterSvrB" ssl="/usr/local/mastercert.txt"> </dr>
Note that the replica does not need to enable TLS for its DR port, since it is a consumer and its own port is not used.
For XDCR, each cluster must both enable DR for its own port and specify the TLS credentials for the remote clusters. The configuration file might look like this:
<ssl enabled="true" dr="true"> <keystore path="/etc/ssl/local/mydb.keystore" password="mypasswd"/> <truststore path="/etc/ssl/local/mydb.truststore" password="mypasswd"/> </ssl> <dr id="1" role="xdcr"> <connection source="NYCSvrA,NYCSvrB" ssl="/usr/local/nyccert.txt"> </dr>
Note that when using locally-generated certificates, there is only one properties file specified in the
ssl attribute. So all of the clusters in the XDCR relationship must use the same certificate.
When using commercially purchased certificates, the
ssl attributes is left blank; so
each cluster can, if you choose, use a separate certificate.