Organizing remote work for SMB organizations using OpenVPN

Task Definition

The article describes the organization of remote access for employees using open-source products and can be used to build a fully autonomous system or be helpful for expansion when the existing commercial system lacks licenses or its performance is inadequate.

The goal of the article is to implement a complete remote access solution for the organization, which is a bit more than just 'installing OpenVPN in 10 minutes'.

As a result, we will have a system where user authentication will use certificates and (optionally) a corporate Active Directory directory. Thus, we will have a system with two-factor authentication — something I have (certificate) and something I know (password).

A sign that a user is allowed to connect is their membership in the myVPNUsr group. The certification center will be used autonomously.

The cost of implementing the solution is only minimal hardware resources and 1 hour of a system administrator's work.

We will use a virtual machine with OpenVPN and Easy-RSA version 3 on CentOS 7, which is allocated 4 vCPUs and 4 GiB RAM for 100 connections.

In the example, our organization's network is 172.16.0.0/16, where the VPN server with the address 172.16.19.123 is located in the segment 172.16.19.0/24, DNS servers are 172.16.16.16 and 172.16.17.17, and a subnet 172.16.20.0/23 is allocated for VPN clients.

External connections use port 1194/udp, and an A-record gw.abc.ru has been created in DNS for our server.

It is strongly not recommended to disable SELinux! OpenVPN works without disabling security policies.

Content

  1. Operating System and Application Software Installation
  2. Cryptography Configuration
  3. OpenVPN Configuration
  4. AD Authentication
  5. Launch and Diagnostics
  6. Issuing and Revoking Certificates
  7. Network setup
  8. What's Next

Operating System and Application Software Installation

We use the distribution CentOS 7.8.2003. We need to install the OS in minimal configuration. It is convenient to do this using kickstart, cloning a previously installed OS image, and other means.

After installation, assign an address to the network interface (as per the task conditions 172.16.19.123) and perform an OS update:

$ sudo yum update -y && reboot

It is also necessary to ensure that time synchronization is performed on our machine.
To install application software, the packages openvpn, openvpn-auth-ldap, easy-rsa, and vim as the main editor are needed (the EPEL repository will be required).

$ sudo yum install epel-release
$ sudo yum install openvpn openvpn-auth-ldap easy-rsa vim

For the virtual machine, it is useful to install the guest agent:

$ sudo yum install open-vm-tools

for VMware ESXi hosts, or for oVirt

$ sudo yum install ovirt-guest-agent

Cryptography Configuration

Navigating to the easy-rsa directory:

$ cd /usr/share/easy-rsa/3/

Creating the variables file:

$ sudo vim vars

with the following content:

export KEY_COUNTRY="RU"
export KEY_PROVINCE="MyRegion"
export KEY_CITY="MyCity"
export KEY_ORG="ABC LLC"
export KEY_EMAIL="admin@abc.ru"
export KEY_CN="allUsers"
export KEY_OU="allUsers"
export KEY_NAME="gw.abc.ru"
export KEY_ALTNAMES="abc-openvpn-server"
export EASYRSA_CERT_EXPIRE=3652

Here are parameters described for the hypothetical organization LLC "ABC"; you can correct them to the actual ones or keep them as examples. The most important parameter is the last line, which defines the certificate validity period in days. The example uses a value of 10 years (365*10+2 leap years). This value will need to be adjusted before issuing user certificates.

Next, we set up the offline certificate authority.

The setup includes exporting variables, initializing the CA, issuing the root key and CA certificate, generating the Diffie-Hellman key, TLS key, as well as the server key and certificate. The certificate authority key must be carefully guarded and kept secret! All parameters in requests can be left at their defaults.

cd /usr/share/easy-rsa/3/
. ./vars
./easyrsa init-pki
./easyrsa build-ca nopass
./easyrsa gen-dh
./easyrsa gen-req myvpngw nopass
./easyrsa sign-req server myvpngw
./easyrsa gen-crl
openvpn --genkey --secret pki/ta.key

This concludes the main part of setting up the cryptographic mechanism.

OpenVPN Configuration

Now we move to the OpenVPN directory, create service directories, and add a link to easy-rsa:

cd /etc/openvpn/
mkdir /var/log/openvpn/ /etc/openvpn/ccd /usr/share/easy-rsa/3/client
ln -s /usr/share/easy-rsa/3/pki/ /etc/openvpn/

Creating the main OpenVPN configuration file:

$ sudo vim server.conf

with the following content

