OpenVPN

From FusionPBX
Revision as of 19:18, 5 August 2020 by Soapee01 (talk | contribs) (TODO)
Jump to: navigation, search

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

Working Phones

  • 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
  • Yealink SIP-T46G
    • 28.83.0.120
    • 28.73.0.50

Phones with Issues

  • put a list here...

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"
#you might want to use the DNS provider for your domain names instead of google for faster changes
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

This is now on GitHub. Grab it there.

wget https://raw.githubusercontent.com/jamesorose/Fusion-Scripts/master/openvpngenconf.sh

TODO

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

Add a Second Server

This is pretty simple. We can set this up so that certificates and revocations are shared across multiple servers. This has a benefit of letting us reconfigure a server address for a phone, and having them automatically move to another server. We could also use this to set up a round robin based set of servers (connect randomly to servers listed in the client config) for load balancing, and provide failover for openvpn in case one of them goes down.

The procedure

apt install openvpn easy-rsa rsync

Rsync

rsync some files over

from your main server copy ssh keys so we can get passwordless logins

primary_server# ssh-keygen
primary_server# ssh-copy-id root@secondary_server

now let's rsync some files

primary_server# rsync -avp --progress /usr/share/easy-rsa/ root@secondary_server:/usr/share/easy-rsa
primary_server# rsync -avp --progress /var/centralconfig/openvpn/ root@secondary_server:/var/centralconfig/openvpn
primary_server# rsync -avp --progress /etc/openvpn/ root@secondary_server:/etc/openvpn

Change Network

nano /etc/sysctl.conf change the following net.ipv4.ip_forward=1

or you can try this sed one liner...

secondary_server# sed -i -e s/\#net.ipv4.ip_forward=1/net.ipv4.ip_forward=1/g /etc/sysctl.conf

then reboot

secondary_server# reboot

Iptables

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

Add your rules for your management IP

iptables -I FORWARD --src 10.80.0.0/16 --dst 10.80.0.0/16 -j DROP
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

Finishing up

On a PC, change the openvpn client config server url to your new address. You should be able to connect.