Skip to content

Instantly share code, notes, and snippets.

@dyerseve
Forked from jcconnell/USG_OpenVPN_Radius_Auth.md
Last active October 4, 2021 20:10
Show Gist options
  • Save dyerseve/00b39fa56424465f96b3e0a75687eb12 to your computer and use it in GitHub Desktop.
Save dyerseve/00b39fa56424465f96b3e0a75687eb12 to your computer and use it in GitHub Desktop.
Unifi Security Gateway (USG) OpenVPN server with RADIUS authentication

OpenVPN on UniFi USG Instructions for FIT

Last Updated: 2021/01/19

Fork Notes

Forked this to provide better details for our environment, you should be able to copy paste most of the commands from the command blocks

Details

I wanted to run an OpenVPN server on the USG. Since it has a Radius server built in, I figured this would be a much better way to handle OpenVPN authentication. Make sure you have the Radius server enabled on your USG under Settings > Services > Radius > Server in the controller. Add OpenVpn users under Settings > Services > Radius > Server.

Thanks to the following resources in helping to configure this:

Reboot device first

To ensure the system is running at top performance for the key generation, give it a reboot before you start the process

Configure easy-rsa and generate keys

SSH into your USG and run the following commands (updated url on 2020/05/01)

sudo bash
curl -O http://ftp.us.debian.org/debian/pool/main/e/easy-rsa/easy-rsa_2.2.2-1_all.deb
sudo dpkg -i easy-rsa_2.2.2-1_all.deb

If curl fails, browse to that folder on ftp and see what the filename is, confirmed working with "2.2.2-1"

Generate keys on PC instead of USG

You can take a shortcut to Configure OpenVPN on USG if you generate the keys on your PC, I actually recommend this as it will save you half an hour to an hour versus key generation on the USG itself.

Download the script here

The zip password is in LP under USG OpenVPN Key Generator Zip Password

Extract to a short path with no spaces and then run !FITRUNME.bat

This will generate a keys folder (it will overwrite previous keys), then just copy these keys into /config/auth/keys/ on the USG

Once the files have been copied, you can now skip to Configure OpenVPN on USG step

Generate Keys on USG (skip if you did the PC key generation)

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

All defaults straight down is fine Make sure to set the password, but it won't be necessary to take note of it.

./build-key-server server

Set the common name to “server” (which is again all defaults straight down) Answer yes to signing the certificate and commiting it. This process runs for a very long time (30 to 60 minutes on a USG Pro)

./build-dh

Copy the generated keys (skip if you did the PC key generation)

