Configuring Fusion for SSL

Fusion uses the Java Secure Socket Extension (JSSE) framework to enable SSL configuration for secure communication between the Fusion UI and any HTTP client.

To configure Fusion for SSL you must install an SSL certificate and enable SSL in the Fusion UI.

Installing an SSL certificate

The server has a locally-protected private key that is accessible via a JSEE keystore. The keystore maintains both the server certificate and the private key.

Important
In a production environment, SSL certificates must be signed by a trusted Certificate Authority (CA).

To store certificates, you can use the Java keytool, which is part of the JDK. When you have a signed certificate, then you create a JSSE keystore by using the keytool "import" command.

In the following example, we have a signed certificate, in pfx format, in a PKCS#12 file called fusion.keystore.p12. The following command creates a new JSSE keystore (JKS):

keytool -importkeystore -srckeystore /opt/lucidworks/fusion/apps/jetty/ui/etc/fusion.keystore.p12 \
 -srcstoretype pkcs12 -destkeystore /opt/lucidworks/fusion/jetty/ui/etc/keystore -deststoretype JKS

If you have the certificate and private key as separate files, then you need to use openssl to create a PKCS#12 file. For example:

openssl pkcs12 -export -out /home/admin/keys/keystore.pkcs12 -in /home/admin/keys/fullchain.pem -inkey /home/admin/keys/privkey.pem
Note
When prompted for a password, do not enter a blank password.

Now use keytool to import the PKCS#12 file into Java keystore format and optionally delete the PKCS#12 file:

keytool -importkeystore -srckeystore /home/admin/keys/keystore.pkcs12 -srcstoretype PKCS12 -destkeystore {fusion_path}/apps/jetty/ui/etc/keystore
Note
If your server certificate is signed by an intermediate CA rather than a root CA, you must add the intermediate certificate to the keystore before you add the server certificate.

Configuring the Fusion UI

The current version of the Fusion UI runs an embedded Jetty server. In the Fusion distribution, this server is in directory fusion/apps/jetty/ui. Server configuration files including the keystore file and HTTPS and SSL config files are stored in the subdirectory fusion/apps/jetty/ui/etc.

To configure the Fusion UI server for SSL, you must:

  • configure the embedded web server to use the JSSE keystore which has your certificates

  • configure the web server ports

  • redirect HTTP request to HTTPS

As a training exercise, we show how to configure the Fusion UI for SSL with the default Fusion developer deployment and test the configuration via a web browser running on the same machine, i.e., the web client sends requests to server "localhost" on port 8764, the default port for the Fusion UI. In an enterprise deployment, of course, the browser client and Fusion UI will be on different machines, and the Fusion UI wouldn’t be using port 8764.

Configure Jetty to use the JSSE keystore

The following details are taken from the eclipse.org Jetty documentation pages.

The generated SSL certificates held in the key store are configured on Jetty by injecting an instance of a SslContextFactory object and passing it to the connector’s SslConnectionFactory, which is done in the Jetty distribution in file jetty-https.xml. The SslContextFactory object is configured in the file jetty-ssl.xml.

These XML files are in the fusion/apps/jetty/home/etc directory. The directory that contains the Jetty server instance which runs the Fusion UI is directory fusion/apps/jetty/ui.

This means that you must:

  1. Copy the files jetty-https.xml and jetty-ssl.xml from fusion/apps/jetty/home/etc to fusion/apps/jetty/ui/etc.

  2. Edit the jetty-ssl.xml file and update the following the sslContextFactory class properties so that they match the actual keystore location and passwords:

    • KeyStorePath

    • KeyStorePassword

    • KeyManagerPassword

    • TrustStorePath

    • TrustStorePassword

For our example, the path values are all "my.keystore.jks" and the password values are all "secret".

