Secure Communication with Stunnel

Originally published in the LinuxGazette.net, October 2004, Issue 107.

1. Introduction

Stunnel is an SSL encryption wrapper that allows what are normally plain text and insecure communications to be encrypted during transmission. Stunnel recently went through some major changes and the current version (4.x) has a completely different architecture than previous versions. In this article I will be dealing exclusively with the new version.

One of Stunnel's most common uses is encrypting communications between POP or IMAP mail servers and e-mail clients. Both of these protocols require users to authenticate themselves with a username and a password. In the majority of cases, these usernames and passwords are the same ones as they would use for logging into the machine locally or remotely via SSH. Without using Stunnel to encrypt this data, anyone intercepting the transmission could now log into your server and gain elevated privileges much easier than a local exploit would require.

2. Getting and Installing Stunnel

Stunnel is generally included as a precompiled package with most common distributions and is possibly already installed on your system. If not, locate the package on your distribution's installation CDs or download it from the distribution's website.

The source code is released under the GNU General Public License and, as such, is freely available for download and installation. The current version (which at time of going to press was 4.05) can be downloaded from ftp://stunnel.mirt.net/stunnel/. To compile and install Stunnel, download the source code tarball from here and then execute the following commands:

$ tar zxf stunnel-4.XX.tar.gz
$ cd stunnel-4.XX
$ ./configure
$ make
$ make install   (as root)

3. Generating a Self-Signed Certificate

In order to use Stunnel we must first have a certificate-key pair. If you compiled from sources then such a pair will have been created for you automatically (stunnel.pem). Some pre-built binary packages may include a certificate-key pair, some may generate one as part of the installation procedure and others may leave it up to the user to generate one.

The easiest way of generating a certificate-key pair is by using a script provided with Stunnel's source code. If you're compiling from the tarball, just issue the following additional commands in the source directory:

$ cd tools
$ make stunnel.pem
I have decided to put the specific details outside the scope of this article, but if you are interested in the actual details then have a look at the Makefile in the "tools" directory.

4. Using Stunnel to Encrypt POP3/IMAP

This method can be used to encrypt any similar service where SSL-enabled clients exist and are readily available. Most e-mail clients are SSL-enabled for POP3, IMAP and SMTP, most internet clients (web browsers) are enabled for HTTPS, etc.

Once Stunnel is installed and you have generated a certificate-key pair, you are only a simple configuration file away from using Stunnel to encrypt your communications. A simple one that would encrypt POP3 and IMAP communications would be:

# Sample stunnel configuration file for POP3/IMAP

# Provide the full path to your certificate-key pair file
cert = /usr/local/etc/stunnel/stunnel.pem

# lock the process into a chroot jail
chroot = /usr/local/var/run/stunnel/
# and create the PID file in this jail
pid = /stunnel.pid

# change the UID and GID of the process for security reasons
setuid = nobody
setgid = nobody

# Configure our secured POP3 and IMAP services

[pop3s]
accept  = 995
connect = 110

[imaps]
accept  = 993
connect = 143

Using this configuration, any encrypted connection coming in on port 995 (POP3s) will be decrypted and forwarded to the local service (POP3) on port 110. When the local POP3 service responds, it will be encrypted by Stunnel and transmitted back through port 995. Similarly for IMAPs on port 993.

Stunnel operates as a daemon service by default, so to start it off with this configuration we can simply execute:

stunnel stunnel-secure-email.conf
where stunnel-secure-email.conf is the text file containing the above configuration; ensure you change the paths so that they are correct for your system.

We can set up Stunnel to start during boot-up by placing the appropriate command in the rc.local file that is usually contained in /etc/rc.d/. This file is the last file executed during a system boot and it is generally used by system administrators for their own initialisation stuff. When placing commands in this script, use fully qualified paths such as:

/path/to/stunnel /path/to/the/configuration-file
For Debian and similar distros without an 'rc.local', the procedure varies slightly: modify a copy of "/etc/init.d/skeleton" (named, e.g., "/etc/init.d/stunnel") to run the above and create a link to it from the appropriate runlevel (usually /etc/rc2.d/).

