This requirement may be very simple to comply with if the only passwords we have to worry about were SSH passwords. SSH and Linux does exactly what is asked for, namely:
8.4 Render all passwords unreadable during transmission and storage on all system components using strong cryptography.
However, often life is not as simple.
Sometimes legacy applications which are essential to an environment’s operation don’t support the use of SSL and attempt to authenticate by sending plain text passwords.
How can we comply with this PCI requirement in these cases?
As always there are a few options.
Lets assume we have an application server (
APP_SRV1) which connects to a database server (
DB_SRV1) listening on port 5432, but it does this by sending a clear text password for the database to
We could create an SSH tunnel which the application would use to communicate with the database.
The rough process on
APP_SRV1 server would be as follows.
SSH key exchange:
ssh-keygen -t rsa ssh-copy-id db_user@DB_SRV1
Then create a tunnel:
ssh -L 5555:localhost:5432 db_user@DB_SRV1
(you must ensure the DB server would be listening on
The command is not immediately transparent as to what it’s doing. This says, create a local port listening on 5555, and use SSH to tunnel to
DB_SRV1. Once there, pass the traffic to
The traffic actually uses the standard SSH port of 22 between the two servers which you need to know for firewall purposes.
APP_SRV1 would send its request to
localhost:5555 instead of
DB_SRV1:5432. Then on
DB_SRV1, the request would emerge from the SSH
tunnel and be passed to
localhost:5432 where the database is
Since this would need to be a persistent connection, something like
authssh would need to
use used to monitor and maintain the tunnel in a matter similar to the
autossh -M 0 -f -q -N -o "ServerAliveInterval 10" -o "ServerAliveCountMax 3" -L 5555:localhost:5432 db_user@DB_SRV1
IPsec could also be used. The encrypted connection is designed to be persistent but it would encrypt all communication between 2 specific hosts which may be overkill depending on your configuration.
We found a good compromise between persistence and targeted encryption
This is quite similar in concept to SSH tunnelling but packaged in a more convenient way.
Stunnel will need to be installed on both the application server and the database server.
Installation is via the debian package:
apt-get install stunnel4
Stunnel Server Configuration
First we will configure the server side of connection which will listen
/etc/stunnel/stunnel.conf so it reads:
; Some debugging stuff useful for troubleshooting ;debug = 7 ;foreground = yes ;output = /var/log/stunnel4/stunnel.log pid = /var/run/stunnel4.pid [db_srv1] cert = /etc/ssl/certs/stunnel.cert key = /etc/ssl/private/stunnel.key options = NO_SSLv2 ciphers = ALL:!aNULL:!ADH:!eNULL:!LOW:!EXP:RC4+RSA:+HIGH:+MEDIUM accept = DB_SRV1:5433 connect = localhost:5432
This will listen on port 5433 on
DB_SRV1 and pass traffic onto the DB
which is listening locally on
ciphers lines ensure we do not use weak ciphers for encryption
(“Render all passwords unreadable during transmission [..] using
And to create the required certificate and key:
[david@debian:~]$ sudo openssl genrsa -out /etc/ssl/private/stunnel.key 2048 Generating RSA private key, 2048 bit long modulus .................................................................................+++ .+++ e is 65537 (0x10001) [david@debian:~]$ sudo openssl req -new -x509 -key /etc/ssl/private/stunnel.key -out /etc/ssl/certs/stunnel.cert -days 365 You are about to be asked to enter information that will be incorporated into your certificate request. ...snip... [david@debian:~]$ chmod 400 /etc/ssl/private/stunnel.key [david@debian:~]$ chmod 400 /etc/ssl/certs/stunnel.cert
We want this connection to restart if the server restarts so in
/etc/default/stunnel4 ensure the following is present:
Now we can restart stunnel and the connection will start listening:
Stunnel Client Configuration
And for the client side of the connection which will run on
we use the same process except using the following configuration in
; Some debugging stuff useful for troubleshooting ;debug = 7 ;foreground = yes ;output = /var/log/stunnel4/stunnel.log pid = /var/run/stunnel4.pid [db_srv1] cert = /etc/ssl/certs/stunnel.cert key = /etc/ssl/private/stunnel.key client = yes accept = localhost:5432 connect = DB_SRV1:5433
This configuration says stunnel will listen locally on
and will connect to
DB_SRV1:5433 as a client to pass on any connection
DB_SRV1:5433 of course is the server side of the stunnel
connection and everything sent over that connection will be encrypted.
Once you have configured the keys,
restarted, you configure your application to speak to
DB_SRV1:5432, and you now have encrypted communication
between the two points.
Although the configuration effort appears greater for stunnel than for SSH tunnels, once up and running, we found stunnel to be very robust and reliable.