Friday, July 24, 2009

Windows SSL for PostgreSQL

I had to do this for work, so I see no reason not to share it with the world at large.
Setting up SSL for PostgreSQL on Windows servers:

In order for this to work, you need the following installed on the machine with PostgreSQL:
1. PostgreSQL 8.3 (it was not tested with earlier versions, and as of today I couldn't get it to work on PostgreSQL 8.4)
2. Cygwin, with the following extra features checked at install time: openssl, Gnu Make (possibly labeled ‘make’ in the Cygwin installer), and a Cygwin text editor. "joe" and "nano" are easy for Unix/Cygwin newbies, though "vim" and "emacs" are available for veterans.


Certificate Creation (on the PostgreSQL server):
(Every command that should be executed at a command prompt or Cygwin prompt will be
written with # in front)
1. Open a Cygwin command prompt (henceforth called ‘Cygwin shell’) and make a directory for creating the certificates, and move in to that directory
#mkdir ssl
#cd ssl
2. Copy the files ‘Makefile’ and ‘openssl.cnf’ from this page: http://sial.org/howto/openssl/ca/
Then edit the openssl.conf with
#nano openssl.cnf
OR
#joe openssl.cnf
OR
whatever other editor you want
NOTE: You can modify the file in any text editor you want PROVIDED it saves the results with Unix line endings ONLY. You can’t use, for example, Notepad or Wordpad because it will insert the “Carriage Return” invisible character at the end of each line, and then many Cygwin tools will crash trying to read the file.
4. In the text editor you launched, scroll down the file to find the section with the heading
“[ root_ca_distinguished_name ]”
And set the values in it to whatever you think is appropriate. You don’t need to modify anything else in the file, though you may wish to change default_bits to 2048. When you’re finished, save the file and exit.
5. In the Cygwin shell in the ssl folder we will now create our public and private certificate. Run:
make init
6. The command above should spit out some quick information about what it’s doing. When that’s finished, our public certificate is in PEM format in ca-cert.pem, and our private key to the certificate will be in the folder named ‘private’ with the name ca-key.pem. We want to verify the output. In the Cygwin shell run
#openssl x509 -text -in ca-cert.pem
The bottom of the output should be a bunch of funky characters, but near the top it should have a section listing all of the data you entered in the [ root_ca_distinguished_name ] section of the openssl.cnf file.
If there is a problem and the wrong data is included, exit Cygwin, open Windows Explorer to the ssl directory you created in step 1, delete the directory, and then start over at Step 1.
7. Now we must transmit the public certificate from PEM to DER format (No, I have no clue what DER means either, but that’s the format that PostgreSQL wants). Run the following command in the Cygwin shell:
#openssl x509 -outform der -in ca-cert.pem -out root.crt
Now there is a file root.crt with the root certificate we created. You can do
#ls root.crt
To verify that the file was created.
8. Open a separate Windows Command Prompt (cmd.exe) and run the command
#ping –a localhost
The result of the ping should include the name of the server you are on. For example, on this workstation the result is oscar.network3.somecompany.com
Note that value.
NOTE: If the server you are using always has the same IP address, you may instead use the IP address. Note, however, that if you change the server IP address in the future without creating a new certificate, connections will stop working!
9. Now we are going to generate our PostgreSQL server SSL certificate. In the Cygwin shell, do:
#openssl req -newkey rsa:2048 -days 1000 -text -out server.req
You will be asked a series of questions about settings. Only three are important. For the keystore PEM pass phrase, use “changeit”. For the Common Name value, enter the host name result you got from the ping –a localhost command above. For the challenge password, just hit Enter to leave it blank.
Note: I’m not certain that the ‘-days 1000’ parameter above is necessary…
10. After the step above, the public and private key are created. However, we do not want PostgreSQL to prompt for the password to them each time it is started. So run the following two commands in the Cygwin shell:
#openssl rsa -in privkey.pem -out server.key
(You will be prompted to enter the “changeit” password.)
#rm privkey.pem
11. Now we want to digitally sign our server certificate using the root certificate we created earlier for 1000 days (or substitute whatever number you want). In Cygwin shell do:
#openssl req -x509 -in server.req -text -days 1000 -key private/ca-key.pem -out server.crt
12. The files are created, now the permissions must be set. To do this easily, we will create a special subdirectory and put the files there, and then change permissions and owners in that directory.
Note: The last line below assumes the PostgreSQL database is run under user account ‘postgres’. If it runs under a different account, substitute the name of that account instead.
#mkdir postgres_certs
#cp root.crt postgres_certs
#cp server.key postgres_certs
#cp server.crt postgres_certs
#cd postgres_certs
#chmod 600 *
#chown postgres *
13. Open Windows Explorer to C:\cygwin\home\(whatever user you are)\ssl\postgres_certs and copy the 3 files there to the PostgreSQL data directory, on my machine it's
F:\Program Files\PostgreSQL\8.3\data .


PostgreSQL configuration
14. In order for all of this to work, you must have done the steps to create a certificate on the server and put the certificate in the proper location.
15. On the server with PostgreSQL, a System environmental variable with the location of the openssl.cnf file must be created. This must not point to the openssl.cnf file used in Certificate Creation. The normal location of the Cygwin openssl.cnf value we want to use is
C:\cygwin\usr\ssl\openssl.cnf, so in the “System” control panel
“Advanced -> Environmental Variables” setting, create a new System Environmental Variable OPENSSL_CONF with the value C:\cygwin\usr\ssl\openssl.cnf
16. In the PostgreSQL configuration file postgresql.conf change the ssl settings to “ssl=on” and “ssl_ciphers= ALL “
17. In the PostgreSQL configuration file pg_hba.conf change all of the entries from “host” to “hostssl”
18. Re-start the PostgreSQL service. If it does not start, check the Windows Event Viewer for errors.
19. Open pgAdmin3 and create an SSL connection to the server. Try to connect, and verify it works.
20. In any other machine configured to connect to the server, in pgAdmin3 create an SSL connection and verify it works.
21. If you try the PostgreSQL command-line tool “psql” for a connection to the database, it should connect automatically and give a message that an SSL connection was established.

NOTE 1: All this gives you SSL with self-signed certificates. To connect with, for example, JDBC and PostgreSQL (which is what we use), you would need to have a fairly recent JDBC driver and make your connection URL;
jdbc:postgresql://hostname:5432/databasename?ssl=true&sslfactory=org.postgresql.ssl.SSLNonValidatingFactory
(If you're writing in XML files, the '&' must be written as '&')

NOTE 2: If you want to use certificates signed by a recognized Certificate Authority, you'll
do steps 9 and 10 above, submit the resulting server.req to a Certificate Authority for them to make the server.crt, and then use your server.key, their server.crt, and their root.crt and continue from step 12. At least, I think that's what you'll do. I haven't done it.

Thursday, July 9, 2009

VPN disconnects on Debian Linux "Lenny"

I use VPN to work from home. My office workstation runs Windows Vista Professional (alas!) but I prefer to work in Linux.

I have Debian "Lenny" running at home, and I did apt-get install rdesktop pptpclient (as root) to get the programs I need.

I followed the directions at http://pptpclient.sourceforge.net/howto-debian.phtml#configure_by_hand
I called the connection "work".
I also followed the directions at http://pptpclient.sourceforge.net/routing.phtml#client-to-lan
and added a file called "work" in the /etc/ppp/ip-up.d/ directory, with the contents of the file (copied from the client-to-lan page copied and modified):
#!/bin/sh
if [ "${PPP_IPPARAM}" = "work" ]; then
/sbin/route add -net 192.168.10.0/24 dev ${IFNAME}

/sbin/iptables --insert OUTPUT 1 \
--source 0.0.0.0/0.0.0.0 \
--destination 192.168.10.0/24 \
--jump ACCEPT --out-interface ${IFNAME}

/sbin/iptables --insert INPUT 1 \
--source 192.168.10.0/24 \
--destination 0.0.0.0/0.0.0.0 \
--jump ACCEPT --in-interface ${IFNAME}

/sbin/iptables --insert FORWARD 1 \
--source 0.0.0.0/0.0.0.0 \
--destination 192.168.10.0/24 \
--jump ACCEPT --out-interface ${IFNAME}

/sbin/iptables --insert FORWARD 1 \
--source 192.168.10.0/24 \
--destination 0.0.0.0/0.0.0.0 --jump ACCEPT

/sbin/iptables --table nat --append POSTROUTING \
--out-interface ${IFNAME} --jump MASQUERADE

/sbin/iptables --append FORWARD --protocol tcp --tcp-flags SYN,RST SYN \
--jump TCPMSS --clamp-mss-to-pmtu
fi

To run it, I open a terminal as root and do:
pon work
Wait a few seconds, do ifconfig and make sure "ppp0" is listed as a connection, then
/etc/ppp/ip-up.d/work to route the network traffic appropriately.
Then in my menu Applications -> Internet -> Remotedesktop Client I opened a connection to my machine.

I ran into two problems. First, the /etc/ppp/ip-up.d/work file didn't seem to run, so I took the if and fi out. That fixed that, and I could ping and connect to machines at work.
Second, my connection would drop a few times an hour. I read around the pptp client site until I saw a suggestion to drop the MTU (which I learned means "maximum transmission unit", or maximum packet size) to 1400. So I inserted a new second line to the file above,
/sbin/ifconfig ppp0 mtu 1400

After that, everything worked fine. Next, I'm going to work on making DNS operate across the VPN. For right now, I cheat and log in to servers at work with fixed IP addresses, and then use pings from those machines to locate any DHCP machine I can't find.