Stunnel can also be used with (x)inetd if preferred. You can find further details in Stunnel's man page.

5. Using Stunnel to Encrypt MySQL Transactions

This method can be used to encrypt any service where neither the server nor the client are SSL-enabled. Common examples include CVS, MySQL, etc.

In the example with POP3 and IMAP above, we were only concerned with providing the server with SSL encryption as the clients generally have this built in. However, neither the standard MySQL server nor client have SSL capabilities - but we can still use Stunnel to provide this.

It involves using a Stunnel daemon on both the server's machine and the client's machine. The configuration for the server side is similar to the one we used above for POP3/IMAP. The default MySQL port is 3306, and since no port is reserved for secure MySQL connections, I will use 3307:

# Sample stunnel configuration file for securing MySQL (server side)

# Provide the full path to your certificate-key pair file
cert = /usr/local/etc/stunnel/stunnel.pem

# lock the process into a chroot jail
chroot = /usr/local/var/run/stunnel/
# and create the PID file in this jail
pid = /stunnel.pid

# change the UID and GID of the process for security reasons
setuid = nobody
setgid = nobody

# Configure our secured MySQL server

[mysqls]
accept  = 3307
connect = 3306
I can now start the Stunnel daemon on the server machine with:
$ stunnel stunnel-mysql-server.conf
where stunnel-mysql-server.conf is a text file containing the above configuration. We also need to set up an Stunnel daemon on the client machine with the following configuration:
# Sample stunnel configuration file for securing MySQL (client side)

# Provide the full path to your certificate-key pair file
cert = /usr/local/etc/stunnel/stunnel.pem

# lock the process into a chroot jail
chroot = /usr/local/var/run/stunnel/
# and create the PID file in this jail
pid = /stunnel.pid

# change the UID and GID of the process for security reasons
setuid = nobody
setgid = nobody

# enable client mode
client = yes

# Configure our secured MySQL client

[mysqls]
accept  = 3306
connect = 1.2.3.4:3307
You'll notice that I have used a new option: client = yes - this enables "client mode" which lets Stunnel know that the remote service uses SSL. Our local Stunnel daemon will now listen for connections on the local MySQL port (3306), encrypt them and forward them to our MySQL server machine (say 1.2.3.4) where another Stunnel is listening on port 3307. The remote Stunnel will decrypt the transmission and forward it to the MySQL server listening on port 3306 of the same machine. All responses will be sent back through the same encrypted channel.

Save the client configuration as stunnel-mysql-client.conf and start off Stunnel with:

$ stunnel stunnel-mysql-client.conf
and then you can connect to the remote MySQL server through the encrypted channel by connecting to the local Stunnel daemon (which is listening on MySQL's 3306 port):
$ mysql -h 127.0.0.1 -u username -p

6. Trouble Shooting

Stunnel can be a bit tricky about permissions - especially when using a chroot jail and reducing your user and group ID to nobody (some systems might need nogroup for setgid). Ensure your chrooted directory is writable by the nobody user and/or the nobody (or nogroup) group.

Stunnel runs in the background by default and doesn't show any error messages. This means you won't know if it worked or not from the command line! You can check that the process is running by searching the output of the ps command:

$ ps -ef | grep stunnel
nobody 21769 [...] /usr/local/sbin/stunnel ./stunnel-mysql-server.conf

Stunnel can also be instructed to run in the foreground by adding the following command to the configuration file (above the service configuration):

foreground = yes

As with all services, the best method of diagnosing problems is through the service's log messages. You can enable Stunnel's logging facilities by adding the following commands to the configuration file (above the service configuration):

debug = 7
output = /tmp/stunnel.log

If you are running in the foreground for testing/debugging, then you might prefer to send the log messages to standard out:

debug = 7
output = /dev/stdout

7. Further Reading/References

There are many other commands that can be used in the configuration files and these are all listed in Stunnel's man page (STUNNEL(8)).

The following websites may also prove useful:

As always, I appreciate any feedback on this or previous articles and suggestions/requests for future ones. You'll find my e-mail address on my contact details page.

Copyright © 2004, Barry O'Donovan. Released under the Open Publication license.