Application: "OpenVPN v2.1/2.4", "EasyRSA", "Bash".
Задача: установить и настроить сервис доступа в сетевую инфраструктуру предприятия удалённых клиентов с шифрованием трафика с аутентификацией посредством индивидуальный x509-сертификатов.
На роль самого удобного и простого в применении на стороне клиента напрашивается протокол L2TP, клиенты которого реализованы для всех современных операционных систем, включая предназначенные для мобильных телефонов. Для использования L2TP не требуется установка дополнительного клиентского программного обеспечения - и это хорошо. Однако в процессе эксплуатации выявляются некоторые проблемы, вроде невозможности автоматически отправить клиенту маршруты на подсети за VPN-соединением, а также существенная трудность настройки IPSec в случае подключения с одного IP-адреса нескольких клиентов. В итоге, для организации доступа к разветвлённой корпоративной сети из хорошо известных и проверенных годами бесплатных решений остаётся только "OpenVPN Community Edition (CE)".
Последовательность дальнейших действий такова:
1. Подготовка системного окружения (отдельная инструкция);
2. Установка сервера "OpenVPN";
3. Создание корневого SSL-сертификата;
4. Создание SSL-сертификата для сервера "OpenVPN";
5. Настройка и запуск сервера "OpenVPN";
6. Разрешение пересылки сетевых пакетов в несущей системе;
7. Наладка ротации журналов событий;
8. Создание SSL-сертификатов для клиентов "OpenVPN".
9. Индивидуальная настройка сетевых параметров клиентов "OpenVPN".
2. Установка сервера "OpenVPN";
3. Создание корневого SSL-сертификата;
4. Создание SSL-сертификата для сервера "OpenVPN";
5. Настройка и запуск сервера "OpenVPN";
6. Разрешение пересылки сетевых пакетов в несущей системе;
7. Наладка ротации журналов событий;
8. Создание SSL-сертификатов для клиентов "OpenVPN".
9. Индивидуальная настройка сетевых параметров клиентов "OpenVPN".
Установка сервера "OpenVPN".
У проекта "OpenVPN Community" нет официального пакетного репозитория, так что основной способ установки - из исходных кодов, свободно доступных в git-репозитории. В "README" репозитория можно найти ссылки на инструкции по установке и настройке "OpenVPN", которыми мы в дальнейшем и воспользуемся. Кроме того, в Wiki проекта "Linux Debian" есть хорошее описание их подхода к настройке "OpenVPN".
При том, что официально "OpenVPN" в готовой сборке не поставляется, таковые сделаны для всех распространённых систем командами их поддержки. В частности, для "Linux Ubuntu 18.04 LTS" дистрибутивная версия "OpenVPN v2.4.4", а в разделе загрузки на сайте разработчиков последняя стабильная "v.2.4.9" - разбег не шокирующе велик, так что не будем усложнять себе жизнь и воспользуемся готовым APT-пакетом, идущим в комплекте с несущей операционной системой:
# apt-get update && apt-get upgrade
# apt-get install openvpn openssl iptables git
# apt-get install openvpn openssl iptables git
Сборки "OpenVPN" для "Linux Debian/Ubuntu" 2019-2020 годов не предусматривают запуск сервиса от имени произвольного непривилегированного пользователя. Можно попробовать это исправить, добавив соответствующую системную учётную запись, раздав разрешения, создав несколько sudo-правил и скриптовых обёрток для обхода недостаточного уровня полномочий при доступе к ресурсам, после чего вполне успешно запустив приложение в нужном контексте. Но за этим потребуется отключить автоматику управления приложения подсистемами "Sys-V/Systemd", написав свою - и вот мы уже потеряли возможность обновлять систему с приложениями встроенными инструментами APT. Я за максимальную совместимость и автоматизацию, и полагаю, что проще вынести VPN-сервис на полностью выделенный сервер, позволив ему там вытворять всё, что угодно.
Создаем директории для отображения статистики и хранения журнальных файлов:
# mkdir -p /var/lib/openvpn /var/log/openvpn
# touch /var/lib/openvpn/status.log
# touch /var/log/openvpn/server.log
# touch /var/lib/openvpn/status.log
# touch /var/log/openvpn/server.log
"OpenVPN" страдает мелким капризом, не желая запускаться и завершая работу в случае отсутствия файла журнала событий. Потому заранее создаём его одной и команд выше.
Отмечу, что "OpenVPN" представляет собой практически всего один исполняемый файл, играющий роль как сервера, так и клиента, в зависимости от того, с каким параметрами конфигурации он запускается.
Создание корневого SSL-сертификата.
Обеспечение конфиденциальности передаваемых данных реализуется сервисом "OpenVPN" посредством инкапсуляции в простейшее SSL-соединения, представляемое для пользователей в виде VPN-туннеля. Совершенно так же, как это случается при обращении к web-сайту по протоколу HTTPS, но в данном случае заверяющие подлинность сетевых узлов SSL-сертификаты выпущены не каким-то внешним центром сертификации, а создаются администратором VPN-сервиса.
Для управления SSL-сертификатам воспользуемся адаптированным для "OpenVPN" набором скриптов "EasyRSA" - это действительно проще, чем написание чего-то подобного самостоятельно:
# cd /usr/src
# git clone --single-branch --branch master https://github.com/OpenVPN/easy-rsa.git
# git clone --single-branch --branch master https://github.com/OpenVPN/easy-rsa.git
На случай, если "OpenVPN" будет использоваться не только в роли принимающего подключения пользователей сервиса, но и как клиент для связи со сторонней сетевой инфраструктурой, явно вынесем настраиваемую сейчас конфигурацию в поддиректорию "./server/":
# mkdir -p /etc/openvpn/server/easy-rsa
# cp -r /usr/src/easy-rsa/easyrsa3/* /etc/openvpn/server/easy-rsa
# mv /etc/openvpn/server/easy-rsa/vars.example /etc/openvpn/server/easy-rsa/vars
# cp -r /usr/src/easy-rsa/easyrsa3/* /etc/openvpn/server/easy-rsa
# mv /etc/openvpn/server/easy-rsa/vars.example /etc/openvpn/server/easy-rsa/vars
Опишем заранее ряд констант, которые будут использоваться при создании x509-сертификатов, как сервера, так и клиентов:
# vi /etc/openvpn/server/easy-rsa/vars
....
set_var EASYRSA_REQ_COUNTRY "RU"
set_var EASYRSA_REQ_PROVINCE "Krasnoyarsk"
set_var EASYRSA_REQ_CITY "Krasnoyarsk"
set_var EASYRSA_REQ_ORG "Company Name"
set_var EASYRSA_REQ_OU "IT"
....
# Задаём срок действия корневого сертификата в десять лет
set_var EASYRSA_CA_EXPIRE 3650
....
# Задаём срок действия сертификатов сервера и клиентов в десять лет
set_var EASYRSA_CERT_EXPIRE 3650
....
set_var EASYRSA_REQ_COUNTRY "RU"
set_var EASYRSA_REQ_PROVINCE "Krasnoyarsk"
set_var EASYRSA_REQ_CITY "Krasnoyarsk"
set_var EASYRSA_REQ_ORG "Company Name"
set_var EASYRSA_REQ_OU "IT"
....
# Задаём срок действия корневого сертификата в десять лет
set_var EASYRSA_CA_EXPIRE 3650
....
# Задаём срок действия сертификатов сервера и клиентов в десять лет
set_var EASYRSA_CERT_EXPIRE 3650
....
Зачищаем место для работы (внимательно с этим - удаляются все ранее созданные сертификаты в файловой иерархии "./easy-rsa/") и генерируем первичный корневой "самоподписанный" сертификат:
# cd /etc/openvpn/server/easy-rsa
# ./easyrsa init-pki
# ./easyrsa build-ca nopass
# ./easyrsa init-pki
# ./easyrsa build-ca nopass
Common Name (eg: your user, host, or server name) [Easy-RSA CA]: Self-signed CA certificat for OpenVPN Server
Проверим срок действия и вообще соответствие ожиданиям публичной части корневого сертификата:
# openssl x509 -noout -text -in /etc/openvpn/server/easy-rsa/pki/ca.crt | less
Далее для работы нам понадобится только публичная часть "самоподписанного" корневого сертификата "./pki/ca.crt", а секретный ключ "./pki/private/ca.key" будет использоваться исключительно скриптом "EasyRSA" для создания новых сертификатов и отзыва старых или скомпрометированных.
Заранее заготовим файл для перечня отозванных сертификатов:
# cd /etc/openvpn/server/easy-rsa
# ./easyrsa gen-crl
# ./easyrsa gen-crl
Закрываем доступ посторонним в директорию с сертификатами:
# chown -R root:root /etc/openvpn/server/easy-rsa
# chmod -R go-rwx /etc/openvpn/server/easy-rsa
# chmod -R go-rwx /etc/openvpn/server/easy-rsa
Создание SSL-сертификата для сервера "OpenVPN".
Если делать всё правильно, с выносом секретной части "корневого" сертификата отдельно от VPN-сервера, то для создания подписанного сертификата понадобиться пройти путь создания приватного клуча и CSR-запроса ("easyrsa gen-req"), перемещения запроса в систему с корневым сертификатом ("easyrsa import-req"), создания там сертификата на основе запроса ("easyrsa sign-req"), и перемещение итогового файла на VPN-сервер.
Но, кто так делает, изначально пойдя по самому лёгкому пути с использованием "EasyRSA"? Для VPN-сервиса с количеством пользователей в пару десятков - никто, наверное. Потому, одной командой прогоняем всю цепочку операций создания условно серверного сертификата:
# cd /etc/openvpn/server/easy-rsa
# ./easyrsa build-server-full ovpn.example.net nopass
# ./easyrsa build-server-full ovpn.example.net nopass
Просмотр содержимого полученного сертификата - всех трёх его компонентов:
# openssl rsa -noout -text -in ./pki/private/ovpn.example.net.key | less
# openssl req -noout -text -in ./pki/reqs/ovpn.example.net.req | less
# openssl x509 -noout -text -in ./pki/issued/ovpn.example.net.crt | less
# openssl req -noout -text -in ./pki/reqs/ovpn.example.net.req | less
# openssl x509 -noout -text -in ./pki/issued/ovpn.example.net.crt | less
Кроме SSL-сертификата серверу "OpenVPN" ещё понадобится служебный файл параметров "Диффи-Хэлмана", предназначающийся для обеспечения более надёжного шифрования соединения сервера и клиента:
# openssl dhparam -out /etc/openvpn/server/easy-rsa/pki/dhparam.key 2048
Также создаем служебный файл статического ключа "HMAC", обеспечивающего первичную простейшую аутентификацию как дополнительную защиту от DDoS атак:
# openvpn --genkey --secret /etc/openvpn/server/easy-rsa/pki/ta.key
Клиентскими сертификатами займёмся позже, а пока попробуем запустить сам сервер "OpenVPN".
Настройка и запуск сервера "OpenVPN".
Воспользуемся предоставленным разработчиками шаблоном конфигурационного файла "OpenVPN":
# cp /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz /etc/openvpn/
# gunzip /etc/openvpn/server.conf.gz
# gunzip /etc/openvpn/server.conf.gz
# vi /etc/openvpn/server.conf
# Задаём режим работы приложения
mode server
tls-server
# Включаем VPN-сервер в режим работы маршрутизатора (Layer 3)
# (явно задаём имя используемого виртуального сетевого интерфейса,
# это пригодится для чёткого описания правил защитного экрана):
dev tun0
# Включаем режим выделения клиентам адресов с маской "/30"
# (на серверах после "v2.1" можно выделять подсеть "/32", но тогда нереализуемы многосетевые схемы):
topology net30
# Принимаем подключения отовсюду:
local 0.0.0.0
# Указываем протокол и порт, на котором VPN-сервер будет принимать подключения
# (намеренно используем порт "для сайтов", чтобы дать клиентам возможность проходить
# из зашоренных корпоративных локальных сетей через защитные экраны и прокси):
proto tcp-server
port 443
# Указываем месторасположение SSL-сертификатов и ключей сервера:
ca /etc/openvpn/server/easy-rsa/pki/ca.crt
tls-auth /etc/openvpn/server/easy-rsa/pki/ta.key 0
dh /etc/openvpn/server/easy-rsa/pki/dhparam.key
cert /etc/openvpn/server/easy-rsa/pki/issued/ovpn.example.net.crt
key /etc/openvpn/server/easy-rsa/pki/private/ovpn.example.net.key
# Указываем месторасположение списка отозванных сертификатов:
crl-verify /etc/openvpn/server/easy-rsa/pki/crl.pem
# Включаем шифрование чуть более высокого относительно стандартного уровня:
cipher AES-256-CBC
# Включаем сжатие трафика между сервером и клиентом:
comp-lzo
# Указываем серверу поддерживать связь с клиентами путём посылания мини-пакета
# каждые 10 секунд и закрывать соединения, если ответ не пришёл спустя 120 секунд:
keepalive 10 120
# Задаём основной IP-адрес VPN-сервера и обслуживаемый сетевой диапазон
# (из него будут адресоваться подключившиеся клиенты, для которых явно
# не переопределены параметры через CCD; адреса будут выдаваться
# в порядке очерёдности автоматически из имеющихся свободных):
ifconfig 10.20.30.2 10.20.30.1
ifconfig-pool 10.20.30.4 10.20.30.254 255.255.255.0
# Передаём клиентам команды, дополняющие их сетевую конфигурацию
# (маршруты к обслуживаемым VPN-сервером подсетям общего пользования):
push "route 10.10.10.0 255.255.255.0"
# (опционально) Передаём клиенту команду перевести весь его трафик на VPN-соединение
;push "redirect-gateway def1 bypass-dhcp"
# Передаём клиентам команды, дополняющие их сетевую конфигурацию (DNS и опции):
push "dhcp-option DNS 10.10.10.10"
# Передаём клиентам указание проверять соединение каждые 10 секунд и
# перезапускать сессию, если от VPN-сервера нет ответа в течении 60 секунд:
push "ping 10"
push "ping-restart 60"
# Указываем директорию с клиентскими конфигурациями, переопределяющими параметры "по умолчанию":
client-config-dir /etc/openvpn/server/ccd
# Явно не разрешаем межклиентское взаимодействие:
;client-to-client
# Явно не разрешаем использование разными клиентами одинаковых "Common Name"
# (у нас для каждого клиента генерируется индивидуальный сертификат):
;duplicate-cn
# Указываем месторасположение и режим работы журналов событий:
status /var/lib/openvpn/status.log
log-append /var/log/openvpn/server.log
verb 3
;mute 10
mode server
tls-server
# Включаем VPN-сервер в режим работы маршрутизатора (Layer 3)
# (явно задаём имя используемого виртуального сетевого интерфейса,
# это пригодится для чёткого описания правил защитного экрана):
dev tun0
# Включаем режим выделения клиентам адресов с маской "/30"
# (на серверах после "v2.1" можно выделять подсеть "/32", но тогда нереализуемы многосетевые схемы):
topology net30
# Принимаем подключения отовсюду:
local 0.0.0.0
# Указываем протокол и порт, на котором VPN-сервер будет принимать подключения
# (намеренно используем порт "для сайтов", чтобы дать клиентам возможность проходить
# из зашоренных корпоративных локальных сетей через защитные экраны и прокси):
proto tcp-server
port 443
# Указываем месторасположение SSL-сертификатов и ключей сервера:
ca /etc/openvpn/server/easy-rsa/pki/ca.crt
tls-auth /etc/openvpn/server/easy-rsa/pki/ta.key 0
dh /etc/openvpn/server/easy-rsa/pki/dhparam.key
cert /etc/openvpn/server/easy-rsa/pki/issued/ovpn.example.net.crt
key /etc/openvpn/server/easy-rsa/pki/private/ovpn.example.net.key
# Указываем месторасположение списка отозванных сертификатов:
crl-verify /etc/openvpn/server/easy-rsa/pki/crl.pem
# Включаем шифрование чуть более высокого относительно стандартного уровня:
cipher AES-256-CBC
# Включаем сжатие трафика между сервером и клиентом:
comp-lzo
# Указываем серверу поддерживать связь с клиентами путём посылания мини-пакета
# каждые 10 секунд и закрывать соединения, если ответ не пришёл спустя 120 секунд:
keepalive 10 120
# Задаём основной IP-адрес VPN-сервера и обслуживаемый сетевой диапазон
# (из него будут адресоваться подключившиеся клиенты, для которых явно
# не переопределены параметры через CCD; адреса будут выдаваться
# в порядке очерёдности автоматически из имеющихся свободных):
ifconfig 10.20.30.2 10.20.30.1
ifconfig-pool 10.20.30.4 10.20.30.254 255.255.255.0
# Передаём клиентам команды, дополняющие их сетевую конфигурацию
# (маршруты к обслуживаемым VPN-сервером подсетям общего пользования):
push "route 10.10.10.0 255.255.255.0"
# (опционально) Передаём клиенту команду перевести весь его трафик на VPN-соединение
;push "redirect-gateway def1 bypass-dhcp"
# Передаём клиентам команды, дополняющие их сетевую конфигурацию (DNS и опции):
push "dhcp-option DNS 10.10.10.10"
# Передаём клиентам указание проверять соединение каждые 10 секунд и
# перезапускать сессию, если от VPN-сервера нет ответа в течении 60 секунд:
push "ping 10"
push "ping-restart 60"
# Указываем директорию с клиентскими конфигурациями, переопределяющими параметры "по умолчанию":
client-config-dir /etc/openvpn/server/ccd
# Явно не разрешаем межклиентское взаимодействие:
;client-to-client
# Явно не разрешаем использование разными клиентами одинаковых "Common Name"
# (у нас для каждого клиента генерируется индивидуальный сертификат):
;duplicate-cn
# Указываем месторасположение и режим работы журналов событий:
status /var/lib/openvpn/status.log
log-append /var/log/openvpn/server.log
verb 3
;mute 10
Заранее создаём директорию для размещения клиентских конфигураций, переопределяющих глобальные:
# mkdir -p /etc/openvpn/server/ccd
В дистрибутивной поставке для "Linux Debian/Ubuntu" скрипты автоматического запуска "Sys-V/Systemd" принимают на вход сразу все конфигурационные файлы ".conf" в директории "/etc/openvpn", так что обычно достаточно просто запустить или перезапустить сервис.
В "Linux Ubuntu" для "Systemd" наверчена дополнительная конструкция сканирования набора конфигурационных файлов и запуска определённого с указанием имени сервиса, сопоставляемого с именем его конфигурационного файла. В самом простом случае, по умолчанию, имя сервиса будет "server":
# systemctl enable openvpn@server.service
# systemctl start openvpn@server
# systemctl status openvpn@server
# journalctl -xe
# systemctl start openvpn@server
# systemctl status openvpn@server
# journalctl -xe
Если ошибок при запуске сервиса небыло, то проверяем, начал ли сервер "OpenVPN" прослушивать назначенный ему порт:
# netstat -apn | grep openvpn
tcp ... 0 0.0.0.0:443 0.0.0.0:* LISTEN .../openvpn
Если в системе нет других туннельных виртуальных интерфейсов, то "OpenVPN" по умолчанию задействует имя "tun0":
# ip addr show dev tun0
3: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> ...
....
....
# netstat -rn
Destination Gateway Genmask ... Iface
0.0.0.0 10.10.10.1 0.0.0.0 ... ens3
....
10.20.30.0 10.10.30.2 255.255.255.0 ... tun0
10.20.30.2 0.0.0.0 255.255.255.255 ... tun0
0.0.0.0 10.10.10.1 0.0.0.0 ... ens3
....
10.20.30.0 10.10.30.2 255.255.255.0 ... tun0
10.20.30.2 0.0.0.0 255.255.255.255 ... tun0
Если свидетельств успешного запуска сервера посредством "Sys-V/Systemd" не наблюдается, то пробуем сделать это вручную и смотрим сообщения об ошибках в журнале событий:
# openvpn --config /etc/openvpn/server.conf --verb 4
Разрешение пересылки сетевых пакетов в несущей системе.
В конфигурации выше мы выбрали режим работы сервера "OpenVPN" в роли виртуального маршрутизатора, терминирующего клиентские подключения. Чтобы пакеты пересылались и далее, в соответствии с уже системной таблицей маршрутизации, потребуется явно включить режим "IP forwarding" для несущей системы:
# vi /etc/sysctl.d/30-ip-forward.conf
# Enable IP forwarding (for OpenVPN)
net.ipv4.ip_forward = 1
net.ipv4.ip_forward = 1
Применяем заготовленную для этапа запуска операционной системы конфигурацию вручную:
# sysctl -p -f /etc/sysctl.d/30-ip-forward.conf
Важно иметь в виду то, что в режиме конфигурации "topology net30" ("Layer 3") сервер "OpenVPN" эмулирует работу маршрутизатора, к портам которого подключены как сам сервер, так и его клиенты. При этом, каждому подключению выделяется, из описанного нами выше в конфигурационном файле диапазона, по четыре IP-адреса (подсеть /30, ограничиваемая маской 255.255.255.252), где (например):
"10.20.30.0" - адрес подсети 10.20.30.0/30;
"10.20.30.1" - адрес виртуального порта на стороне VPN-сервера;
"10.20.30.2" - адрес виртуального порта на стороне VPN-клиента;
"10.20.30.3" - адрес широковещательный (broadcast).
"10.20.30.1" - адрес виртуального порта на стороне VPN-сервера;
"10.20.30.2" - адрес виртуального порта на стороне VPN-клиента;
"10.20.30.3" - адрес широковещательный (broadcast).
Надо отметить, что непосредственно к портам виртуального маршрутизатора обратиться не получится - в частности, на ICMP-запросы они не отвечают.
Начиная с "OpenVPN v2.1" появилась поддержка топологии "subnet" (), когда сервер и клиент находятся в одной подсети, и выделение IP осуществляется по одному, а не блоками из четырёх - это экономнее. Однако до сих пор не все клиенты этот режим поддерживают, да и логику маршрутизации придётся менять, что не всегда возможно с большим производственным наследием и разномастными подсетями, в которых нужно адресовать подключающихся пользователей.
Наладка ротации журналов событий.
В дистрибутивной поставке "OpenVPN" усечение и ротация журналов событий не предусмотрена. Исправим это:
# vi /etc/logrotate.d/openvpn
/var/log/openvpn/*.log {
weekly
rotate 12
compress
delaycompress
missingok
notifempty
copytruncate
}
weekly
rotate 12
compress
delaycompress
missingok
notifempty
copytruncate
}
Проверяем корректность конфигурации, не воздействуя при этом на файлы журналов:
# logrotate -d /etc/logrotate.d/openvpn
Создание SSL-сертификатов для клиентов "OpenVPN".
Создание SSL-сертификатов для клиентов "OpenVPN" рассматривается в отдельной заметке.
Индивидуальная настройка сетевых параметров клиентов "OpenVPN".
Подготовка CCD-конфигурации для клиентов "OpenVPN" рассматривается в отдельной заметке.