169 create_a_secure_virtual_private_network_with_openvpn 2007-11-28 23:19:00 2009-04-25 13:34:00 tools server security network internet debian vpn openvpn virtual private network With openvpn you can easy create a very secure virtual network. ///Table of Contents Goes Here/// # Introduction With `openvpn` you can easy create a virtual private network so that you can access this network from outside you own network. This will be ideal for laptops, when you travel and need to access you network. Sure you can access you hosts from anywhere with ssh, but this have some limitation and tunneling everything into this will give some pain. When setting up openvpn, you can choice about two different ways how the server will act. You can setup one client to one client. This will be ideal to create some bridge between two trusted network located at a different location. Or to setup a server who may receive different openvpn client connections. # Installation and setup At the time of writing this article, openvpn version `2.0.9-4etch1` is available on Etch and version `2.1~rc8-1` on Lenny. For the server and client side, the install and the questions during the install are the same. aptitude install openvpn During the install, you will be asked for If you accept here, the package will make a special device called /dev/net/tun for openvpn's use. If you refuse, the device won't be made now. Read README.Debian for details on how to make it. If you are using devfs refuse here. Would you like a TUN/TAP device to be created? Select `Yes`. Then you get the question: In some cases you may be upgrading openvpn in a remote server using a VPN to do so. The upgrade process stops the running daemon before installing the new version, in that case you may lose your connection, the upgrade may be interrupted, and you may not be able to reconnect to the remote host. Unless you do your upgrades locally, it is advised NOT to stop openvpn before it gets upgraded. The installation process will restart it once it's done. This option will take effect in your next upgrade. Would you like to stop openvpn before it gets upgraded? Select `No`. *Note that i don't got these questions when installing openvpn om my Debian Etch and Lenny box anymore! It seems that some things have changed. You can get the latest question with "dpkg-reconfigure openvpn".* ## One server, one client Creating the static.key file: cd /etc/openvpn openvpn --genkey --secret static.key Copy this file `static.key` to the clients in the directory `/etc/openvpn`. On server side, create a file `/etc/openvpn/tun0.conf` and add the following: dev tun0 ifconfig 10.9.8.1 10.9.8.2 secret static.key # Enable compression the VPN link # must be enabled on both sides comp-lzo # Verbosity level. # 0 -- quiet except for fatal errors. # 1 -- mostly quiet, but display non-fatal network errors. # 3 -- medium output, good for normal operation. # 9 -- verbose, good for troubleshooting verb 3 The client is another computer on another network. A computer on the other side of the world who has also an internet connection. On the client side create the file `/etc/openvpn/tun0.conf` and add the following: # The remote is the ip (or hostname) of the gateway remote 84.198.69.134 # set float if the gateway get's a dynamic IP float dev tun0 ifconfig 10.9.8.2 10.9.8.1 secret static.key # Enable compression the VPN link # must be enabled on both sides comp-lzo # Verbosity level. # 0 -- quiet except for fatal errors. # 1 -- mostly quiet, but display non-fatal network errors. # 3 -- medium output, good for normal operation. # 9 -- verbose, good for troubleshooting verb 3 The routing table needs to be adjusted so that all the data won't pass to our old default gateway but to the new gateway point. Issue the command `route` to see the routing table: This output Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 10.9.8.1 * 255.255.255.255 UH 0 0 0 tun0 localnet * 255.255.255.0 U 0 0 0 eth3 default moon.pinguin 0.0.0.0 UG 0 0 0 eth3 Remove the default (old) route: route del default Add the new route: route add default gw 10.9.8.1 See the modified routing table. Issue the command `route`: Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 10.9.8.1 * 255.255.255.255 UH 0 0 0 tun0 localnet * 255.255.255.0 U 0 0 0 eth3 default 10.9.8.1 0.0.0.0 UG 0 0 0 tun0 On the server side, the firewall needs to be adjusted aswell. For iptables use the following commands: iptables -A INPUT -i tun+ -j ACCEPT iptables -A INPUT -i $INTDEV -p UDP --dport 1194 -j ACCEPT If you want to be able to ping, you must allow iptable too: ## Set ICMP open to the internet tune0 $IPTABLES -A INPUT -i tun0 -p ICMP -j ACCEPT $IPTABLES -A OUTPUT -o tun0 -p ICMP -j ACCEPT # ICMP naar internet filteren $IPTABLES -A INPUT -i tune0 -p ICMP --icmp-type 0 -j ACCEPT $IPTABLES -A INPUT -i tune0 -p ICMP --icmp-type 3 -j ACCEPT $IPTABLES -A INPUT -i tune0 -p ICMP --icmp-type 5 -j ACCEPT $IPTABLES -A INPUT -i tune0 -p ICMP --icmp-type 11 -j ACCEPT Start openvpn on both side with the follow command: openvpn --config /etc/openvpn/tun0.conf ## One server, many clients (routed setup) We should first copy the key generator somewhere at a secure place. This will avoid to loose the config and keys if we later remove or upgrade the package: We first create the ca keys: mkdir /etc/openvpn_keys cp -r /usr/share/doc/openvpn/examples/easy-rsa /etc/openvpn/ cd /etc/openvpn/easy-rsa Edit the `vars` file. I changed the `KEY_SIZE` to `2048`, and some other stuff on the end of the file: export KEY_COUNTRY=BE export KEY_PROVINCE=Vlaams-Brabant export KEY_CITY=Halle export KEY_ORG="DVM@Home" export KEY_EMAIL="david.van.mosselbeen@gmail.com" Now let start the process: source ./vars ./clean-all ./build-ca *As we filled the vars file, some values should not be entered twice during the ./build-ca. Just the Organizational Unit Name (where i filled "IT"), Common Name (eg, your name or your server's hostname) []: dvm.zapto.org* We now create the certificates and keys: ./build-key-server server *Again as we did with the ./build-ca, just that you may fill in some cool challenge password. And had need to manually fill in the company name (DVM@Home).* Respond yes to sign the certificate and commit. We now need to create the keys for the clients: ./build-key myClient1Hostname ./build-key myClient2Hostname ... **Note that each client needs to have his own common name. So the CN for `client1` could `be client1.dvm.zapto.org`. For the clarity you can use the hostname of the concerned `client` in case of `client1`.** If later, you need to create an additional key for a client: cd /etc/openvpn/easy-rsa source ./vars ./build-key aNewClient *If you have created the client keys on name of the hostname, don't forget to adjust the above line.* Generate Diffie Hellman parameters: ./build-dh *Note that this command take a very long time, especially because of the length of the 2048 bit key. This took around 20 minutes on a P3 664MHz.* We should now copy some keys to some clients, here's the list with they usage: | **Filename** | **Needed By** | **Purpose** | **Secret** | | ca.crt | server + all clients | Root CA certificate | NO | | ca.key | key signing machine only | Root CA key | YES | | dh{n}.pem | server only | Diffie Hellman parameters | NO | | server.crt | server only | Server Certificate | NO | | server.key | server only | Server Key | YES | | client1.crt | client1 only | Client1 Certificate | NO | | client1.key | client1 only | Client1 Key | YES | | client2.crt | client2 only | Client2 Certificate | NO | | client2.key | client2 only | Client2 Key | YES | | client3.crt | client3 only | Client3 Certificate | NO | | client3.key | client3 only | Client3 Key | YES | On server side, copy the needed files from the keys directory where we have create the certifications `ca.crt, dh2048.pem, server.crt, server.key` to the directory `/etc/openvpn/`. On the client side, copy the needed files from the server where we have create the certifications files `ca.crt, client.conf. client1.crt, client1.key` to `/etc/openvpn/`. On server side, copy the default config file: zcat /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz \ > /etc/openvpn/server.conf On client side, copy the default config file: cp /usr/share/doc/openvpn/examples/sample-config-files/client.conf \ /etc/openvpn/ Adjust the config file on server and client side. On the client side i had need to add a line with as content `float`. Note that the firewall needs to be adjusted, like the many-clients to one server don't use the same network setup. *On server side, i took a copy of good working "client.conf", so that in the future, if a new client needs to have a VPN connection, i first create the client keys and provide a modified version of the client.conf from the server. As in the client.conf file we just need to change two lines referencing to the client keys.* # Testing if the vpn work You should now start the openvpn client on server side first: For both server and client, `cd` first to `/etc/openvpn/`. openvpn --config /etc/openvpn/server.conf And then on the client: openvpn --config /etc/openvpn/client.conf If you are running the `One server, one client`. You should be able to ping `10.9.8.2` from the server and `10.9.8.1` from the client. If you are running the `One server, many clients`. You should be able to ping `10.8.0.5` from the server and `10.8.0.1` from the client. # Firewalling Before everything works like expected, even a ping, the firewalls needs to be configured on server and client side so that it permit the `openvpn` and other traffic. ## vuurmuur I use [vuurmuur] (http://www.vuurmuur.org) to manage the iptables firewall on my gateway. Here's an overview of the `vuurmuur` config so that i'm able to surf on the web and do some other stuff. It's up to you to add or remove some more rules depending on your needs! ### Server side - One server, one client *Note that the following vuurmuur firewall config is for the one-client to one server setup on server side.* I use [vuurmuur] (http://www.vuurmuur.org) to manage the iptables firewall on my gateway. Here's an overview of the `vuurmuur` config so that i'm able to surf on the web. *Note that the following vuurmuur firewall config is for the one-client to one server setup.* I first created an interface called tun0b with ip `10.9.8.1`. Then a zone `ptp-vpn` with `local 10.9.8.0/255.255.255.0` as network within that zone. I added a host in this new `local.ptp-vpn` zone. I created a host in this network and specified the ip `10.9.8.2` for this host without a mac address. As rules i have set: | 61 ----------------------------[ Openvpn ]----------------------------- | | [x] 62 Accept openvpn local.ptp-vpn firewall(any) log,loglimit="| | [x] 63 Accept ping local.ptp-vpn firewall(any) log,loglimit="| | [x] 64 Accept http local.ptp-vpn world.inet log,loglimit="| | [x] 65 Accept ssh local.ptp-vpn world.inet log,loglimit="| | [x] 66 Snat any local.ptp-vpn world.inet - | | 67 -------------------------------------------------------------------- | *Note that you may disable the interface `tun0b` in vuurmuur if you have setup a `ptp-vpn` and `openvpn` zone in `vuurmuur`. As both zone's make use of the same `tun0` interface with a different ip. Otherwise `vuurmuur` will complain that the ip don't match the current interface.* ### Server side - One server, many clients *Note that the following vuurmuur firewall config is for the one server with many clients setup on server side.* I first created an interface called tun0b with ip `10.8.0.1`.Then a zone `openvpn` with `local 10.8.0.0/255.255.255.0` as network within that zone. I added a host in this new `local.ptp-vpn` zone. I created a host in this network and specified the ip `10.8.0.6` for this host without a mac address. | 71 ------------------[ one server multiples clients ]------------------ | | [x] 72 Accept openvpn any firewall(any) log,logprefix=| | [x] 73 Accept ping local.openvpn firewall(any) log,loglimit="| | 74 -------------------[ Access local lan from vpn ]-------------------- | | [x] 75 Accept ping local.openvpn local.lan log,loglimit="| | [x] 76 Accept ping local.openvpn world.inet log,loglimit="| | [x] 77 Accept http local.openvpn world.inet comment="Acces| | [x] 78 Accept https local.openvpn world.inet comment="Acces| | [x] 79 Accept http local.openvpn local.lan comment="Acces| | [x] 80 Accept ssh local.openvpn local.lan - | | [ ] 81 Accept ssh local.openvpn firewall(any) log,logprefix=| | [x] 82 Accept ldap local.openvpn local.lan - | | [x] 83 Accept imap local.openvpn local.lan - | | [x] 84 Accept imaps local.openvpn local.lan - | | [x] 85 Accept smtp local.openvpn local.lan - | | [x] 86 Accept portmap local.openvpn local.lan - | | [x] 87 Accept nfs local.openvpn local.lan - | | [x] 88 Accept rpc local.openvpn local.lan - | | [x] 89 Accept samba local.openvpn local.lan - | | [ ] 90 Accept any local.openvpn local.lan log,loglimit="| | [x] 91 Snat any local.openvpn world.inet - | | 92 ------[ Allow local.lan clients reach local.openvpn clients ]------- | | [x] 93 Accept ping local.lan local.openvpn log,loglimit="| | [x] 94 Accept ssh local.lan local.openvpn log,loglimit="| | [x] 95 Accept ident local.lan local.openvpn - | | 96 -------------------------------------------------------------------- | *Note that you may disable the interface `tun0b` in vuurmuur if you have setup a `ptp-vpn` and `openvpn` zone in `vuurmuur`. As both zone's make use of the same `tun0` interface with a different ip. Otherwise `vuurmuur` will complain that the ip don't match the current interface.* ### Client side On client side you may also use vuurmuur and setup it up to your needs. Vuurmuur is straightforward and isn't hard/complicated to use. Give some time to setup it correctly. Or just some little shell script that let **all** in and out. Trust me, this isn't secure at all!!! At all, why do you use a encrypted secured manner to connect to your LAN?? You are warned, use this at your own risk!!! Create a file called somethings like `unsecure_openvpn_firewall_script.sh` and put the following into it.: #!/bin/sh Then followed by and tune up to your needs!: # This script is especially made for use with openvpn. It open ALL and let # EVERYTHINGS in and out, use at your own risk!!! ### # IPTABLES="/sbin/iptables" TUN="tun0" INTDEV="wlan0" OPENVPNPORT=1194 PROTOCOL=UDP # Flush all previous rules $IPTABLES -F ## Open hole!! # Let everything in and out!!! #$IPTABLES -A INPUT -j ACCEPT #$IPTABLES -A OUTPUT -j ACCEPT #$IPTABLES -A FORWARD -j ACCEPT # Let some openvpn specifiq stuff pass $IPTABLES -A INPUT -i tun+ -j ACCEPT $IPTABLES -A OUTPUT -o tun+ -j ACCEPT $IPTABLES -A INPUT -i $INTDEV -p $PROTOCOL --dport $OPENVPNPORT -j ACCEPT $IPTABLES -A OUTPUT -p $PROTOCOL --dport $OPENVPNPORT -j ACCEPT # Permit ping ## Set ICMP open to the internet tune0 $IPTABLES -A INPUT -i $TUN -p ICMP -j ACCEPT $IPTABLES -A OUTPUT -o $TUN -p ICMP -j ACCEPT # ICMP naar internet filteren $IPTABLES -A INPUT -i $TUN -p ICMP --icmp-type 0 -j ACCEPT $IPTABLES -A INPUT -i $TUN -p ICMP --icmp-type 3 -j ACCEPT $IPTABLES -A INPUT -i $TUN -p ICMP --icmp-type 5 -j ACCEPT $IPTABLES -A INPUT -i $TUN -p ICMP --icmp-type 11 -j ACCEPT Or somethings more realist could be: #!/bin/bash NETDEV="wlan0" TUN="tun0" echo "1" > /proc/sys/net/ipv4/ip_forward iptables -P INPUT DROP iptables -P OUTPUT DROP iptables -P FORWARD DROP iptables -A INPUT -i $NETDEV -p tcp --dport 22 -j ACCEPT iptables -A INPUT -i $NETDEV -p udp --dport 1194 -j ACCEPT iptables -A INPUT -i $NETDEV -j DROP iptables -A OUTPUT -o $NETDEV -p tcp --sport 22 -j ACCEPT iptables -A OUTPUT -o $NETDEV -p udp --dport 1194 -j ACCEPT iptables -A OUTPUT -o $NETDEV -j DROP iptables -A INPUT -i $TUN -j ACCEPT iptables -A OUTPUT -o $TUN -j ACCEPT iptables -A FORWARD -i $TUN -j ACCEPT Set this file now as executable: chmod +x unsecure_openvpn_firewall_script.sh And now each time before you start your openvpn connection, start this script as root user first. You should execute somethings like `./unsecure_openvpn_firewall_script.sh`. See the firewall script provided with `openvpn` `/usr/share/doc/openvpn/examples/sample-config-files/firewall.sh` You can now start the openvpn connection manually with: openvpn --config /etc/openvpn/client.conf # Certificates revocation list At some point, you want to reject some certification. This could be because you know that a particular client certification got compromised. If you want to be able to reject some certification, you need to create a certification revocation list. As first thing to do, we need to specify in the openvpn server configuration to check revoked certificates from a particular file: echo " # Revoked certificate list crl-verify /etc/openvpn/keys/certification_revocation_list.pem" >> /etc/openvpn/server.conf We can now create an empty revocation file with: # First load (source) the needed config cd /etc/openvpn/easy-rsa source vars # Script isn't executable :-s chmod +x /etc/openvpn/easy-rsa/make-crl # Finally we create the revocation list /etc/openvpn/easy-rsa/make-crl /etc/openvpn/keys/certification_revocation_list.pem To revoke some certification: # First load (source) the needed config cd /etc/openvpn/easy-rsa source vars ./revoke-full client2 See for more informations. # Hardening the setup ## tls-auth man-in-the-middle-attack, also know as eavesdropping. On server side, in the directory where we created the keys: cd /etc/openvpn_keys/examples/easy-rsa/keys openvpn --genkey --secret ta.key cp ta.key /etc/openvpn Edit now the server.conf and uncomment the line `tls-auth ta.key 0`. Now on client side, copy in a secure maner (scp) the `ta.key` from the server to `/etc/openvpn/`. Edit now the client.conf and uncomment the line `tls-auth ta.key 1`. ## Other cipher With a default setup the Blowfish cipher is used. One server and client side, uncomment the line `cipher AES-128-CBC`. # Logging No default logging is setup, in fact all things are logged to the screen and not to a logfile. On server side define the line: log-append /var/log/openvpn/openvpn.log Now create this directory on the server: mkdir /var/log/openvpn.log chown root:adm /var/log/openvpn After having changed the server config file and restarted openvpn, you will discover that nothings is sent on screen anymore, so check the logs ;-) Some easy trick can be `tail -f /var/log/openvpn/openvpn.log`. You can now create a script for the log rotating. See the directory `/etc/logrotate.d/`. I created a file `/etc/logrotate.d/openvpn` and have fill this with: # logrotate for openvpn /var/log/openvpn/openvpn.log { rotate 999999 mail SomeUser@SomeMail.com mailfirst monthly compress delaycompress missingok notifempty postrotate /etc/init.d/openvpn restart > /dev/null endscript } The log file `/var/log/openvpn/openvpn.log` will be rotated monthly, before rotating, the content of the log will be mailed to `SomeUser@SomeMail.com`. `999999` rotates will be keept and all will be compressed. # Startup script `Openvpn` won't startup default, some few easy action is required. Before configuring the system to automatically startup `openvpn` at boot time. Be sure that the set is well been tested. You should first experiment and adjust all the wanted options before letting the system start `openvpn` at boot time. On server side, i adjusted the file `/etc/default/openvpn` and have commented the line `#AUTOSTART="none"` and set `AUTOSTART="server"`. On client side, i won't let `openvpn` startup at boot time, because the client is a laptop and it's possible that this laptop may be connected to some LAN's where the port `1194` is blocked by the firewall. Anyway if you want to let openvpn start at boot time, adjust the same lines as for the server, but replace the work `server` with `client`. # Tools * See the openvpn documentation about [GUI] (http://openvpn.net/index.php/documentation/graphical-user-interface.html) tools. * Openvpn for Pocket PC # Things left to do * Tweak the Bind9 DNS server so that we may be able to ping the clients connecting with the hostname. Actually no hostname lookup is possible. We need to ping the client on his ip. See also the `;push "dhcp-option DNS 10.8.0.1"`. * Load balancing. See `remote-random`. Should be two remote server at different locations? * Is `tls-server` and `tls-client` needed? * See for the options: `ipchange` (--ipchange /script-ip.sh), `float` (float should be set as we get the ip of the ISP, see DHCP). `shaper` throttles the outgoing data bandwidth, only works for outgoing traffic. `route-up` (--route-up /script.sh) - start script when route is up. `redirect-gateway` force all traffice to pass to the VPN?? * Max connections for a vpn server is 128? * See for `tls-server` and `tls-client`. # Config files * * /usr/share/doc/openvpn/examples/sample-config-files/ # Resources ## Books * Building and integrating virtual private netwoks. By Packt publishing. ISBN 1-904811-85-X. . First published on april 2006. ## On the web * * * * * [Why TCP Over TCP Is A Bad Idea] (http://sites.inka.de/~W1011/devel/tcp-tcp.html) * * * *