Skip to content

Loading modules via SSL

Rob Rudin edited this page Jan 25, 2024 · 21 revisions

ml-gradle and its underlying libraries - ml-javaclient-util and ml-app-deployer - provide support for creating an app server with a certificate template and then, in the case of a REST API server, loading modules via an SSL connection with that server.

Note that "SSL" is a misleading term these days, as the TLS protocol is widely used as a replacement for SSL. But "SSL" is still used throughout Java, particularly the SSLContext that is used to create a secure connection using either SSL or TLS.

As of ml-gradle 4.7.0, 2-way SSL - where the client must present a certificate and trust the server's certificate - is supported via properties and no longer requires writing Java code in your build.gradle file. Please see the section below on how to configure 2-way SSL.

The ssl-project example project shows an example of how this works - here are the moving parts:

  • A certificate template config file defines the template configuration.
  • The REST API server file includes a reference to the SSL certificate template.
  • The build.gradle file adds an instance of GenerateTemporaryCertificateCommand to the mlDeploy task. This temporary certificate is then used by the REST API server (the management API offers other options for generating real certificates). Without generating this certificate, the REST API server won't be able to accept HTTP or HTTPS connections.
  • gradle.properties includes mlSimpleSsl=true. This uses a "simple" or insecure approach where the server's certificate is not validated.

Note that if you've enabled SSL on the App-Services server (which defaults to port 8000), you'll also need to add mlAppServicesSimpleSsl=true for a "trust everything" approach.

Note that "simple" or insecure SSL is useful for development but is not recommended for production use cases.

Selecting the SSLContext protocol

Starting in 3.16.0, the default protocol is TLSv1.2. You can override this by setting the mlSimpleSsl and/or mlAppServicesSimpleSsl properties to any value besides "true" or "false".

Using your JVM's default keystore

Starting in 3.17.0, you can set mlRestUseDefaultKeystore=true and mlAppServicesUseDefaultKeystore=true so that your JVM's default keystore is used for trusting certificates (as opposed to the "trust everything" approach employed by mlSimpleSsl and mlAppServicesSimpleSsl). See the Property Reference for additional properties that you can configure when using this approach.

Note that when using this approach, you need to ensure that your JVM's default keystore - typically a file named cacerts - contains a certificate associated with the certificate template in use by the MarkLogic app server that ml-gradle will connect to. That certificate can be obtained via the following steps:

  1. Go to your MarkLogic server's Admin UI and select "Certificate Templates".
  2. Select the certificate template in use by your app server.
  3. Click on the "Status" tab for the certificate template.
  4. Scroll down to see the signed certificates for your certificate template. Depending on how you've configured your template, you may need to import all of these certificates into your JVM's default keystore.

Customizing the SSL objects

Instead of using mlSimpleSsl, you can always configure your own SSLContext and SSLHostnameVerifier. The AppConfig instance that is stored under the key "mlAppConfig" by ml-gradle has properties named "restSslContext" and "restSslHostnameVerifier" for these objects. You can set these to anything in your build.gradle file - here's a pseudocode example:

ext {
  def mySSLContext = write any Groovy code you want to create your own SSLContext
  def mySSLHostnameVerifier = write any Groovy code you want to create your own SSLHostnameVerifier
  def myTrustManager = write any Groovy code you want to create your own X509TrustManager

  mlAppConfig.restSslContext = mySSLContext
  mlAppConfig.restSslHostnameVerifier = mySSLHostnameVerifier
  mlAppConfig.restTrustManager = myTrustManager // Only supported starting in ml-gradle 3.8.3
}

Note that SSLHostnameVerifier is a MarkLogic Java Client class. It includes a few built-in implementations that may suffice for you.

As of version 3.0.0, you can also manually configure the SSL components for a connection to the App-Services server. This is necessary in case you've enabled SSL on the App-Services server, as that server is used for loading modules that are not REST extensions.

ext {
  mlAppConfig.appServicesSslContext = mySSLContext
  mlAppConfig.appServicesSslHostnameVerifier = mlSSLHostnameVerifier
  mlAppConfig.appServicesTrustManager = myTrustManager // Only supported starting in ml-gradle 3.8.3
}

Supporting 2-way SSL

Starting in ml-gradle 4.7.0, you can now configure 2-way SSL via properties. Since modules are typically loaded via both the App-Services port and the port of your REST API server, you will need to configure 2-way SSL for both connections (if one does not require 2-way SSL, then of course there is nothing further to configure for that connection).

The following properties allow you specify both a key store (which must contain your client certificate) and a trust store (which must contain the server's public certificate):

mlRestKeyStorePath=/path/to/keystore.jks
mlRestKeyStorePassword=optional password
mlRestKeyStoreType=JKS
mlRestKeyStoreAlgorithm=SunX509

mlRestTrustStorePath=/path/to/truststore.jks
mlRestTrustStorePassword=optional password
mlRestTrustStoreType=JKS
mlRestTrustStoreAlgorithm=SunX509

For the type and algorithm, if "JKS" and "SunX509" are the correct values (this is normally the case), you do not need to configure those as "JKS" and "SunX509" are the default values.

If your key store is also your trust store, you only need to configure the following (this works for the App-Services connection as well):

mlRestKeyStorePath=/path/to/keystore.jks
mlRestKeyStorePassword=optional password

If your App-Services app server requires 2-way SSL, you can use the following properties for that connection:

mlAppServicesKeyStorePath=/path/to/keystore.jks
mlAppServicesKeyStorePassword=optional password
mlAppServicesKeyStoreType=JKS
mlAppServicesKeyStoreAlgorithm=SunX509

mlAppServicesTrustStorePath=/path/to/truststore.jks
mlAppServicesTrustStorePassword=optional password
mlAppServicesTrustStoreType=JKS
mlAppServicesTrustStoreAlgorithm=SunX509

If your Manage and Admin app servers also require 2-way SSL, please see SSL with Manage and Admin servers for how to configure those connections.

If your App-Services, REST API, Manage, and Admin app servers all require the same configuration, you can use the following properties to specify the configuration once:

mlKeyStorePath=/path/to/keystore.jks
mlKeyStorePassword=optional password
mlKeyStoreType=JKS
mlKeyStoreAlgorithm=SunX509

mlTrustStorePath=/path/to/truststore.jks
mlTrustStorePassword=optional password
mlTrustStoreType=JKS
mlTrustStoreAlgorithm=SunX509

For ml-gradle prior to 4.7.0, the ssl-2way example project includes code in the project's build.gradle file to show how to construct an SSLContext based on a keystore containing a client certificate.

Clone this wiki locally