<Configure id="sslContextFactory" class="org.eclipse.jetty.util.ssl.SslContextFactory">
  <Set name="KeyStorePath"><Property name="jetty.base" default="." />/<Property name="jetty.keystore" default="etc/my.keystore.jks"/></Set>
  <Set name="KeyStorePassword"><Property name="jetty.keystore.password" default="secret"/></Set>
  <Set name="KeyManagerPassword"><Property name="jetty.keymanager.password" default="secret"/></Set>
  <Set name="TrustStorePath"><Property name="jetty.base" default="." />/<Property name="jetty.truststore" default="etc/my.keystore.jks"/></Set>
  <Set name="TrustStorePassword"><Property name="jetty.truststore.password" default="secret"/></Set>

Configure the Fusion UI startup script

The Fusion UI startup script, path fusion/bin/ui, sets a series of environment variables and then starts the Jetty server. The arguments to exec command to start the Jetty server should be changed as follows:

  • change command line argument "jetty.port=$HTTP_PORT" to "https.port=$HTTP_PORT"

  • add XML config files to the command line arguments

Here is the command to start Jetty in the script fusion/bin/ui, after making the above edits:

exec "$JAVA" \
    $JAVA_OPTIONS \
    "-Djava.io.tmpdir=$JETTY_BASE/work" \
    "-Dlog4j.configurationFile=file:$JETTY_BASE/resources/log4j2.xml" \
    "-Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager" \
    "-Dapollo.home=/path/to/fusion" \
    "-Dcom.lucidworks.apollo.admin.zk.connect=$FUSION_ZK" \
    "-XX:OnOutOfMemoryError=/path/to/fusion/bin/oom.sh ui" \
    -jar "$JETTY_HOME/start.jar" \
    "jetty.home=$JETTY_HOME" \
    "jetty.base=$JETTY_BASE" \
    "https.port=$HTTP_PORT" \
    "STOP.PORT=$STOP_PORT" \
    "STOP.KEY=$STOP_KEY" \
    "$JETTY_BASE/etc/jetty-ssl.xml" \
    "$JETTY_BASE/etc/jetty-https.xml" \
    "$JETTY_BASE/etc/jetty-logging.xml"

Disabling HTTP

Note
Only do this if blocking access to HTTP using the firewall is not feasible.

To entirely disable HTTP, remove the HTTP connector from the Jetty startup configuration:

rm {fusion_path}/apps/jetty/ui/start.d/http.ini

Configuring Fusion for SSL Solr/SolrCloud

To configure the Fusion HTTP client for a SSL-ed Solr or SolrCloud server, you must specify the javax.net.ssl system properties.

Step 1. Edit the configuration file

In the fusion/conf/config.sh file, add the following properties to the options API_JAVA_OPTIONS, CONNECTORS_JAVA_OPTIONS and UI_JAVA_OPTIONS:

    -Djavax.net.ssl.keyStore="/path/to/solr-ssl.keystore.jks"
    -Djavax.net.ssl.keyStorePassword=secret
    -Djavax.net.ssl.trustStore="/path/to/solr-ssl.keystore.jks"
    -Djavax.net.ssl.trustStorePassword=secret

Step 2. Register SolrCloud as a search cluster in Fusion

Send a request to the REST API 'searchCluster' endpoint:

curl -u admin:pass -H 'Content-type: application/json' -X POST 'http://localhost:8764/api/apollo/searchCluster' -d '
{
  "id" : "ssl",
  "connectString" : "localhost:2181",
  "cloud" : true
}

Step 3. Test: create collection, index data, query collection

Create collection in SolrCloud with configured SSL:

curl -u admin:pass -H 'Content-type: application/json' -X POST 'http://localhost:8764/api/apollo/collections' -d '
{
  "id" : "mycollection",
  "searchClusterId" : "ssl"
}'

Index data using an existing pipeline:

curl -u admin:pass 'http://localhost:8764/api/apollo/index-pipelines/mycollection-default/collections/mycollection/index' -XPOST -H "Content-type: application/json" -d '{
  "id": "1",
  "foo_s": "bar",
  "spam_s": 42
}'

Query the collection using the default query pipeline:

curl -u admin:pass 'http://localhost:8764/api/apollo/query-pipelines/mycollection-default/collections/mycollection/select?q=*:*'

