Knowledge Base

A demonstration of IntraCluster SSL Encryption

This document provides a step-by-step demonstration of the process to deploy a Self-Signed SSL Certificate, to member instances of a Causal Cluster, aimed at achieving intra-cluster encryption. The steps can be outlined as:

  • Generate and install cryptographic objects

  • Create an SSL policy

  • Configure Causal Clustering with the SSL policy

  • Validate the secure operation of the cluster

Lets go through the demonstration of creation, deployment and verification of the SSL certificate.

Install OpenSSL

A certificate can be signed by a trusted Certificate Authority (CA) or, as in this case, be a self-signed one. We will create a self-signed certificate using OpenSSL. We’ll first need to install OpenSSL in order to create a self-signed certificate.

Windows

OpenSSL can be installed using a Windows binary. Some sample binaries are available at the below links:

Linux

Many Linux distributions has OpenSSL installed. If this is not the case, use a package manager to install openssl, for example:

$ sudo apt-get install openssl

Mac

On OSX, OpenSSL can be installed using macports, as described here: https://www.macports.org/install.php

Or alternatively via homebrew package manager as below:

$ brew install openssl

Verify Installation

Once installed, the version and installation directory, amongst other installation features, can be checked by running brew info openssl, or openssl version -a:

$ openssl version -a
LibreSSL 2.8.3
built on: date not available
platform: information not available
options:  bn(64,64) rc4(16x,int) des(idx,cisc,16,int) blowfish(idx)
compiler: information not available
OPENSSLDIR: "/private/etc/ssl"

Create a Neo4j SSL Framework directory structure

Neo4j SSL Framework requires the following directory structure be created:

<NEO4J_HOME>/certificates
                └── cluster
                    ├── revoked
                    └── trusted

From <NEO4J_HOME> run the following commands to create the above structure:

---
$ mkdir certificates/cluster
$ mkdir certificates/cluster/trusted
$ mkdir certificates/cluster/revoked
---

Create the SSL Certificate and Key

Use the following command to create a certificate cert.pem and a key key.pem making sure to change xxx to the number of days the certificates should be valid for:

$ sudo openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days XXX

or, for a relatively smaller key length:

$ sudo openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days XXX

Below describes each parameter used in the openssl command above:

  • req: PKCS#10 certificate request and certificate generating utility.

  • x509: outputs a self signed certificate instead of a certificate request.

  • newkey: creates a new certificate request and a new private key. Note the rsa:nbits, where nbits is the number of bits, generates an RSA key nbits in size.

  • keyout: gives the filename to write the newly created private key to.

  • out: specifies the output filename to write to or standard output by default.

  • days: when the -x509 option is being used this specifies the number of days to certify the certificate for (default is 30 days).

Below is the output of the executed openssl generation command:

$ sudo openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365
Password:
Generating a 4096 bit RSA private key
..................................................................................................................................................++
................................................................................................++
writing new private key to 'key.pem'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
Country Name (2 letter code) [AU]:UK
State or Province Name (full name) [Some-State]:London
Locality Name (eg, city) []:London
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Neo4j
Organizational Unit Name (eg, section) []:CS
Common Name (e.g. server FQDN or YOUR name) []:CS
Email Address []:myemail@email.com

The below commands then generate the public.crt and private.key files, using the .pem files created above:

$ sudo openssl x509 -outform pem -in cert.pem -out public.crt
$ openssl rsa -in key.pem -out private.key

DEPLOYING THE SSL CERTIFICATE AND KEY

Place the above created private.key and public.crt in $NEO4J_HOME/certificates/cluster. Then place public.crt in $NEO4J_HOME/certificates/cluster/trusted:

certificates
└── cluster
    ├── private.key
    ├── public.crt
    ├── revoked
    └── trusted
        └── public.crt

Then add the following to neo4j.conf of each instance in the cluster, making sure to replace [Absolute_Path_Of_$NEO4J_HOME] appropriately:

dbms.ssl.policy.cluster.enabled=true
dbms.ssl.policy.cluster.base_directory=<<Absolute_Path_Of_$NEO4J_HOME>>/certificates/cluster
dbms.ssl.policy.default.base_directory=<<Absolute_Path_Of_$NEO4J_HOME>>/certificates/cluster
dbms.ssl.policy.default.trusted_dir=<<Absolute_Path_Of_$NEO4J_HOME>>/certificates/cluster/trusted
dbms.ssl.policy.default.revoked_dir=<<Absolute_Path_Of_$NEO4J_HOME>>/certificates/cluster/revoked
dbms.ssl.policy.cluster.ciphers=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
dbms.ssl.policy.cluster.client_auth=REQUIRE

Validate the Intra-cluster Encryption

We’re now ready to initialise all cluster instances. Once these are initialised and available, we can then verify our SSL encryption by using the nmap tool (sometimes deployed alongside openssl otherwise it will need to be installed separately), to check the available SSL ciphers as below:

$ nmap --script ssl-enum-ciphers -p 5000 localhost
Starting Nmap 7.80 ( https://nmap.org ) at 2022-07-07 14:18 UTC
Nmap scan report for localhost (127.0.0.1)
Host is up (0.000049s latency).
Other addresses for localhost (not scanned): ::1

PORT     STATE SERVICE
5000/tcp open  upnp
| ssl-enum-ciphers:
|   TLSv1.2:
|     ciphers:
|       TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 (secp256r1) - A
|     compressors:
|       NULL
|     cipher preference: indeterminate
|     cipher preference error: Too few ciphers supported
|     warnings:
|       Key exchange (secp256r1) of lower strength than certificate key
|_  least strength: A

Nmap done: 1 IP address (1 host up) scanned in 0.31 seconds

Where port 5000 is the default Causal Cluster Discovery Management. The above configuration will also enable SSL on port 6000 and 7000 which are Causal Cluster Transaction and Causal Cluster RAFT ports respectively. Details on Neo4j port usages can be found on the following link:

An additional confirmation would be to find debug messages similar to the following, in the Neo4j debug.log:

2022-07-08 09:30:28.006+0000 INFO  [o.n.s.c.SslPolicyLoader] Loaded SSL policy 'CLUSTER' = SslPolicy{keyCertChain=Subject: EMAILADDRESS=myemail@email.com, CN=neo4j.local, OU=Support, O=Neo4j, L=London, ST=London, C=UK, Issuer: EMAILADDRESS=myemail@email.com, CN=neo4j.local, OU=Support, O=Neo4j, L=London, ST=London, C=UK, ciphers=[TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384], tlsVersions=[TLSv1.2], clientAuth=REQUIRE}

References: