OpenVPN
Contents
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
- CA DEFAULT
- 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
SCRIPT
This is now on GitHub. Grab it there.
wget https://raw.githubusercontent.com/jamesorose/Fusion-Scripts/master/openvpngenconf.sh
This script will make it trivial to add clients, revoke certificates, rebuild clients, generate yealink openvpn.tar files, etc. Here's how it's run.
USAGE: openvpngenconf.sh build|revoke OPTIONS --------------------------------------------- build options: vpn_server_address client-name it's recommended to set client-name = phone_mac_address Build Example: 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 revoke options: client-name Revoke Example: openvpngenconf.sh revoke Client1 This will update the csr.pem file for the server and block the client from connecting. The old certificates will be moved out of the way so that you can re-generate them if you need to. Have a look in /var/centralconfig/openvpn/keys/revoked/
Manual Way
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
TODO
certificate revocationhopefully 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.