Generating a self-signed certificate

If don’t have signed certificates from an external CA, then you can generate a set of self-signed certificates using the Java keytool utility to generate a public/private key pair and generate a self-signed certificate.

The keytool option "-genkeypair" generates a public/private key pair. It wraps the public key into an X.509 v3 self-signed certificate, which is stored as a single-element certificate chain. This certificate chain and the private key are stored in a new keystore entry identified by alias. The full set of arguments to this command are:

-genkeypair
    {-alias alias}
    {-keyalg keyalg}
    {-keysize keysize}
    {-sigalg sigalg}
    [-dname dname]
    [-keypass keypass]
    {-startdate value}
    {-ext ext}*
    {-validity valDays}
    {-storetype storetype}
    {-keystore keystore}
    [-storepass storepass]
    {-providerClass provider_class_name {-providerArg provider_arg}}
    {-v}
    {-protected}
    {-Jjavaoption}

Arguments of interest are:

  • keyalg specifies the algorithm to be used to generate the key pair. This must be RSA in order to talk to browser clients IE and Navigator.

  • keysize specifies the size of each key to be generated. Depends on keyalg. For RSA, this should be 2048.

  • dname specifies the X.500 Distinguished Name to be associated with the alias, and is used as the issuer and subject fields in the self-signed certificate. If no distinguished name is provided at the command line, the user will be prompted for one. An X.500 Distinguished name is a set of named fields, of these, the field named "CN", ("Common Name"), is the internet-facing fully qualified domain name of the server.

  • keypass is a password used to protect the private key of the generated key pair. If no password is provided, the user is prompted for it. If you press RETURN at the prompt, the key password is set to the same password as that used for the keystore. keypass must be at least 6 characters long.

  • ext is used to embed extensions into the certificate generated. For Fusion, the server certificate should include the "SAN" or SubjectAlternativeName extension which allows alternative URIs and IP addresses to be associated with this certificate.

Keystore files created by the keystore tool are in the JKS format, which is a proprietary file format capable of storing multiple key-pairs, certificates, and symmetric encryption keys, and with all entries indexed by the keypair alias.

To generate a self-signed certificate for the Fusion UI running as "localhost", we use the following arguments:

keytool -genkeypair \
 -alias localhost -keyalg RSA -keysize 2048 \
 -keypass secret -storepass secret \
 -validity 365 -keystore my.keystore.jks \
 -ext SAN=DNS:localhost,IP:127.0.0.1 \
 -dname "CN=localhost, OU=org unit, O=org, L=loc, ST=st, C=country"
Note
The value for CN must match the hostname you will be using to access Fusion. For example, if will use the URL https://myfusion.com:8864 to access the UI then the CN should have the value myfusion.com.

This keystore file can now be imported to the Fusion UI keystore. To check the generated keystore we use the openssl tool to pretty-print the signed certificate in the file my.keystore.jks. This is not strictly necessary; this should always be done before sending the certificate to a CA to get it signed properly in order to verify that the certificate information is complete and correct.

To get from the keystore JKS format to a human-readable printout, it must be converted to the text-based "PEM" format, which is ASCII (Base64) armored data prefixed with a -– BEGIN … line. This requires three steps.

First, we use the keytool to convert the proprietary JKS format to the PKCS #12 format:

keytool -importkeystore \
 -srckeystore my.keystore.jks -destkeystore my.keystore.p12 \
 -srcstoretype jks -deststoretype pkcs12

This command prompts for passwords - as before, the password is "secret".

Next, we use openssl to convert the PKCS format to PEM format:

openssl pkcs12 -in my.keystore.p12 -out my.keystore.pem

Finally, to pretty-print the certificate, we use the following openssl command:

openssl x509 -in my.keystore.pem -text -noout