port 1194
proto udp
dev tun
ca /etc/openvpn/pki/ca.crt
cert /etc/openvpn/pki/issued/myvpngw.crt
key /etc/openvpn/pki/private/myvpngw.key
crl-verify /etc/openvpn/pki/crl.pem
dh /etc/openvpn/pki/dh.pem
server 172.16.20.0 255.255.254.0
ifconfig-pool-persist ipp.txt
push "route 172.16.0.0 255.255.255.0"
push "route 172.17.0.0 255.255.255.0"
client-config-dir ccd
push "dhcp-option DNS 172.16.16.16"
push "dhcp-option DNS 172.16.17.17"
keepalive 10 120
cipher AES-256-CBC
user nobody
group nobody
persist-key
persist-tun
status /var/log/openvpn/openvpn-status.log
log-append  /var/log/openvpn/openvpn.log
verb 3
explicit-exit-notify 1
username-as-common-name
plugin /usr/lib64/openvpn/plugin/lib/openvpn-auth-ldap.so /etc/openvpn/ldap.conf

Some notes on the parameters:

  • if a different name was specified when issuing the certificate — specify it;
  • the address pool should be adjusted for your needs*;
  • there can be one or more routes and DNS servers;
  • the last 2 lines are needed for implementing authentication in AD**.

*The selected address range in the example allows up to 127 clients to connect simultaneously, as a /23 network is chosen, and OpenVPN creates a /30 subnet for each client.
If necessary, the port and protocol can be changed; however, keep in mind that changing the port number will require SELinux configuration, and using the TCP protocol will increase overhead, as TCP packet delivery control is already performed at the encapsulated packet level.

**If AD authentication is not needed, comment them out, skip to the next section, and in the template, remove the line auth-user-pass.

AD Authentication

To support two-factor authentication, we will use account verification in AD.

We need a domain account with user rights and a group, the membership of which will determine the ability to connect.

Creating the configuration file:

/etc/openvpn/ldap.conf

with the following content

URL             "ldap://ldap.abc.ru"
        BindDN          "CN=bindUsr,CN=Users,DC=abc,DC=ru"
        Password        b1ndP@SS
        Timeout         15
        TLSEnable       no
        FollowReferrals yes


        BaseDN          "OU=allUsr,DC=abc,DC=ru"
        SearchFilter    "(sAMAccountName=%u)"
        RequireGroup    true
        
                BaseDN          "OU=myGrp,DC=abc,DC=ru"
                SearchFilter    "(cn=myVPNUsr)"
                MemberAttribute "member"

Main parameters:

  • URL "ldap://ldap.abc.ru" — the address of the domain controller;
  • BindDN "CN=bindUsr,CN=Users,DC=abc,DC=ru" — the canonical name for binding to LDAP (User is bindUsr in the abc.ru/Users container);
  • Password b1ndP@SS — the password for the user binding;
  • BaseDN "OU=allUsr,DC=abc,DC=ru" — the path from which to start looking for the user;
  • BaseDN "OU=myGrp,DC=abc,DC=ru" — the container of the approving group (group myVPNUsr in the abc.ru/myGrp container);
  • SearchFilter "(cn=myVPNUsr)" — the name of the approving group.

Launch and Diagnostics

Now we can try to enable and start our server:

$ sudo systemctl enable openvpn@server.service
$ sudo systemctl start openvpn@server.service

Check the startup:

systemctl status openvpn@server.service
journalctl -xe
cat /var/log/messages
cat /var/log/openvpn/*log

Issuing and Revoking Certificates

Since keys and other settings are needed in addition to the certificates, it is very convenient to wrap all of this into one profile file. This file is then passed to the user, and the profile is imported on the OpenVPN client. For this, we will create a settings template and a script to generate the profile.

The profile needs to include the contents of the root certificate files (ca.crt) and the TLS key (ta.key).

Before issuing user certificates Don't forget to set the required validity period for the certificates in the parameter file. It shouldn't be too long; I recommend limiting it to a maximum of 180 days.

vim /usr/share/easy-rsa/3/vars

...
export EASYRSA_CERT_EXPIRE=180

vim /usr/share/easy-rsa/3/client/template.ovpn

client
dev tun
proto udp
remote gw.abc.ru 1194
resolv-retry infinite
nobind
persist-key
persist-tun
remote-cert-tls server
cipher AES-256-CBC
verb 3
auth-user-pass


-----BEGIN CERTIFICATE-----
PUT YOUR CA CERT (ca.crt) HERE
-----END CERTIFICATE-----


key-direction 1

-----BEGIN OpenVPN Static key V1-----
PUT YOUR TA KEY (ta.key) HERE
-----END OpenVPN Static key V1-----

Notes:

  • lines PUT YOUR… replace with the content of your certificates;
  • in the remote directive, specify the name/address of your gateway;
  • the auth-user-pass directive is used for additional external authentication.

In the home directory (or another convenient location), create a script to request the certificate and create the profile:

vim ~/make.profile.sh

#!/bin/bash

if [ -z "$1" ] ; then
 echo Missing mandatory client name. Usage: $0 vpn-username
 exit 1
fi

#Set variables
basepath=/usr/share/easy-rsa/3
clntpath=$basepath/client
privpath=$basepath/pki/private
certpath=$basepath/pki/issued
profile=$clntpath/$1.ovpn

#Get current year and lowercase client name
year=`date +%F`
client=${1,,}
echo Processing $year year cert for user/device $client

cd $basepath

if [  -f client/$client* ]; then
    echo "*** ERROR! ***"
    echo "Certificate $client already issued!"
    echo "*** ERROR! ***"
    exit 1
fi

. ./vars
./easyrsa --batch --req-cn=$client gen-req $client nopass
./easyrsa --batch sign-req client $client

#Make profile
cp $clntpath/template.ovpn $profile

echo "<key>" >> $profile
cat $privpath/$1.key >> $profile
echo "</key>" >> $profile

echo -e "n" >> $profile
openssl x509 -in $certpath/$1.crt -out $basepath/$1.crt

echo "<cert>" >> $profile
cat $basepath/$1.crt >> $profile
echo "</cert>" >> $profile
echo -e "n" >> $profile

#remove tmp file
rm -f $basepath/$1.crt

echo Complete. See $profile file.

cd ~

We make the file executable:

chmod a+x ~/make.profile.sh

And we can issue our first certificate.

~/make.profile.sh my-first-user

Review

In case of certificate compromise (loss, theft) it is necessary to revoke this certificate:

cd /usr/share/easy-rsa/3/
./easyrsa revoke my-first-user
./easyrsa gen-crl

View issued and revoked certificates

To view issued and revoked certificates, simply check the index file:

cd /usr/share/easy-rsa/3/
cat pki/index.txt

Explanations:

  • the first line contains the server certificate;
  • the first character
    • V (Valid) — valid;
    • R (Revoked) — revoked.

Network setup

The last steps involve configuring network transmission — routing and firewalls.

Allowing connections in the local firewall:

$ sudo firewall-cmd --add-service=openvpn
$ sudo firewall-cmd --add-service=openvpn --permanent

Next, enable IP traffic routing:

$ sudo sysctl net.ipv4.ip_forward=1
$ sudo echo "net.ipv4.ip_forward=1" > /etc/sysctl.d/50-sysctl.conf

In a corporate environment, there is likely a division into subnets, and we need to inform the router(s) how to send packets addressed to our VPN clients. In the command line, execute a command similar to (depends on the equipment used):

# ip route 172.16.20.0 255.255.254.0 172.16.19.123

and save the configuration.

Additionally, on the interface of the border router, where the external address gw.abc.ru is served, it is necessary to allow the passage of packets udp/1194.

If your organization has strict security policies, you also need to configure a firewall on our VPN server. In my opinion, configuring iptables FORWARD chains offers the most flexibility, although it is less convenient to set up. Here's a bit more detail on how to do this. The easiest way is to use 'direct rules,' which are stored in a file. /etc/firewalld/direct.xmlYou can find out the active configuration of the rules like this:

$ sudo firewall-cmd --direct --get-all-rule

Before modifying the file, make a backup of it:

cp /etc/firewalld/direct.xml /etc/firewalld/direct.xml.`date +%F.%T`.bak

A sample content of the file is as follows:


  
    -i tun0 -o ens192 -p udp --dport 53 -j ACCEPT
  
    -i tun0 -o eth0 -p tcp -d 172.16.19.200 --dport 80 -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT
    -i tun0 -o eth0 -p tcp -d 172.16.19.201 --dport 443 -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT
  
    -i tun0 -o eth0 -p udp -d 172.16.19.100 --dport 7000 -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT
  
    -i tun0 -o eth0 -j LOG --log-prefix 'forward_fw '

Explanations

Essentially, these are standard iptables rules, otherwise wrapped since the introduction of firewalld.

The default destination interface is tun0, while the external one for the tunnel could be different, e.g., ens192, depending on the platform used.

The last line is meant for logging dropped packets. To enable logging, you need to adjust the debugging level in the firewalld configuration:

vim /etc/sysconfig/firewalld
FIREWALLD_ARGS=--debug=2

Applying the settings is done with the standard firewalld command to reload the settings:

$ sudo firewall-cmd --reload

You can view dropped packets like this:

grep forward_fw /var/log/messages

What's Next

That completes the configuration!

On the client side, you need to install the client software, import the profile, and connect. The distribution for Windows OS is available at developer's website..

Finally, we connect our new server to monitoring and archiving systems, and remember to regularly install updates.

Stable connection!

Source: habr.com

Buy reliable website hosting with DDoS protection, VPS VDS servers 🔥 Buy reliable website hosting with DDoS protection, VPS VDS servers | ProHoster