0530 Self Signed Encryption for MonetDB

MonetDB can not encrypt its communication over the wire. This is leaved to specialized programs that are called "TLS Termination Proxy". In that way we get superb protection and flexibility provided by these tools.

Clients must also have support for TLS. "Mclient" and "Pymonetdb" have support for TLS.

TLS (Transport Layer Security ) is a critical internet protocol that encrypts and authenticates data in transit. TLS is widely tested and trusted, and it is used in HTTPS, email, and VPNs to prevent eavesdropping and tampering.

Most popular client tools (DBeaver, JDBC, Python libraries, etc.) already support TLS.

Purple Server

I will create totally new server for this blog post. I will call it "Purple Server ". This is the server on the new virtual machine.

I am currently the user "fff". I will add myself to "monetdb" group. This group was created after the installation of the MonetDB. People from this group can start a database.

sudo adduser fff monetdb

For this to apply, we have to log out, and then to log in.
Then, I will start monetdbd servis, and I will create a database "tlsDB".

sudo systemctl start monetdbd
monetdb create tlsDB
monetdb release tlsDB


This database will be created in the default folder "/var/monetdb5/dbfarm/".

This command bellow will make my server the full fledged systemctl controled daemon. That means that MonetDB will automatically start when I start my computer.
systemctl enable monetdbd

Self-Signed Certificate

In this tutorial we will create certificate ourselves, and we will use that certificate both on the server and on the client.

We will change default port of the MonetDB to 49999. This is because I want to use the port 50000 for TLS connection.monetdbd set port=49999 /var/monetdb5/dbfarm

Internal communication will use 127.0.0.1:49999, and external encrypted communication will use 192.168.100.152:50000. The only way to access MonetDB is through the TLS proxy server.

Creation of a Self-Signed Certificate

At the location "/etc/ssl/private" we have a folder that is only accessible to root. We can use any other folder, but it is important that folder has restrictive permissions, and that only admin can access it.
We can not access this folder with "sudo cd" because sudo doesn't work with built-in command "cd". We will first take the role of the root with "sudo -i", and then we will "cd /etc/ssl/private". That will make this folder our current folder.

Inside of this folder I will make a script.
touch /etc/ssl/private/SelfCertScript.sh

I will open this script in nano. I will paste the code.

nano SelfCertScript.sh

This is the version where we use IP address for the server.
I don't have a domain name, so I will use this version. =>
#!/bin/bash
set -euo pipefail

IP="192.168.100.152"
DAYS=90
KEY="selfsigned.key"
CRT="selfsigned.crt"

openssl req -x509 -newkey rsa:2048 -sha256 -nodes \
-keyout "$KEY" -out "$CRT" -days "$DAYS" \
-subj "/CN=$IP" \
-addext "subjectAltName=IP:$IP"

This is the version you use, if you have a domain name.  
#!/bin/bash
set -euo pipefail  

DOMAIN="dbhost.mymonetdb.org"
DAYS=90
KEY="selfsigned.key"
CRT="selfsigned.crt"  

openssl req -x509 -newkey rsa:2048 -sha256 -nodes \
-keyout "$KEY" -out "$CRT" -days "$DAYS" \
-subj "/CN=$DOMAIN" \
-addext " subjectAltName=DNS:$DOMAIN"
This is the version with the both.  
#!/bin/bash
set -euo pipefail  

IP="192.168.100.152"
DOMAIN="dbhost.mymonetdb.org"
DAYS=90 KEY="selfsigned.key"
CRT="selfsigned.crt"  

openssl req -x509 -newkey rsa:2048 -sha256 -nodes \
-keyout "$KEY" -out "$CRT" -days "$DAYS" \
-subj "/CN=$DOMAIN" \
-addext "subjectAltName=DNS:$DOMAIN,IP:$IP"

https://dbhost.mymonetdb.org
https://192.168.100.152
If we use IP in the script, then the clients must use IP. If we use domain name, then the clients must use domain name.
If we use both in the script, then the client tool can connect both with the IP or with the domain name.

We will now run our script.
bash ./SelfCertScript.sh
Two files will be created inside of the private folder. "selfsigned.key" is our secret that must be secure. This is why is important to use folder accessible only to root. "selfsigned.crt" is file that we will send to clients so that they can access our database.

We can also change permissions on files.
sudo chmod 600 /etc/ssl/private/selfsigned.*