This converts the PEM format to text format, and writes the output to the terminal. The output is:

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 1442779707 (0x55ff123b)
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=country, ST=st, L=loc, O=org, OU=org unit, CN=localhost
        Validity
            Not Before: Apr  8 07:39:35 2015 GMT
            Not After : Apr  7 07:39:35 2016 GMT
        Subject: C=country, ST=st, L=loc, O=org, OU=org unit, CN=localhost
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
            RSA Public Key: (2048 bit)
                Modulus (2048 bit):
                    00:96:04:46:6c:be:7f:ec:ea:18:fa:28:11:a9:fb:
                    3d:07:c5:3c:49:39:57:11:24:1d:75:47:5d:76:26:
                    4b:73:c0:ea:44:7a:a5:59:3a:a7:4b:16:eb:1f:be:
                    05:f1:2a:be:62:72:2c:67:ec:d3:8b:ad:76:af:dc:
                    6d:14:ca:c9:75:5a:76:24:80:c6:f8:55:b0:27:6a:
                    fa:a8:1b:4b:5c:55:93:49:ff:f8:84:67:29:56:80:
                    ca:c1:d8:c4:8c:b8:57:a4:78:6a:e8:e0:2c:51:74:
                    fb:fb:52:3d:d3:e9:58:e5:11:79:5f:5a:70:ec:c3:
                    de:d7:56:36:67:fd:52:dd:73:60:f7:93:9f:00:c0:
                    36:49:65:7d:77:45:76:34:0e:81:38:96:2b:19:b0:
                    30:8b:ac:2f:ae:dd:92:41:78:da:47:32:02:f7:0d:
                    04:f5:51:85:dc:06:58:08:9b:d2:a0:69:52:ac:b2:
                    7d:c7:bd:16:1d:9e:af:e2:2b:6a:61:8e:cb:a9:ec:
                    fc:01:fe:6b:34:49:1c:d8:75:8b:ca:ec:ea:fd:93:
                    0a:8b:34:6b:77:98:ec:83:6f:d2:bc:81:ec:f5:18:
                    48:41:db:92:da:ef:19:19:27:5b:05:5f:8c:6e:1e:
                    9d:e5:90:42:6f:36:8f:11:49:05:aa:dd:a5:c9:0a:
                    fe:81
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Subject Alternative Name:
                DNS:localhost, IP Address:127.0.0.1
            X509v3 Subject Key Identifier:
                E1:D1:66:F6:1F:5A:18:1A:82:33:A7:32:0E:0B:EA:8E:C0:D3:ED:05
    Signature Algorithm: sha256WithRSAEncryption
        56:a8:31:c0:94:8f:5a:80:27:17:36:ba:e0:ff:e6:59:13:9e:
        67:6b:1e:7d:67:04:5c:e1:88:9e:d9:89:11:ca:88:a0:21:4c:
        90:a8:8b:9d:b5:ba:0f:92:65:da:c5:a9:91:82:17:46:55:43:
        82:78:92:b1:f9:f5:2b:65:5e:b0:93:03:3b:94:83:bb:fe:9b:
        09:a9:f3:82:d2:4d:b5:72:e9:ee:75:15:31:3d:18:a7:c1:e8:
        45:44:1d:40:d2:eb:96:b7:01:41:dd:9d:1c:31:e6:45:4a:c2:
        3d:ec:22:1a:35:ec:38:62:e8:3d:b3:30:10:d3:88:09:5a:87:
        54:87:fb:92:d6:0e:74:52:3c:f2:c3:f5:70:61:ea:72:3f:cd:
        65:72:34:6f:51:94:13:e0:7a:73:bb:57:c8:ad:98:f7:3f:43:
        4d:75:96:db:cf:2e:e6:82:1c:c2:97:38:2d:37:06:c4:27:db:
        87:82:6b:c6:01:71:f7:e9:1f:69:62:0d:cc:54:e9:f4:25:86:
        6a:e2:38:72:c3:9c:53:b4:6e:4f:ae:8a:09:36:14:f0:10:57:
        9c:c9:a8:a3:a5:e6:db:d1:d4:39:95:f3:54:95:4f:2f:db:59:
        b6:bd:77:00:77:c2:9d:4f:d9:04:d5:af:33:bb:2e:0f:65:a9:
        74:ff:66:f2