Difference between revisions of "OpenVPN"

From FusionPBX
Jump to: navigation, search
(Created page with "=Take 2= This basis comes from MacKiller on #fusionpbx. He's provisioning this one per client (not per phone). I (soapee01) have made some enhancements that help automate this...")
(No difference)

Revision as of 19:53, 4 August 2020

Take 2

This basis comes from MacKiller on #fusionpbx. He's provisioning this one per client (not per phone). I (soapee01) have made some enhancements that help automate this, and improve security. My openvpn setup is a DISTINCT SERVER. I'm doing it this way so I can have several servers in differing geographic areas. In my case, I've got some bad routes from an ISP to my datacenter where Fusion lives, and I'm hoping to use OpenVPN to fix this. And also punch through NAT, improve security, etc.

Installation

These instructions are for Debian 9 (openvpn version 2.4.0) and are known to work with the following phones/firmware

  • Yealink W60B 77.83.0.85
  • Yealink SIP-T54W 96.85.0.24
  • Yealink SIP-T46S 66.84.0.90
  • Yealink SIP-T29G 46.83.0.126
  • Yealink SIP-T42S 66.85.0.5

Install Packages

Install openvpn

apt install -y openvpn easy-rsa

EasyRSA

Edit Vars

cd /usr/share/easy-rsa
vim vars

Change the following variables to match

export KEY_COUNTRY="US"
export KEY_PROVINCE="YourState (two letters, eg TX)"
export KEY_CITY="YourCity"
export KEY_ORG="Your Company"
export KEY_EMAIL="your@email.com"
export KEY_OU="phones"
#export KEY_SIZE=2048
export KEY_SIZE=1024
#export KEY_DIR="$EASY_RSA/keys"
export KEY_DIR="/var/centralconfig/openvpn/keys"

You'll need to symlink the openssl.cnf file. It's poorly documented.

ln -s openssl-1.0.0.cnf openssl.cnf

edit it.

vim openssl.cnf

We're going to change the certificate generation algorithm. This makes thinks less secure, but it is what yealink requires to work. The change needs to happen in two places

  1. CA DEFAULT
  2. REQ
#default_md     = sha256                # use public key default MD
default_md      = sha1                  # use public key default MD

Build the Server Certs

cd /usr/share/easy-rsa
source ./vars
./clean-all
./build-ca

Answer all of the questions

./build-key-server server

Answer all of the questions

./build-key phone1
./build-dh

Config OpenVPN Server

gunzip /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz
cp /usr/share/doc/openvpn/examples/sample-config-files/server.conf /var/centralconfig/openvpn/server.conf
nano /var/centralconfig/openvpn/server.conf

Here's what you need in the server

port YOUR_PORT_NUMBER
proto udp
dev ovpn
dev-type tun
ca /var/centralconfig/openvpn/keys/ca.crt
cert /var/centralconfig/openvpn/keys/server.crt
key /var/centralconfig/openvpn/keys/server.key 
dh /var/centralconfig/openvpn/keys/dh1024.pem
server 10.80.0.0 255.255.0.0
ifconfig-pool-persist ipp.txt
#the route below may be required if openvpn lives on your
#FS server, but if it does not, it registration will not
#happen.
#push "route YOUR_LISTENING_IP_FROM_FREESWITCH 255.255.255.255"
#MAKE THIS A FULL TUNNEL INSTEAD
push "redirect-gateway def1"
push "dhcp-option DNS 8.8.8.8"
client-to-client
duplicate-cn
keepalive 20 60
comp-lzo
status openvpn-status.log
verb 3
explicit-exit-notify 1
management localhost 7505
ln -s /var/centralconfig/openvpn/server.conf /etc/openvpn/server.conf
nano /etc/sysctl.conf

change the following

 net.ipv4.ip_forward=1

Now reboot

reboot

add the nat for openvpn

iptables -t nat -A POSTROUTING -s 10.80.0.0/16 -o eth0 -j MASQUERADE

Phone Configuration

