Before you can enable server-to-server and client-to-server encryption using Transport Security Layer (TLS), you need to prepare each node in a YugabyteDB cluster.

Create server certificates

Creating server certificates involves a number of steps.

Create a secure data directory

To generate and store the secure information, such as the root certificate, create a directory, secure-data, in your root directory by running the following command:

mkdir secure-data

After completing the preparation, you will copy this data into a secure location and then delete this directory.

Create temporary node directories

Create one directory for each node to put all the required data in that directory, as follows:

mkdir 127.0.0.1/ 127.0.0.2/ 127.0.0.3/

The files added to each directory will be copied into the tls-cert directory on each node.

You should now have three directories, named 127.0.0.1, 127.0.0.2, and 127.0.0.3, representing the three nodes of your YugabyteDB cluster.

Create the root configuration file

Create the file ca.conf in the secure-data directory with the OpenSSL CA configuration, as follows:

cat > secure-data/ca.conf

Paste the following example root configuration into the file:

####################################
# Example CA root configuration file
####################################

[ ca ]
default_ca = my_ca

[ my_ca ]
# Validity of the signed certificate in days
default_days = 3650

# Text file with next hex serial number to use
serial = secure-data/serial.txt

# Text database file to use, initially empty
database = secure-data/index.txt

# Message digest algorithm. Do not use MD5
default_md = sha256

# Section with a set of variables corresponding to DN fields
policy = my_policy

[ my_policy ]

# Policy for nodes and users. If the value is "match", then
# field value must match the same field in the CA certificate.
# If the value is "supplied", then it must be present. Optional
# means it may be present
organizationName = supplied
commonName = supplied

[req]
prompt=no
distinguished_name = my_distinguished_name
x509_extensions = my_extensions

[ my_distinguished_name ]
organizationName = Yugabyte
commonName = CA for YugabyteDB

[ my_extensions ]
keyUsage = critical,digitalSignature,nonRepudiation,keyEncipherment,keyCertSign
basicConstraints = critical,CA:true,pathlen:1

To save and close the file, enter Ctl+D.

Add required files

Create the index file index.txt and database file serial.txt by running the following commands:

touch index.txt
echo '01' > serial.txt

Generate the root key

To generate the root private key file ca.key in the secure-data directory, run the following openssl genrsa command:

openssl genrsa -out secure-data/ca.key

You should see an output similar to the following:

Generating RSA private key, 2048 bit long modulus (2 primes)
......................+++++
.................+++++
e is 65537 (0x010001)

Change the access permissions of the generated private key to allow read-only privileges by running the chmod command, as follows:

chmod 400 secure-data/ca.key

Generate the root certificate file

Generate the root certificate file ca.crt by running the following openssl req command:

openssl req -new \
            -x509 \
            -days 3650 \
            -config secure-data/ca.conf \
            -key secure-data/ca.key \
            -out secure-data/ca.crt

In the secure-data directory, you should now have the following three files:

  1. ca.conf - root configuration file
  2. ca.key - root key file
  3. ca.crt - root certificate file

You can verify the root certificate by running the following openssl x509 command:

openssl x509 -in secure-data/ca.crt -text -noout