Only root now have read, write rights on our files.

Using Some Other Folder

We can also keep our script, key and certificate in some other folder.
First, we will create a folder, and then we can make that folder only accessible to a root.
"chmod 700" means read/write/execute rights.
sudo mkdir /some/folder
sudo chown root:root /some/folder
sudo chmod 700 /some/folder

Script Explanation

!/bin/bashShebang: run this script with the Bash shell (not sh, zsh, etc.).
-e (errexit)Exit immediately if any simple command returns a non-zero status (if there is an error).
-u (nounset)Treat the use of unset or empty variables as an error, and exit.
-o pipefailin a pipeline a | b | c, the pipeline's exit status is the first non-zero exit code among a, b, or c (instead of just c).

Let's dissect this line.openssl req -x509 -newkey rsa:2048 -sha256 -nodes -keyout "$KEY" -out "$CRT" -days "$DAYS" -subj "/CN=$DOMAIN" -addext "subjectAltName=DNS:$DOMAIN,IP:$IP"

openssl reqWe start self-signed certificate creation process.
-x509Create a self-signed certificate instead of a certificate signing request (CSR). CSR is for commercial certificates.
-newkey rsa:2048Generate a new RSA private key of 2048 bits.
-sha256Use SHA-256 as the hash algorithm.
-nodesPrivate key will not be encrypted. This is useful for automation, because there is no need for a password.
-keyout "$KEY_FILE"Private key will be saved to this file.
-out "$CRT_FILE"Certificate will be saved to this file.
-days "$EXPIRATION_DAYS"Certificate will be valid for 90 days. Clients usually do not trust certificates with a longer lifespan.
-subj "/CN=$IP"IP address (or domain name).
-addext "subjectAltName=IP:$IP"The same as above, but modern, because it can accept several IP addresses or domains.

Stunnel

"Stunnel" is the name of a program that we will use as a "TLS Termination Proxy". We now have to install it and configure it.

apt install stunnel4We install it. We are already the root, so we don't need "sudo".

stunnel -version

which stunnelWe find its installation folder.

cd /etc/stunnel
touch monetdb.conf
We'll go to stunnel installation folder. There we will create configuration file.

We'll open this file in nano, and we will paste the code.  

nano monetdb.conf
foreground = yes

cert = /etc/ssl/private/selfsigned.crt
key  = /etc/ssl/private/selfsigned.key

[monetdb]
accept  = 0.0.0.0:50000
connect = 127.0.0.1:49999

Stunnel Systemd Service

MonetDB service will always run automatically, because it is controlled by systemd. We want the same for stunnel. For stunnel to become a service, first we have to create configuration file for that service (systemd unit file).

First, we go to folder where we have to place systemd unit file.
cd /etc/systemd/system  

We create new file:
touch stunnel-monetdb.service  

We open this file in nano text editor:
nano stunnel-monetdb.service  

We paste our code into it:
[Unit]
Description=Stunnel TLS for MonetDB
After=network.target

[Service]
ExecStart=/usr/bin/stunnel /etc/stunnel/monetdb.conf
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
PrivateTmp=yes

[Install]
WantedBy=multi-user.target

Let's explain parts of this system unit file:

After=network.targetThis is a prerequisite. Stunnel should only be started after the network becomes functional during system startup.
ExecStart=/usr/bin/stunnel /etc/stunnel/monetdb.confStart stunnel program, with specified configuration file.
ExecReload=/bin/kill -HUP $MAINPID$MAINPID is process ID of the stunnel. "-HUP" means that stunnel should reload without restarting process.
Restart=on-failureRestart stunnel if it crushes.
PrivateTmp=yesInstead of /tmp and /var/tmp, service will use its own private temporary folders.
WantedBy=multi-user.targetDuring the startup, stunnel should start after some basic services already started.

Now we have to use this "stunnel-monetdb.service" file to register our new service with systemd:

sudo systemctl daemon-reexecUsed to refresh systemd.
sudo systemctl daemon-reloadReload all of the "systemd unit files". Now, it will include our "stunnel-monetdb.service" file.
sudo systemctl enable stunnel-monetdb.serviceTo have the service start automatically during reboot.
sudo systemctl start stunnel-monetdb.serviceStart our service immediately, without waiting for the first reboot. 