mkdir /config/auth/keys/
cp keys/* /config/auth/keys/

Configure OpenVPN on the USG

configure
set interfaces openvpn vtun0 mode server

Make sure to use a subnet not in use anywhere else on your USG, 10.72.1.0/24 is fine as a standard option

set interfaces openvpn vtun0 server subnet 10.72.1.0/24
set interfaces openvpn vtun0 tls ca-cert-file /config/auth/keys/ca.crt
set interfaces openvpn vtun0 tls cert-file /config/auth/keys/server.crt
set interfaces openvpn vtun0 tls key-file /config/auth/keys/server.key
set interfaces openvpn vtun0 tls dh-file /config/auth/keys/dh2048.pem
set interfaces openvpn vtun0 encryption aes128
set interfaces openvpn vtun0 openvpn-option "--keepalive 8 30"
set interfaces openvpn vtun0 openvpn-option "--comp-lzo"
set interfaces openvpn vtun0 openvpn-option "--duplicate-cn"
set interfaces openvpn vtun0 openvpn-option "--user nobody --group nogroup"
set interfaces openvpn vtun0 openvpn-option "--plugin /usr/lib/openvpn/openvpn-auth-pam.so openvpn"
set interfaces openvpn vtun0 openvpn-option "--client-cert-not-required --username-as-common-name"
set interfaces openvpn vtun0 openvpn-option "--verb 1"
set interfaces openvpn vtun0 openvpn-option "--proto udp6"
set interfaces openvpn vtun0 openvpn-option "--port 1194"
set interfaces openvpn vtun0 openvpn-option "--push redirect-gateway def1"
set interfaces openvpn vtun0 openvpn-option "--push dhcp-option DNS 8.8.8.8"
set interfaces openvpn vtun0 openvpn-option "--push dhcp-option DNS 8.8.4.4"

Configure the firewall

set firewall name WAN_LOCAL rule 20 action accept
set firewall name WAN_LOCAL rule 20 description "Allow OpenVPN clients in"
set firewall name WAN_LOCAL rule 20 destination port 1194
set firewall name WAN_LOCAL rule 20 log disable
set firewall name WAN_LOCAL rule 20 protocol udp

Configure the firewall for IPv6

set firewall ipv6-name wan_local-6 rule 20 action accept
set firewall ipv6-name wan_local-6 rule 20 description "Allow OpenVPN clients in"
set firewall ipv6-name wan_local-6 rule 20 destination port 1194
set firewall ipv6-name wan_local-6 rule 20 log disable
set firewall ipv6-name wan_local-6 rule 20 protocol udp

Forward traffic to the internet

set service nat rule 5010 description "Masquerade for WAN"
set service nat rule 5010 outbound-interface eth0
set service nat rule 5010 type masquerade

commit
save
exit

If you need to check the configuration to make sure the changes are still there after a reboot or force provision, etc, just type:

show configuration

Place the certificate in your clipboard

cat /config/auth/keys/ca.crt

Now right click the putty title bar and choose copy all to clipboard, put it in notepad++ and remove all but the certificate output between -----BEGIN CERTIFICATE----- and -----END CERTIFICATE-----

Create a .ovpn file

Give this to your clients for connection. Make sure to change the relevant details, two spots below The contents of this file should be saved to LP as Secure Note "ClientName OVPN File"

client
float
dev tun

# Replace my.hostname.com in the line below to the DDNS, FQDN or static IP, maintain the "remote at the beginning of the line
remote my.hostname.com 1194 udp

resolv-retry infinite
nobind
persist-key
persist-tun
auth-user-pass
cipher AES-128-CBC
comp-lzo
verb 3
<ca>
 -----BEGIN CERTIFICATE----- 
# put your certificate block here. Copy it from your /config/auth/keys/ca.crt file on your USG
# Paste it in from your clipboard which we did earlier.
-----END CERTIFICATE----- 
</ca> 

# this is an random certificate. The .ovpn file needs one, but doesn't use it, so you can leave this as is
<cert> 
-----BEGIN CERTIFICATE-----
MIIB1jCCAT+gAwIBAgIEAmLSTjANBgkqhkiG9w0BAQUFADAVMRMwEQYDVQQDEwpP
cGVuVlBOIENBMB4XDTEzMDExNzAyMTExMloXDTIzMDEyMjAyMTExMlowKDEmMCQG
A1UEAxQdZnJyaWN0aW9uQGdtYWlsLmNvbV9BVVRPTE9HSU4wgZ8wDQYJKoZIhvcN
AQEBBQADgY0AMIGJAoGBALVEXIZYYu1Inmejuo4Si6Eo5AguTX5sg1pGbLkJSTR4
BXQsy6ocUnZ9py8htYkipkUUhjY7zDu+wJlUtWnVCwCYtewYfEc/+azH7+7eU6ue
T2K2IKdik1KWhdtNbaNphVvSlgdyKiuZDTCedptgWyiL50N7FMcUUMjjXYh/hftB
AgMBAAGjIDAeMAkGA1UdEwQCMAAwEQYJYIZIAYb4QgEBBAQDAgeAMA0GCSqGSIb3
DQEBBQUAA4GBABhVzSYXHlQEPNaKGmx9hMwwnNKcHgD9cCmC9lX/KR2Y+vT/QGxK
7sYlJInb/xmpa5TUQYc1nzDs9JBps1mCtZbYNNDpYnKINAKSDsM+KOQaSYQ2FhHk
bmBZk/K96P7VntzYI5S02+hOWnvjq5Wk4gOt1+L18+R/XujuxGbwnHW2
-----END CERTIFICATE-----
</cert>

# this is an random key. The .ovpn file needs one, but doesn't use it, so you can leave this as is
<key>
-----BEGIN PRIVATE KEY-----
MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALVEXIZYYu1Inmej
uo4Si6Eo5AguTX5sg1pGbLkJSTR4BXQsy6ocUnZ9py8htYkipkUUhjY7zDu+wJlU
tWnVCwCYtewYfEc/+azH7+7eU6ueT2K2IKdik1KWhdtNbaNphVvSlgdyKiuZDTCe
dptgWyiL50N7FMcUUMjjXYh/hftBAgMBAAECgYEAsNjgOEYVRhEaUlzfzmpzhakC
SKT8AALYaAPbYO+ZVzJdh8mIbg+xuF7A9G+7z+5ZL35lrpXKnONuvmlxkK5ESwvV
Q7EOQYCZCqa8xf3li3GUBLwcwXKtOUr3AYXhdbOh2viQdisD4Ky7H6/Nd3yMc3bu
R4pErmWeHei+l6dIwAECQQDqljNxi9babmHiei6lHaznCMg5+jfAyDXgHvO/afFr
1bDQVDTDK+64kax4E9pvDZC6B/HGse9hOUGWXTjb0WZBAkEAxdAw/14iJIUcE5sz
HDy2R0RmbUQYFjrNgBCi5tnmr1Ay1zHAs1VEF+Rg5IOtCBO50I9jm4WCSwCtN6zF
FoFVAQJAUGfBJDcZIm9ZL6ZPXJrqS5oP/wdLmtFE3hfd1gr7C8oHu7BREWB6h1qu
8c1kPlI4+/qDHWaZtQpJ977mIToJwQJAMcgUHKAm/YPWLgT31tpckRDgqgzh9u4z
e1A0ft5FlMcdFFT8BuWlblHWJIwSxp6YO6lqSuBNiuyPqxw6uVAxAQJAWGxOgn2I
fGkWLLw4WMpkFHmwDVTQVwhTpmMP8rWGYEdYX+k9HeOJyVMrJKg2ZPXOPtybrw8T
PUZE7FgzVNxypQ==
-----END PRIVATE KEY-----
</key>

Configure OpenVPN to authenticate with Radius

Create the file /etc/pam_radius_auth.conf and add the following contents to it. RADIUSSERVERIP should be the internal IP of your USG (just glance at the putty titlebar). Enter the shared secret you created when you enabled the Radius server.

sudo vi /etc/pam_radius_auth.conf

Need to know vi quick start tips, once the file is opened, press I to enter insert mode type the USG IP and the RADIUS Preshared Key as noted below

Give it a carriage return, then press Escape on the keyboard bring up the vi command prompt with : and (w)rite and (q)uit

:wq

File contents for /etc/pam_radius_auth.conf

RADIUSSERVERIP SHAREDSECRET

Create the file /etc/pam.d/openvpn

sudo vi /etc/pam.d/openvpn

and add the following contents:

auth sufficient pam_radius_auth.so debug
account sufficient pam_permit.so
session sufficient pam_permit.so

You should now be able to connect to your USG via OpenVPN using Radius authentication with the username and password you configured in the beginning. (in the Radius settings, which is outside the scope of this document, if they had L2TP they can re-use those settings)

Client setup is as easy as installing the lastest client software (2020-12-22 confirmed 2.5.0 works https://swupdate.openvpn.org/community/releases/OpenVPN-2.5.0-I601-amd64.msi)

Then start the GUI, it'll nag you about no configs, then right click the notification tray icon and choose import and browse to the .ovpn file you created earlier.

Persist your changes

Reboot Persist

On a reboot the configuration can be removed so we make a script to fix that

sudo vi /config/scripts/post-config.d/postreboot.sh
postreboot.sh code
#!/bin/vbash
readonly logFile="/var/log/postreboot.log"

source /opt/vyatta/etc/functions/script-template

#restore the radius configuration
echo "Copying PAM and OpenVPN config files" >> ${logFile}
cp -f /config/scripts/ovpn_radius_config/pam_radius_auth.conf /etc
cp -f /config/scripts/ovpn_radius_config/openvpn /etc/pam.d/openvpn

Mark your script executable:

sudo chmod +x /config/scripts/post-config.d/postreboot.sh

'Force Provision' Persist

Files will be overwritten after provisions. In order to persist your changes, you'll need to add a script to the /config/scripts directory to copy your files over and schedule a task to complete this after each provision.

Copy the files pam_radius_auth.conf and openvpn from the previous steps into a new directory in /config/scripts. I used ovpn_radius_config.

sudo mkdir /config/scripts/ovpn_radius_config
sudo cp /etc/pam_radius_auth.conf /config/scripts/ovpn_radius_config
sudo cp /etc/pam.d/openvpn /config/scripts/ovpn_radius_config

Create the following script /config/scripts/postprovision.sh

sudo vi /config/scripts/postprovision.sh
postprovision.sh code
#!/bin/vbash
readonly logFile="/var/log/postprovision.log"

#restore the ssmtp configuration

cp /config/scripts/ovpn_radius_config/pam_radius_auth.conf /etc
cp /config/scripts/ovpn_radius_config/openvpn /etc/pam.d/openvpn

#the following lines remove the postprovision scheduled task
#do not modify below this line

source /opt/vyatta/etc/functions/script-template

configure > ${logFile}
delete system task-scheduler task postprovision >> ${logFile}
commit >> ${logFile}
save >> ${logFile}:
#exit

#end no edit

exit

Mark your script executable:

sudo chmod +x /config/scripts/postprovision.sh

Update your config:

configure
set system task-scheduler task postprovision executable path "/config/scripts/postprovision.sh"
set system task-scheduler task postprovision interval 3m
commit
save
exit

Now we need to set the firewall rules to persist a provision or update, to do this we need to make a change on the unifi controller. Using Putty on the Fuller network connect to the UniFi Controller (the creds are in LP "FIT UniFi Ubuntu Login" but you may not have access to this, a senior tech may need to do this)

We need the site ID, to get this, navigate to the site on the unifi web interface and check the url: hxxps://xxxxxxxxxxxx:xxxx/manage/site/i3w5kh6s/dashboard

The part between site and dashboard is the site ID.

You have to copy the config.gateway.json from default to the site id folder at /usr/lib/unifi/data/sites

I made a bash script to handle this, it won't overwrite a file already there though.

sudo ./openvpnjson.sh
openvpnjson.sh code
#!/bin/bash

printf "Type site ID, (case sensitive):\n"
read siteid
siteidfolder="/usr/lib/unifi/data/sites/${siteid}"
if [ ! -d "$siteidfolder" ]; then
mkdir "$siteidfolder"
fi
cd /usr/lib/unifi/data/sites/default
cp config.gateway.json "$siteidfolder"
It will prompt for the site ID only, enter it in lowercase as it appears in the url. If a site folder doesn't exist, it makes one and then copies the file from the default folder into the site folder. The default config.gateway.json contents can be viewed in LP "FIT UniFi Default Site config.gateway.json"

To test the persistence: Navigate to the device in question and go to manage and perform a force provision Once the provision is complete, view the firewall rules for WAN LOCAL and confirm that "Allow OpenVPN client in" is at Rule 20.

Testing

Reboot the USG. Test connection. Force Provision the USG. Test connection.

Verification

To verify a config is still operational, say due to an update or provision, login to the device and check the following:

ls /config/auth/keys

Look for ca.crt, server.crt, server.key, dh2048.pem

sudo cat /config/auth/keys/ca.crt

Make sure this matches the entry in LP

configure
show | grep "openvpn"
exit

Confirm the configuration has openvpn lines in it. You should see this:

   openvpn vtun0 {
         openvpn-option "--keepalive 8 30"
         openvpn-option --comp-lzo
         openvpn-option --duplicate-cn
         openvpn-option "--user nobody --group nogroup"
         openvpn-option "--plugin /usr/lib/openvpn/openvpn-auth-pam.so openvpn"
         openvpn-option "--client-cert-not-required --username-as-common-name"
         openvpn-option "--verb 1"
         openvpn-option "--proto udp6"
         openvpn-option "--port 1194"
         openvpn-option "--push redirect-gateway def1"
         openvpn-option "--push dhcp-option DNS 8.8.8.8"
         openvpn-option "--push dhcp-option DNS 8.8.4.4"
[edit]

Confirm presence and (optionally) contents of these files:

cat /etc/pam_radius_auth.conf
cat /etc/pam.d/openvpn
cat /config/scripts/post-config.d/postreboot.sh
cat /config/scripts/postprovision.sh

Confirm the task-scheduler entries are present

configure
show | grep "task-scheduler"
exit

That completes the verification of the settings on the USG

Troubleshooting

If you find you have trouble connecting, check your USG logs with show log | grep openvpn You can check your configuration to ensure the firewall rules exist using this command: mca-ctrl -t dump-cfg | grep OpenVPN

You might also see this in the connection log, these two warnings are normal, anything additional is not normal

Mon Jun 08 16:08:39 2020 WARNING: No server certificate verification method has been enabled.  See http://openvpn.net/howto.html#mitm for more info.
Mon Jun 08 16:08:39 2020 TCP/UDP: Preserving recently used remote address: [AF_INET]xx.xx.xx.xx:1194
Mon Jun 08 16:08:39 2020 Socket Buffers: R=[65536->65536] S=[65536->65536]
Mon Jun 08 16:08:39 2020 UDP link local: (not bound)
Mon Jun 08 16:08:39 2020 UDP link remote: [AF_INET]xx.xx.xx.xx:1194
Mon Jun 08 16:08:39 2020 MANAGEMENT: >STATE:1591646919,WAIT,,,,,,
Mon Jun 08 16:08:39 2020 MANAGEMENT: >STATE:1591646919,AUTH,,,,,,
Mon Jun 08 16:08:39 2020 TLS: Initial packet from [AF_INET]69.61.140.22:1194, sid=95dff9c7 b848d0b4
Mon Jun 08 16:08:39 2020 WARNING: this configuration may cache passwords in memory -- use the auth-nocache option to prevent this

Repairs

Had a customer call and for some reason the easyrsa binaries were missing (I don't think they're needed after key generation) and the postprovision steps were not in the configuration. The easiest fix is to login and run these commands, I did an update while I was at it, it's possible I missed the postprovision steps on the original visit.

sudo bash
curl -O http://ftp.us.debian.org/debian/pool/main/e/easy-rsa/easy-rsa_2.2.2-1_all.deb
sudo dpkg -i easy-rsa_2.2.2-1_all.deb
configure
set system task-scheduler task postprovision executable path "/config/scripts/postprovision.sh"
set system task-scheduler task postprovision interval 3m
commit
save
exit

Changelog

  • 2021/01/21 Same customer called back and I dug into this again and found reboots reset it, so added a script for reboots
  • 2021/01/19 Customer lost binaries and postprovision part of config, detailed repair steps
  • 2020/12/22 Had another tech use the document and found some unclear things, confirmed 2.5.0 works
  • 2020/06/15 Put the bash code in as well, tested this on another site and it seems to work.
  • 2020/06/09 Completed document by adding the json file copy necessary for persistence.
  • 2020/06/08 Minor adjustments, typo correction and added log file warnings that are safe to ignore
  • 2020/05/01 Forked and added some details for our environment
  • 2018/18/30: Added post provision script
  • 2018/08/29: First release
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment