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
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 , 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-toolsfor 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 varswith 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.confwith 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.confwith 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.ovpnclient
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.shAnd we can issue our first certificate.
~/make.profile.sh my-first-userReview
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.123and 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-ruleBefore modifying the file, make a backup of it:
cp /etc/firewalld/direct.xml /etc/firewalld/direct.xml.`date +%F.%T`.bakA 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 --reloadYou 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 .
Finally, we connect our new server to monitoring and archiving systems, and remember to regularly install updates.
Stable connection!
Source: habr.com