You should see an output similar to the following:

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            61:ca:24:00:c8:40:f3:4d:66:59:80:35:86:ca:b9:6f:98:b1:1c:5e
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: O = Yugabyte, CN = CA for YugabyteDB
        Validity
            Not Before: Feb 14 04:40:56 2020 GMT
            Not After : Mar 15 04:40:56 2020 GMT
        Subject: O = Yugabyte, CN = CA for YugabyteDB
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                RSA Public-Key: (2048 bit)
                Modulus:
                    00:c9:8c:20:7d:63:ed:8d:9f:2d:f2:2e:90:34:2c:
                    79:0b:0b:77:2f:4c:88:78:63:28:db:91:6d:c4:21:
                    bd:e2:dd:14:a3:ba:e5:db:4d:b9:34:e8:74:7b:1f:
                    ff:70:a2:8c:0c:f5:df:d4:11:ae:5c:4c:1a:22:94:
                    98:4e:a7:63:ee:44:5b:c6:b7:f0:34:ef:4e:57:1a:
                    30:99:ee:f7:c9:d9:df:e9:af:ab:df:08:e3:69:d9:
                    d4:5d:8e:0c:50:7a:bf:be:7f:f0:7f:e3:20:13:d8:
                    c9:44:21:1f:05:6b:52:d3:77:b8:75:8e:78:c6:60:
                    3c:7e:9a:8a:77:b2:65:da:6c:25:7a:4a:ee:eb:4a:
                    a8:6b:43:79:ea:15:96:8b:3d:03:50:08:a4:2d:76:
                    2f:09:e3:eb:b3:f6:77:17:2a:3e:dc:9b:f8:60:cf:
                    93:f3:84:6a:19:b0:64:4a:0f:47:51:c9:47:0f:20:
                    5d:cd:af:1e:5d:65:36:0f:b0:44:c3:eb:9a:63:44:
                    dd:ac:25:f8:f4:60:6c:9b:72:46:6d:18:c3:94:7d:
                    b5:d9:89:79:e1:39:dd:4f:01:26:b2:da:c1:ac:af:
                    85:d9:cc:a7:02:65:2a:d6:06:47:cc:11:72:cc:d6:
                    92:45:c0:64:43:4c:13:07:d1:6f:38:8e:fe:db:1e:
                    5e:e5
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature, Non Repudiation, Key Encipherment, Certificate Sign
            X509v3 Basic Constraints: critical
                CA:TRUE, pathlen:1
    Signature Algorithm: sha256WithRSAEncryption
         9e:d1:41:36:63:78:4b:e4:57:f2:bd:23:c4:4b:e1:64:e8:c0:
         e3:e1:30:c5:2b:dd:b0:c2:99:ca:86:cb:85:70:6f:29:4c:b0:
         3e:ba:76:af:87:22:a3:64:1f:3e:4f:69:74:8b:a3:b3:e0:71:
         12:aa:0b:28:85:0a:45:40:7b:a5:d1:42:cd:51:bc:85:6a:53:
         16:69:89:78:85:bd:46:9d:1a:ca:19:14:de:72:e4:5c:91:51:
         58:99:b5:83:97:a5:63:dc:b9:7a:05:1e:a9:a7:5f:42:e1:12:
         4e:2b:e1:98:e5:31:14:b5:64:5f:66:bc:13:b8:19:ca:9c:ad:
         12:44:f8:21:3b:ef:0d:ca:9b:c4:04:d6:d7:93:d2:83:87:79:
         2a:2d:dc:de:4c:ad:30:cf:10:de:05:24:52:91:31:fd:cc:d6:
         cb:3b:ba:73:8f:ae:0d:97:f0:e4:aa:ca:76:c0:15:3c:80:7d:
         3a:d8:28:3c:91:bc:19:c8:5c:cd:94:49:31:23:ae:08:e5:9a:
         ce:62:6a:53:08:38:6d:0f:b4:fd:e9:66:8c:fb:cd:be:a0:01:
         b4:9d:39:57:58:6c:b3:8e:25:e3:86:24:13:59:d6:a0:d2:f0:
         15:1e:8c:24:44:5b:3a:db:1c:ef:60:70:24:58:df:56:99:aa:
         22:78:12:d6

Copy the root certificate to each node directory

Copy the generated root certificate file ca.crt to all three node directories, as follows:

cp secure-data/ca.crt 127.0.0.1
cp secure-data/ca.crt 127.0.0.2
cp secure-data/ca.crt 127.0.0.3

Generate key and certificate files for each node

Now you can generate the node key node.key and node certificate node.crt for each node.

Generate configuration for each node

