Edgerouter Security, Part5

OpenVPN

Now i want to setup an OpenVPN server on my Edgerouter. I am feeling pretty nervous about just securing this with a username and password. I want to be able to connect to my network from a PC I don’t trust 100%. The way to do this is by using a combination of a certificate and a google authenticator passcode. In this way, if that PC gets compromised, the attacker would also need my phone to authenticate to my edgerouter! This step requires that Google Authenticator has already been installed. It will be if you followed this series on Edgerouter Security.

Create a user for logging into our OpenVPN server

First we create a user for our OpenVPN connections. Even though we give it a long secret password, this is never used for authentication, it’s just there to prevent brute force attacks via SSH or the webinterface.

configure
set system login user openvpn-user authentication plaintext-password superlongsecretpassword=5
set system login user openvpn-user level operator
commit

Now we set up google authenticator for our user. All the answers are the same as the setup for our SSH user.

sudo su -c "google-authenticator --label=\"A good name for the openvpn user\"" openvpn-user

The private key should be scanned or typed into your phone.

Create a CA authority, a server certificate and a user certificate

Our first job is to make a directory where all the certificates will be. It’s important to save it under /config, because this directory will survive a firmware update. All certificate commands are run with /config/openvpn as the current directory.

sudo -i
mkdir /config/openvpn
cd /config/openvpn

Now we create a certificate authority that will be signing all future certificates on the Edgerouter.

/usr/lib/ssl/misc/CA.sh -newca
CA certificate filename (or enter to create): <enter>
Enter PEM pass phrase: <CApassword>
Verifying - Enter PEM pass phrase: <CApassword>
Country Name (2 letter code) [AU]: DK
State or Province Name (full name) [Some-State]: Some-State
Locality Name (eg, city) []: Some City
Organization Name (eg, company) [Internet Widgits Pty Ltd]: Some Corp
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []: My CA
Email Address []:
Please enter the following 'extra' attributes to be sent with your certificate request
A challenge password []:
An optional company name []:
Enter pass phrase for ./demoCA/private/./cakey.pem: <CApassword>

A certification authority is now created in /config/openvpn/demoCA

Now we need to create a server certificate for the OpenVPN server.

/usr/lib/ssl/misc/CA.sh -newreq
Generating a 2048 bit RSA private key
Enter PEM pass phrase: <tempserverkeypassphrase>
Verifying - Enter PEM pass phrase: <tempserverkeypassphrase>
Country Name (2 letter code) [AU]: DK
State or Province Name (full name) [Some-State]: Some State
Locality Name (eg, city) []: Some City
Organization Name (eg, company) [Internet Widgits Pty Ltd]: Some Corp
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []: my.domain.org
Email Address []:
A challenge password []:
An optional company name []:

Then we sign the server certificate with our CA

/usr/lib/ssl/misc/CA.sh -sign
Enter pass phrase for ./demoCA/private/cakey.pem: <CApassword>
Sign the certificate? [y/n]: y
1 out of 1 certificate requests certified, commit? [y/n]: y

Now we rename the files to something recognizable and then we decrypt the server key so that OpenVPN can use it without prompting for a passphrase

mv newcert.pem server.pem
mv newkey.pem server.key
rm newreq.pem
openssl rsa -in server.key -out server-decrypted.key
Enter pass phrase for /config/auth/server.key: <tempserverkeypassphrase>

Now we create the Diffie Hellman parameters for perfect forward secrecy. This can take a looooooooooong time…. First time it took about 1,5 hours, second time it took 20 minutes! If you can’t wait you can decrease the keylength to 1024, but that is not recommended.

openssl dhparam -out dh2048.pem -2 2048

Now we generate the user certificate for the user that will connect to our openvpn server

/usr/lib/ssl/misc/CA.sh -newreq
Enter PEM pass phrase: <tempusercertpass>
Verifying - Enter PEM pass phrase: <tempusercertpass>
Country Name (2 letter code) [AU]: DK
State or Province Name (full name) [Some-State]: Some State
Locality Name (eg, city) []: Some City
Organization Name (eg, company) [Internet Widgits Pty Ltd]: Some Corp
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []: openvpn-user
Email Address []:
A challenge password []:
An optional company name []:

Now we sign the new user certificate with our CA

/usr/lib/ssl/misc/CA.sh -sign
Enter pass phrase for ./demoCA/private/cakey.pem: <CApassword>
Sign the certificate? [y/n]: y
1 out of 1 certificate requests certified, commit? [y/n]: y

Now we rename the files to something recognizable and then we decrypt the user-certificate key so that we later can transfer it to our device

mv newcert.pem openvpn-user.pem
mv newkey.pem openvpn-user.key
rm newreq.pem
openssl rsa -in openvpn-user.key -out openvpn-user-decrypted.key
Enter pass phrase for /config/auth/openvpn-user.key: <tempusercertpass>

Setting up the OpenVPN server

First step is to setup PAM to do Google Authentication for OpenVPN

cd /etc/pam.d
cp common-account openvpn
echo "auth required pam_google_authenticator.so" >> openvpn

Now that all certificates are in place, we need to setup an openVPN interface. I chose to set it up with UDP on port 1194 which is standard. I created a special subnet for the interface (192.168.200.0/24) and made it possible for clients to connect to my internal management network (192.168.10.0/24).  The last config line enables Google Authenticator authentication, and it works because we already install Google Authenticator for SSH access.

exit #exit out of our previous sudo session
set interfaces openvpn vtun0
set interfaces openvpn vtun0 description "OpenVPN server"
set interfaces openvpn vtun0 mode server
set interfaces openvpn vtun0 encryption aes256
set interfaces openvpn vtun0 hash sha256
set interfaces openvpn vtun0 server subnet 192.168.200.0/24
set interfaces openvpn vtun0 server push-route 192.168.10.0/24
set interfaces openvpn vtun0 server name-server 192.168.200.1
set interfaces openvpn vtun0 tls ca-cert-file /config/openvpn/demoCA/cacert.pem
set interfaces openvpn vtun0 tls cert-file /config/openvpn/server.pem
set interfaces openvpn vtun0 tls key-file /config/openvpn/server-decrypted.key
set interfaces openvpn vtun0 tls dh-file /config/openvpn/dh2048.pem
set interfaces openvpn vtun0 openvpn-option "--port 1194"
set interfaces openvpn vtun0 openvpn-option --tls-server
set interfaces openvpn vtun0 openvpn-option "--comp-lzo yes"
set interfaces openvpn vtun0 openvpn-option --persist-key
set interfaces openvpn vtun0 openvpn-option --persist-tun
set interfaces openvpn vtun0 openvpn-option "--keepalive 10 120"
set interfaces openvpn vtun0 openvpn-option "--user nobody"
set interfaces openvpn vtun0 openvpn-option "--group nogroup"
set interfaces openvpn vtun0 openvpn-option '--plugin /usr/lib/openvpn/openvpn-auth-pam.so openvpn'
commit

Now we need to punch a hole in our WAN interface to allow incoming OpenVPN traffic.

set firewall name WAN_LOCAL rule 20 action accept
set firewall name WAN_LOCAL rule 20 description 'Allow OpenVPN'
set firewall name WAN_LOCAL rule 20 destination port 1194
set firewall name WAN_LOCAL rule 20 protocol udp

We also need to listen to DNS queries on the OpenVPN interface

set service dns forwarding listen-on vtun0

Creating an .ovpn file for our client

On our client we create a .ovpn file that looks like this:

client
dev tun
proto udp
remote <FQDN or WANIP of the Edgerouter> 1194
cipher AES-256-CBC
auth SHA256
resolv-retry infinite
redirect-gateway def1
nobind
comp-lzo yes
persist-key
persist-tun
user nobody
group nogroup
verb 3
setenv ALLOW_PASSWORD_SAVE 0 
auth-user-pass

<ca>
-----BEGIN CERTIFICATE-----
-----END CERTIFICATE-----
</ca>

<cert>
-----BEGIN CERTIFICATE-----
-----END CERTIFICATE-----
</cert>

<key>
-----BEGIN RSA PRIVATE KEY-----
-----END RSA PRIVATE KEY-----
</key>

The three certificate sections of the .ovpn file should be filled out with the certificate information from the Edgerouter. I got these three pieces of information with these commands listed in correct order