We can now check who is listening on port 50.000. So, port 50.000 is listened by stunnel.

sudo ss -tnlp | grep 50000

TLS Connection from the Local Computer

I will exit being root with "exit". I am running this on the purple server. URL is of the purple server.
mclient -d monetdbs://192.168.100.152:50000/tlsDB
It won't work because mclient doesn't have access to the certificate.

We will copy content of our certificate to $HOME folder. We need folder where mclient has access.sudo cat /etc/ssl/private/selfsigned.crt >$HOME/selfsigned.crt

We will use that folder to signal mclient where to find certificate.
mclient -d "monetdbs://192.168.100.152:50000/tlsDB?cert=$HOME/selfsigned.crt"

Now, we have access.

TLS Connection from the Remote Computer

On the other virtual machine, I will place "selfsigned.crt" into home directory.

The same command will work here, too.

mclient -d "monetdbs://192.168.100.152:50000/tlsDB?cert=$HOME/selfsigned.crt"

How to use TLS with Pymonetdb

On this blog post "link", I have explained how to install pymonetdb. In the mean time there were some changes in the newest versions of Ubuntu.

If we follow that old blog post, we'll get an error.
sudo apt install python3-pip     #install pip
pip install pymonetdb                   #install pymonetdb

While we can install pip, we will not be able to install pymonetdb in this way. Ubuntu is trying to prevent us to install packages into global python context. Ubuntu wants us to use virtual environment. It doesn't want us to mess with global python environment.

We can still install into global environment in this way. This will only work for packages that are inside of the ubuntu repository.
sudo apt install python3-pymonetdb

I will install Spyder IDE:
sudo apt install spyder
I will open this GUI program
and I will run this code=>
import pymonetdb
connection = pymonetdb.connect("monetdbs://192.168.100.152:50000/tlsDB?cert=/home/fff/selfsigned.crt")
cursor = connection.cursor()
cursor.execute('SELECT 2')
print(cursor.fetchone())

We can also test the code in the command line.
python3 -c 'import pymonetdb;connection = pymonetdb.connect("monetdbs://192.168.100.152:50000/tlsDB?cert=/home/fff/selfsigned.crt" );cursor = connection.cursor();cursor.execute("SELECT 2");print(cursor.fetchone())'

We can also use syntax like this one:
connection = pymonetdb.connect("monetdbs://192.168.100.152:50000/tlsDB", cert="/home/fff/selfsigned.crt")

How to use TLS with ODBC

We will again use our Green server. We created that server in this blog post "link", and we installed ODBC drivers in it, in this other post "link".

In the mentioned post "0500 Proto_loaders, ODBC and COPY in MonetDB", we created the file "/etc/odbc.ini" with the credentials of the Blue server. We will now modify that file, so that it leads toward the Purple server, because we want to test TLS connection.

We'll change credentials, but we will add two more properties. We'll add TLS and CERT property.
FOR THE BLUE SERVER:
[DatabaseB]
Description = Connect to Blue Server
Driver = MonetDB
Server = 192.168.100.146
Port = 50000
Database = DatabaseB
User = monetdb
Password = monetdb
FOR THE PURPLE SERVER:
[tlsDB]
Description = Connect to Blue Server
Driver = MonetDB Server = 192.168.100.152
Port = 50000
Database = tlsDB
User = monetdb
Password = monetdb
TLS = ON
CERT = /home/sima/selfsigned.crt

Now it is easy to connect to stunnel through ODBC driver manager.

isql -v tlsdB

How to use TLS with JDBC

In this blog post "link", we downloaded JDBC driver/client to the green server. We will use that client again, but this time with the connection string for TLS.

java -jar /home/sima/Desktop/jdbcclient.jre8.jar -u monetdb -d "jdbc:monetdbs://192.168.100.152:50000/tlsDB?cert=/home/sima/selfsigned.crt"

We will also connect through DBeaver and JDBC. Before my explanation, it would be wise to read how to use DBeaver and JDBC without TLS. It is explained on this blog "link". I will not repeat here the whole story, just the difference. The difference is in the connection, we have to provide certificate.

We can create new connection (1), or we can edit the existing one (2).
We will fill the dialog with credentials for the Purple server (3). After that, we will go to the "Driver properties" tab (4). There we have to add our certificate. Now we can connect.

Leave a Comment

Your email address will not be published. Required fields are marked *