Repeat the following steps for each node, replacing <node-ip-address> with the IP address of the subject node:

  1. Generate a configuration file node.conf for a node, using the node's IP address <node-ip-address> as the directory name, as follows:

    cat > <node-ip-address>/node.conf
    
  2. Add the following sample configuration content (use as-is, or customize as needed):

    #################################
    # Example node configuration file
    #################################
    
    [ req ]
    prompt=no
    distinguished_name = my_distinguished_name
    
    [ my_distinguished_name ]
    organizationName = Yugabyte
    # Required value for commonName, do not change
    commonName = <node-ip-address>
    
    # Multiple subject alternative names (SANs) such as IP Address,
    # DNS Name, Email, URI, and so on, can be specified under this section
    [ req_ext]
    subjectAltName = @alt_names
    [alt_names]
    IP.1 = <IP Address>
    IP.2 = <IP Address>
    DNS.1 = <DNS Name>
    DNS.2 = <DNS Name>
    
  3. After pasting the content in step 2 and replacing <node-ip-address> with the node IP address, save and close the file by entering Ctl+D.

You should have a copy of node.conf in the 127.0.0.1, 127.0.0.2, and 127.0.0.3 directories.

Generate private key files for each node

For each of the three nodes, generate the node private key by running the following command, replacing <node-ip-address> with the node IP address:

openssl genrsa -out <node-ip-address>/node.<node-ip-address>.key
chmod 400 <node-ip-address>/node.<node-ip-address>.key

For YugabyteDB to recognize the file, it must be of the format node.<commonName>.key. In the preceding example, you have used the <node-ip-address> for the <commonName>, so the file names should be node.127.0.0.1.key, node.127.0.0.2.key, and node.127.0.0.3.key.

Generate the node certificates

You need to generate the node certificate by creating the certificate signing request (CSR) for each node, as follows:

openssl req -new \
            -config <node-ip-address>/node.conf \
            -key <node-ip-address>/node.<node-ip-address>.key \
            -out <node-ip-address>/node.csr

Sign each node CSR using the root key ca.key and root certificate ca.crt. Run the following openssl ca command:

openssl ca -config secure-data/ca.conf \
           -keyfile secure-data/ca.key \
           -cert secure-data/ca.crt \
           -policy my_policy \
           -out <node-ip-address>/node.<node-ip-address>.crt \
           -outdir <node-ip-address>/ \
           -in <node-ip-address>/node.csr \
           -days 3650 \
           -batch \
           -extfile <node-ip-address>/node.conf \
           -extensions req_ext

For the 127.0.0.1 node, you should see an output similar to the following:

Using configuration from secure-data/ca.conf
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
organizationName      :ASN.1 12:'Yugabyte'
commonName            :ASN.1 12:'127.0.0.1'
Certificate is to be certified until Feb 11 04:53:11 2030 GMT (3650 days)

Write out database with 1 new entries
Data Base Updated

Each node key and certificate should use the node.<commonName>.[crt | key] naming format.

You can verify the signed certificate for each of the nodes by running the following openssl verify command:

openssl verify -CAfile secure-data/ca.crt <node-ip-address>/node.<node-ip-address>.crt

You should see the following output, displaying the node IP address:

X.X.X.X/node.X.X.X.X.crt: OK

Copy configuration files to the nodes

The files needed for each node are:

  1. ca.crt
  2. node.<commonName>.crt (for example, node.127.0.0.1.crt)
  3. node.<commonName>.key (for example, node.127.0.0.1.key)

You can remove all other files in the node directories, as they are unnecessary.

Upload the necessary information to each target node.

Create the directory that will contain the configuration files, as follows:

ssh <username>@<node-ip-address> mkdir ~/certs

Copy all the configuration files into the preceding directory by running the following commands:

scp <node-ip-address>/ca.crt <user>@<node-ip-address>:~/certs/<node-ip-address>
scp <node-ip-address>/node.<node-ip-address>.crt <user>@<node-ip-address>:~/certs/<node-ip-address>
scp <node-ip-address>/node.<node-ip-address>.key <user>@<node-ip-address>:~/certs/<node-ip-address>

You can now delete, or appropriately secure, the directories you created for the nodes on the local machine.