cat /config/openvpn/demoCA/cacert.pem
cat /config/openvpn/openvpn-user.pem
cat /config/openvpn/openvpn-user-decrypted.key

The finalized file can now be distributed to the client device securely. Eg. I used itunes and a usb cable to transfer the .ovpn file to my iphone. Never use email or dropbox to transfer this file!

What do we have?

Now we can connect to our Edgerouter with OpenVPN. It’s secured with a certificate, and you need a Google Authenticator to generate the passphrases to authenticate. The performance on OpenVPN is about 7 Mbits which is enough for my purposes.

26 thoughts to “Edgerouter Security, Part5”

  1. Excellent instructions. I am wondering about Google authenticator. I don’t need it for my devices, can I just eliminate those lines from your instructions to get the openvpn server running with just username and password? Any help would be great.

    1. You should be able to do that if you skip this config-line:
      set interfaces openvpn vtun0 openvpn-option '--plugin /usr/lib/openvpn/openvpn-auth-pam.so openvpn'

  2. Great guide
    I has to add “-s /bin/bash” to sudo su -c “google-authenticator –label=\”A good name for the openvpn user\”” openvpn-user

    or i will get “This account is currently not available” because operator use another shell

  3. Just one question. the portforward there is on the server can not be reached from vpn. i can contact when i use the local ip. but on lan i can also use domain.com but it dont work on vpn ?

    Do you have a solution ?

  4. Hi there – great instructions! I have configured everything following your steps, but alas, after pushing the .ovpn file onto my iPhone, I am unable to connect to my router… it times out. In the logs, it appears to be attempting to connect to the correct WAN IP address. I get EVENT: CONNECTION_TIMEOUT [ERR] and then it disconnects.

    Any thoughts on what could be wrong?

    1. Be sure you are not on your internal network/wifi. That could be the cause.
      Try to portscan yourself from the outside to see if your vpn server is listening

  5. Thanks for guide, it helps!

    but I made big problem with firewall setting… I used it exactly as it is written but rule 20 have existed already … please write note, that you should find your last firewall rule.

    Thx! It will save severals hours.

    here is command to list yours rules:
    show firewall name WAN_LOCAL

  6. Thanks for the guide, this is great!

    One thing that wasn’t clear, and maybe it’s because I left out the 2FA bit, is that it asks to “Enter Auth Username” and “Enter Auth Password.” I took me a little while to realize I could use “nobody” for the username and anything for the password. How can I change this so I’ve got a specific username & a strong password?

    Also, if I do use Google Authenticator, would I need a separate entry for each of my clients? And will Authy work just as well?

    1. So now I’m trying to get it working with 2FA, but I can’t…

      I’ve answered my own questions about Google Authenticator & Authy. I’ve followed this guide but can’t seem to get it working. It still asks me to “Enter Auth Username” and “Enter Auth Password.” The openvpn-user creds don’t seem to work. Am I doing something wrong?

      1. The very first lines under “Create a user for logging into our OpenVPN server” are where you’re configuring username password logins to the openvpn server. In the example code “openvpn-user” is the userid, and “superlongsecretpassword=5” is the password. Replace those with whatever userid / password you wish to enable on your system.

        1. Tried that. I have the same username (openvpn-user) and of course a different password. Could it be different versions of the OS? I think there’s been a change since this article was written and now “operator” accounts don’t have SSH access, only web GUI access. Much like Brian stated in a previous comment, I had to change the google-authenticator command to be:

          sudo su -s /bin/bash -c "google-authenticator –label=\"A good name for the openvpn user\"" openvpn-user

          or else I’d get “This account is currently not available.”

          1. Yes, probably you are using the newer version of EdgeOS

            https://community.ubnt.com/t5/EdgeRouter/EdgeMAX-EdgeRouter-software-version-v1-9-7-hotfix-3-has-been/td-p/2054138

            [User account] WARNING! Disabled shell access for operator user. From now on operator user will have only WebUI access. If operator user will try to access shell (via SSH or telnet) then error message “This account is currently not available” will be displayed and access will be denied. We decided to decrease operator user privileges for security reasons.

        2. I also tried using openvpn-user for the username and just the 6 digit code from my authenticator app as the password. Anyway, here’s the exact output from my Arch Linux laptop when trying to connect to the router:
          $ sudo openvpn OpenVPN-Client.ovpn
          Thu Feb 8 21:54:21 2018 OpenVPN 2.4.4 x86_64-unknown-linux-gnu [SSL (OpenSSL)] [LZO] [LZ4] [EPOLL] [PKCS11] [MH/PKTINFO] [AEAD] built on Sep 26 2017
          Thu Feb 8 21:54:21 2018 library versions: OpenSSL 1.1.0g 2 Nov 2017, LZO 2.10
          Enter Auth Username: openvpn-user
          Enter Auth Password: ******
          Thu Feb 8 21:54:40 2018 WARNING: No server certificate verification method has been enabled. See http://openvpn.net/howto.html#mitm for more info.
          Thu Feb 8 21:54:40 2018 failed to find GID for group nogroup
          Thu Feb 8 21:54:40 2018 Exiting due to fatal error

        3. Finally got it! In the client .ovpn file, I had to change “group nogroup” to “group users”. Now I use the “openvpn-user” for the Auth Username and the 6-digit OTP for the Auth Password.

        4. I hate to spam this comment section, but when using an ovpn client file I created on a Windows machine, the authentication failed when using a 6 digit OTP as the password. However, it succeeded when I used the openvpn-user password. It also works when I use another admin username/pw combo from the router… wut?

  7. Hi
    during phase ‘Now we sign the new user certificate with our CA’
    /usr/lib/ssl/misc/CA.sh -sign
    Enter pass phrase for ./demoCA/private/cakey.pem:
    Sign the certificate? [y/n]: y

    i have error like this:

    Sign the certificate? [y/n]:y
    failed to update database
    TXT_DB error number 2
    Signed certificate is in newcert.pem

    newcert.pem file is 0 bytes.

    Thanks for help.

  8. Hey Alex,
    Thanks for this!!!
    I’m close but problems –

    Is this login:
    configure
    set system login user openvpn-user authentication plaintext-password superlongsecretpassword=5
    set system login user openvpn-user level operator
    commit

    The same as this:
    cd /etc/pam.d
    cp common-account openvpn
    echo “auth required pam_google_authenticator.so” >> openvpn

    Thanks I’m missing something somewhere… not getting the google-authenticator request.

    1. The login configuration part is only for creating the user in linux.
      The pam.d configuration is to tell linux that when the user logs in he should use the google authenticator plugin

  9. Great guide. I’m not using the Google auth, but everything else is the same. One question, I’ve read that –push “redirect-gateway def1” needs to be performed on the server to ensure all ipv4 traffic flows through the tunnel, is this the case when using an EdgeRouter, or is having
    redirect-gateway def1 in the client config file enough to ensure all ipv4 traffic travels through vpn tunnel?

  10. I have used this guide frequently. It is amazing. Here are a few updates for selinux:
    Use the following to replace the echo to openvpn. It allows the authenticator file to live in a directory available during login:

    echo “auth required pam_google_authenticator.so” secret=/home/${USER}/.ssh/.google_authenticator >> openvpn

    Then after running
    sudo su -s /bin/bash -c “google-authenticator –label=\”A good name for the openvpn user\”” openvpn-user

    run the following to place authenicator in correct directory.
    mv /home/openvpn-user/.google-authenticator /home/openvpn-user/.ssh/.google-authenticator

  11. Just got myself an Edgerouter and have configured everything following the above steps to setup the openvpn.
    I cannot get this to work. I get following errors when trying to connect from an external address:
    “TLS Error: Auth Username/Password was not provided by peer”
    “TLS Error: TLS handshake failed”
    “SIGUSR1[soft,tls-error] received, client-instance restarting”
    I can connect to the openvpn server from my LAN
    I have checked and port 1194 UDP is open
    Any suggestions to fix this would be appreciated, thanx

  12. Hi,

    All great, but this setup will not survive ER firmware update.
    Does anyone knows how to make a setup which will remain even after the firmware update…Since correct me if I’m wrong (I’m real beginner at all of this).
    …/etc folder will be erased once firmware was made .. ?

    cd /etc/pam.d
    cp common-account openvpn
    echo “auth required pam_google_authenticator.so” >> openvpn

Leave a Reply

Your email address will not be published. Required fields are marked *