mkdir -p /var/centralconfig/openvpn/client/blahclient/keys
cp /var/centralconfig/openvpn/keys/ca.crt /var/centralconfig/openvpn/client/blahclient/keys/
cp /var/centralconfig/openvpn/keys/blahclient.crt /var/centralconfig/openvpn/client/blahclient/keys/
cp /var/centralconfig/openvpn/keys/blahclient.key /var/centralconfig/openvpn/client/blahclient/keys/
cp /usr/share/doc/openvpn/examples/sample-config-files/client.conf /var/centralconfig/openvpn/client/blahclient/vpn.cnf
nano /var/centralconfig/openvpn/client/blahclient/vpn.cnf

Then add this to the file

client
dev tun
dev-type tun
proto udp
remote YOUR_DNS_NAME_FOR_OPENVPN_SERVER YOUR_PORT_NUMBER
setenv SERVER_Poll_TIMEOUT 4
resolv-retry infinite
nobind
persist-key
persist-tun
ca /config/openvpn/keys/ca.crt
cert /config/openvpn/keys/masterclient.crt
key /config/openvpn/keys/masterclient.key
remote-cert-tls server
comp-lzo
verb 3

Build the tar file

 tar -cvpf openvpn.tar *

Static IP for Mgmt

Config

Basically we want to block all communication between the phones for security. By default, this is not true! We need to create a vpn client for management (eg for a windows box), and then set up some static IPs for that so we can firewall everything off.

Server Conf Changes

We MUST make some change to the server config. Mainly:

  • disable client-to-client
    • This will allow us to use iptables to decide who gets to talk to each other
  • Change the server directives

In the above configuration we'll comment out:

server 10.80.0.0 255.255.0.0

and replace it with:

mode server
tls-server
ifconfig 10.80.0.1 10.80.0.2
ifconfig-pool 10.80.0.3 10.80.254.252
route 10.80.0.0 255.255.255.0
push "route 10.80.0.1"

We're now left with a server configuration that looks like this:

port 1194
proto udp
dev ovpn
dev-type tun
ca /var/centralconfig/openvpn/keys/ca.crt
cert /var/centralconfig/openvpn/keys/server.crt
key /var/centralconfig/openvpn/keys/server.key
dh /var/centralconfig/openvpn/keys/dh1024.pem
#server 10.80.0.0 255.255.0.0

mode server
tls-server
ifconfig 10.80.0.1 10.80.0.2
ifconfig-pool 10.80.0.3 10.80.254.252
route 10.80.0.0 255.255.255.0
push "route 10.80.0.1"

ifconfig-pool-persist ipp.txt
client-config-dir /etc/openvpn/ccd
#the route below may be required if openvpn lives on your
#FS server, but if it does not, it registration will not
#happen.
#push "route server_ip 255.255.255.255"
push "redirect-gateway def1"
push "dhcp-option DNS 8.8.8.8"
#client-to-client
duplicate-cn
keepalive 20 60
comp-lzo
status openvpn-status.log
verb 3
explicit-exit-notify 1
management localhost 7505

OpenVPN Client Static IP

mkdir /etc/openvpn/ccd

echo "ifconfig-push 10.80.0.3 10.80.0.2" > /etc/openvpn/ccd/JamesTest

This doesn't work in windows. We get the following error:

There is a problem in your selection of --ifconfig endpoints [local=10.80.0.3, remote=10.80.0.2]. The local and remote VPN endpoints cannot use the first or last address within a given 255.255.255.252 subnet. This is a limitation of --dev tun when used with the TAP-WIN32 driver. Try 'openvpn --show-valid-subnets' option for more info. Exiting due to fatal error

So it's time for some subnet calculations. :-/


We've used the range: 10.80.0.0/16 for OpenVPN. However, we we'll have to divide this up into 252 subnets. This means 2 addresses (IP and gateway). The first usable would be: Gateway IP 10.80.0.1 10.80.0.2 10.80.0.3 10.80.0.5 10.80.0.7 10.80.0.9 10.80.0.10

so let's change the rule to: echo "ifconfig-push 10.80.0.9 10.80.0.10" > /etc/openvpn/ccd/JamesTest


Now from windows we can see the following (and it connects):

Ifconfig

Ethernet adapter Ethernet 2:

   Connection-specific DNS Suffix  . :
   IPv4 Address. . . . . . . . . . . : 10.80.0.9
   Subnet Mask . . . . . . . . . . . : 255.255.255.252
   Default Gateway . . . . . . . . . :

Route print

