Hack #100. Encrypt and Tunnel Traffic with SSL

Use stunnel to add SSL encryption to any network service.

stunnel (http://www.stunnel.org) is a powerful and flexible program that, using SSL, can encrypt traffic to and from any TCP port in several different ways. stunnel can tunnel connections, much like SSH can, by providing a local port to connect to. It encrypts the traffic sent to this port, forwards it to a remote system, decrypts the traffic, and finally forwards it to a local port on that system. stunnel can also provide transparent SSL support for inetd-compatible services.

To install stunnel, simply run ./configure from the directory that was created when you unpacked the archive file that you downloaded. Since stunnel requires OpenSSL (http://www.openssl.org), download and install that first if it is not already installed. If you would like to compile stunnel with TCP wrappers support or install OpenSSL in a nonstandard location, you’ll probably want to make use of the --with-tcp-wrappers or --with-ssl command-line options for configure.

For example, the following command configures stunnel to include TCP wrapper support, using the OpenSSL installation under /opt:

$ ./configure --with-tcp-wrappers --with-ssl=/opt/openssl
            

After the script runs, run make to actually compile stunnel. You will then be prompted for information to create a self-signed certificate. This self-signed certificate will be valid for only one year. If this is not what you want, you should create your own certificate and Certificate Authority [Hack #69].

With the older 3.x versions of stunnel, it was possible to configure all options from the command line. The newer 4.x versions make use of a configuration file, stunnel.conf . A sample configuration file can usually be found in /etc/stunnel/stunnel.conf-sample or /usr/local/etc/stunnel/stunnel.conf-sample.

Let’s take a look at the basic form of a configuration file used to forward a local port to a remote port with stunnel.

Here’s the client side:

pid = 
client = yes

[<server port>]
accept = <forwarded port>
connect = <remote address>:<server port>

And here’s the server side:

cert = /etc/stunnel/stunnel.pem
pid = 
client = no

[<forwarded port>]
accept = <server port>
connect = <forwarded port>

You can use the default configuration file or choose another file. If you want to use the default configuration file, you can start stunnel without any arguments. Otherwise, specify the configuration file as the first argument to stunnel.

With the above setup, a program will be able to connect to <forwarded port> on the client side. Then stunnel will encrypt the traffic it receives on this port and send it to <server port> on the remote system specified by <remote address>. On the remote system, stunnel will decrypt the traffic that it receives on this port and forward it to the program that is listening on <forwarded port> on the remote system.

Here’s the format for the equivalent ssh port-forwarding command:

ssh -f -N -L <forwarded port>:<remote address>:<forwarded port> \
<remote address>

If you want to specify a process ID file, you can set the pid variable to whatever filename you wish. Leaving the pid variable in the configuration file without giving it a value causes stunnel to not create a PID file. However, if you leave out the pid variable completely, stunnel will try to create either /var/run/stunnel.pid or /usr/local/var/run/stunnel.pid (i.e., $prefix/var/run/stunnel.pid), depending on how you configured it at compile-time.

In addition to providing SSH-style port forwarding, stunnel can also be used to add SSL capabilities to inetd-style services that don’t have native SSL functionality, such as email or other services.

Here’s an inetd.conf entry for the Samba Web Administration Tool (SWAT):

swat stream tcp nowait.400 root /usr/local/samba/bin/swat swat

To add SSL support to SWAT, you first need to create a configuration file for stunnel to use. Call it swat.conf and put it in /etc/stunnel:

cert = /etc/stunnel/swat.pem
exec = /usr/local/samba/bin/swat 
execargs = swat

Modify the entry in inetd.conf to look like this:

swat stream tcp nowait.400 root /usr/sbin/stunnel stunnel \
  /etc/stunnel/swat.conf

Now, you can access SWAT securely with your favorite SSL-enabled web browser.

Alternatively, you can do away with inetd altogether and have stunnel listen for connections from clients and then spawn the service process itself. Create a configuration file with contents similar to these:

cert = /etc/stunnel/swat.pem

[swat]
accept = 901
exec = /usr/local/samba/bin/swat
execargs = swat

Then, start stunnel with the path to the configuration file:

# stunnel /etc/stunnel/swat.conf
            

In addition, you can start it at boot time by putting the previous command in your startup script (i.e., /etc/rc.local).

stunnel is a powerful tool: not only can it forward connections through an encrypted tunnel, but it can also be used to add SSL capabilities to common services. This is especially nice when clients with SSL support for these services already exist. In this case, you can use stunnel solely on the server side, enabling encryption for the service with no need for the client to install any extra software.