IPv4 Route Table
===========================================================================
Active Routes:
Network Destination        Netmask          Gateway       Interface  Metric
          0.0.0.0          0.0.0.0     192.168.1.1     192.168.1.102     25
          0.0.0.0        128.0.0.0       10.80.0.10        10.80.0.9    291
        10.80.0.1  255.255.255.255       10.80.0.10        10.80.0.9    291
        10.80.0.8  255.255.255.252         On-link         10.80.0.9    291
        10.80.0.9  255.255.255.255         On-link         10.80.0.9    291
       10.80.0.11  255.255.255.255         On-link         10.80.0.9    291
        127.0.0.0        255.0.0.0         On-link         127.0.0.1    331

Notice that our IP (10.80.0.9) will now be static and routed via 10.80.0.10

Firewall

Now currently our firewall is permissive. All VPN clients can connect to each other. Let's fix that.

Here's the command you'll need to see the NAT rules

iptables -t nat -L


Block Client <-> Client Comm

iptables -I FORWARD --src 10.80.0.0/16 --dst 10.80.0.0/16 -j DROP

Allow Managemnt IP Comm

We have to go both ways here....

iptables -I FORWARD --src 10.80.0.9/16 --dst 10.80.0.0/16 -j ACCEPT
iptables -I FORWARD --src 10.80.0.0/16 --dst 10.80.0.9 -j ACCEPT

Apache

Now we'd like to get those config files...

apt install apache2

htaccess

add the following stanza after the last Directory tags to:

vim /etc/apache2/apache2.conf
#ADD for HTACCESS
<Directory /var/www/>
        Options FollowSymlinks
        AllowOverride All
</Directory>
systemctl restart apache2

Turn on Directory Listings

Set your config to look like this

vim /etc/apache2/sites-enabled/000-default

here's the config

<VirtualHost *:80>
        # The ServerName directive sets the request scheme, hostname and port that
        # the server uses to identify itself. This is used when creating
        # redirection URLs. In the context of virtual hosts, the ServerName
        # specifies what hostname must appear in the request's Host: header to
        # match this virtual host. For the default virtual host (this file) this
        # value is not decisive as it is used as a last resort host regardless.
        # However, you must set it for any further virtual host explicitly.
        #ServerName www.example.com

        ServerAdmin webmaster@localhost
        DocumentRoot /var/www
       <Directory /var/www/>
                Options Indexes FollowSymLinks MultiViews
                AllowOverride AuthConfig
                Order allow,deny
                allow from all
        </Directory>

        # Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
        # error, crit, alert, emerg.
        # It is also possible to configure the loglevel for particular
        # modules, e.g.
        #LogLevel info ssl:warn

        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined

        # For most configuration files from conf-available/, which are
        # enabled or disabled at a global level, it is possible to
        # include a line for only one particular virtual host. For example the
        # following line enables the CGI configuration for this host only
        # after it has been globally disabled with "a2disconf".
        #Include conf-available/serve-cgi-bin.conf
</VirtualHost>

Protect the files

Add the htaccess file

vim /var/www/.htaccess
AuthName "Restricted Area"
AuthType Basic
AuthUserFile /etc/apache2/users
require user FusionPBX

Create the password for apache

htpasswd -c /etc/apache2/users FusionPBX

Link the files so we can grab them easily.

cd /var/www
ln -s /var/centralconfig/openvpn/client ./

restart apache2

systemctl restart apache2

Adding Clients

What follows below is a script I wrote to make it easier to add clients. You call it as such:

openvpngenconf.sh
     USAGE: openvpngenconf.sh build vpn_server_address client-name
       it's recommended to set client-name = phone_mac_address

         openvpngenconf.sh build vpn.example.com 805ab09d345f
         yields a config file for yealink named /var/centralconfig/openvpn/client/805ab09d345f/openvpn.tar
                        AND
         yields a config file with certs inline named /var/centralconfig/openvpn/client/805ab09d345f/vpn.example.com-805ab09d345f.ovpn

You DON'T HAVE TO USE A MAC ADDRESS But if you want things to provision easier later, it's better to do so. Yealink CAN grab configurations via http[s] and we need some way to differentiate. Using the MAC makes sense. I also hope to automate this by grabbing entries from the FusionPBX database and calling this script.

For desktop access, you'll Want to call it like

openvpngenconf.sh build vpn_server_address My_Desktop_Name

Script

#!/bin/bash
#openvpngenconf.sh


#------------------------------------------------------------------------------
#
# "THE WAF LICENSE" (version 1)
# This is the Wife Acceptance Factor (WAF) License.
# jamesdotfsatstubbornrosesd0tcom  wrote this file.  As long as you retain this
# notice you can do whatever you want with it. If you appreciate the work,
# please consider purchasing something from my wife's wishlist. That pays
# bigger dividends to this coder than anything else I can think of ;).  It also
# keeps her happy while she's being ignored; so I can work on this stuff.
#   James Rose
#
# latest wishlist: http://www.stubbornroses.com/waf.html
#
# Credit: Based off of the BEER-WARE LICENSE (REVISION 42) by Poul-Henning Kamp
#
#------------------------------------------------------------------------------

BuildDir="/var/centralconfig/openvpn"
TmpDir="/tmp/buildvpn/$3"

buildconf() {

mkdir -p $TmpDir

cd /usr/share/easy-rsa
source ./vars
./build-key $3
#./build-dh

cd $BuildDir
mkdir -p client/$3/keys
cp $BuildDir/keys/ca.crt $BuildDir/client/$3/keys/
cp $BuildDir/keys/$3.crt $BuildDir/client/$3/keys/client.crt
cp $BuildDir/keys/$3.key $BuildDir/client/$3/keys/client.key

cat > $BuildDir/client/$3/vpn.cnf <<DELIM
client
dev tun
dev-type tun
proto udp
remote $2 1194
setenv SERVER_Poll_TIMEOUT 4
resolv-retry infinite
nobind
persist-key
persist-tun
remote-cert-tls server
comp-lzo
verb 3
DELIM



	
#build inline certificate	
		cp $BuildDir/client/$3/vpn.cnf $TmpDir/"$2"-"$3".ovpn

		echo "<ca>" >> $TmpDir/"$2"-"$3".ovpn
		cat ./keys/ca.crt >> $TmpDir/"$2"-"$3".ovpn
		echo "</ca>" >> $TmpDir/"$2"-"$3".ovpn
		
		echo "<cert>" >> $TmpDir/"$2"-"$3".ovpn
		cat ./keys/$3.crt >> $TmpDir/"$2"-"$3".ovpn
		echo "</cert>" >> $TmpDir/"$2"-"$3".ovpn
		
		echo "<key>" >> $TmpDir/"$2"-"$3".ovpn
		cat ./keys/$3.key >> $TmpDir/"$2"-"$3".ovpn
		echo "</key>" >> $TmpDir/"$2"-"$3".ovpn
		
		todos $TmpDir/$2-$3.ovpn



#build yealink zip
	echo "ca /config/openvpn/keys/ca.crt" >> $BuildDir/client/$3/vpn.cnf
	echo "ca /config/openvpn/keys/client.crt" >> $BuildDir/client/$3/vpn.cnf
	echo "ca /config/openvpn/keys/client.key" >> $BuildDir/client/$3/vpn.cnf

	cd $BuildDir/client/$3

	tar -cvpf openvpn.tar *

	mv $TmpDir/$2-$3.ovpn $BuildDir/client/$3/

	rmdir -r $TmpDir

	echo "DONE"
	echo " filename is: $BuildDir/client/$3/$2-$3.ovpn"
	echo "              $BuildDir/client/$3/openvpn.tar"
	
}

echo $1
echo $2
echo $3
case $1 in 
	build)
		buildconf $1 $2 $3
	;;

	*)
		echo; echo
		echo "     USAGE: openvpngenconf.sh build vpn_server_address client-name"
		echo "       it's recommended to set client-name = phone_mac_address"
		echo
		echo "         openvpngenconf.sh build vpn.example.com 805ab09d345f"
		echo "         yields a config file for yealink named $BuildDir/client/805ab09d345f/openvpn.tar"
		echo "                        AND"
		echo "         yields a config file with certs inline named $BuildDir/client/805ab09d345f/vpn.example.com-805ab09d345f.ovpn"
		echo; echo
	;;
esac

TODO

  • certificate revocation
    • hopefully without restarting openvpn.
  • Figure out why I have to manually start openvpn with:
    • openvpn --config /etc/openvpn/server.conf