OpenVPN - 2fa через PrivacyIdea
Задача заметки на сегодня продемонстрировать, как можно прикрутить авторизацию в OpenVPN через OTP-токен в приложении Google Authenticator.В качестве OTP-сервера будем использовать открытый сервис PrivacyIdea. Поэтому у вас уже должен быть предварительно настроенный инстанс с PrivacyIdea.
Для интеграции взаимодействия OpenVPN c PrivacyIdea, на стороне сервера OpenVPN собирается radius-плагин. Через этот плагин происходит взаимодействие с сервером Radius, который в свою очередь валидирует пользователей через http-запрос в PrivacyIdea.
Ниже представлена схемка взаимосвязи сервисов:
Установка OpenVPN
OpenVPN сервер будет разворачивать на базе Almalinux8, поэтому ставим пакеты - openvpn
и easy-rsa
.
Пакет easy-rsa
нужен нам для создания цепочек сертификатов и упрощения работы выпуска сертификатов.
[root@ovpn ~]# yum install openvpn easy-rsa
В каталоге /usr/share/easy-rsa/3 будет содержаться бинарный файл с утилитой и ее конфиг.
Создадим симлинк на бинарь в каталоге для исполняемых файлов:
[root@ovpn ~]# ln -s /usr/share/easy-rsa/3/easyrsa /usr/local/sbin/easyrsa
Под хранение объектов нашей маленькой PKI инфраструктуры создадим отдельный каталог:
[root@ovpn ~]# mkdir /etc/openvpn/keys
Проваливаемся внутрь этого каталога:
[root@ovpn ~]# cd /etc/openvpn/keys/
Проинициализируем новый PKI инстанс:
[root@ovpn keys]# easyrsa init-pkiinit-pki complete; you may now create a CA or requests.Your newly created PKI dir is: /etc/openvpn/keys/pki
Теперь нужно сгенерить сертификат нашего рутового CA. Что бы упростить процесс создания цепочки ключей в переменные окружение импортнем переменные с объектами сертификата:
[root@ovpn keys]# vi .vars---export KEY_COUNTRY="RU"export KEY_PROVINCE="MOSCOW"export KEY_CITY="MOSCOW"export KEY_ORG="NIXHUB"export KEY_EMAIL="Этот адрес электронной почты защищён от спам-ботов. У вас должен быть включен JavaScript для просмотра."export KEY_CN="OVPN.NIXHUB.RU"export KEY_OU="ADMINS"export KEY_NAME="ovpn.nixhub.ru"export KEY_ALTNAMES="openvpn.nixhub.ru"
И импортируем переменные в наше окружение:
[root@ovpn keys]# . ./.vars
Далее генерим рутой сертификат:
[root@ovpn keys]# easyrsa build-ca
После запуска утилита запросит password фразу (Passphrase), вводим ее. В запрос ввода Common Name я указываю имя vpn-сервера.
Теперь сгенерим ключ Диффи-Хеллмана:
[root@ovpn keys]# easyrsa gen-dh
Для выпуска сертификата vpn-сервера сначала нужно сгенерить для него запрос на выпуск сертификата:
[root@ovpn keys]# easyrsa gen-req ovpn-server nopass
В запросе ввода Common Name опционально указываем имя нашего vpn-сервера.
Подписываем запрос и выпускаем сертификат:
[root@ovpn keys]# easyrsa sign-req server ovpn-server
В процессе выполнения утилита запросит подтвердить выпуск сертификата:
Confirm request details: yes
Далее будет представлено окно для ввода секретной фразы ключа, которую мы указывали при создании корневого сертификата. Указываем ее и жмем enter.
Создадим дополнительный сертификат для усиления безопасности, который будет использоваться для TLS Control channel.:
[root@ovpn keys]# openvpn --genkey --secret /etc/openvpn/server/tc.key
По итогу мы получаем базовый состав объектов, необходимых для работы openvpn-сервера:
pki/ca.crt
- Публичный ключ нашего CA, им можно делиться с нашими клиентами;pki/private/ca.key
- Закрытый ключ нашего CA, ни с кем не делимся им;pki/dh.pem
- ключ Диффи Хелмана;pki/issued/ovpn-server.crt
- открытый сертификат для нашего vpn-сервера;pki/private/ovpn-server.key
- закрый ключ от сертфиката vpn-сервера.
Настройка сервера почти завершена, остается только написать конфиг vpn-сервера:
[root@ovpn ~]# vim /etc/openvpn/server/server.conf---port 59182proto udpdev tunca /etc/openvpn/keys/pki/ca.crtcert /etc/openvpn/keys/pki/issued/ovpn-server.crtkey /etc/openvpn/keys/pki/private/ovpn-server.keydh /etc/openvpn/keys/pki/dh.pemauth SHA256cipher AES-256-CBCtls-version-min 1.2tls-crypt /etc/openvpn/server/tc.keyserver 10.8.1.0 255.255.255.0route 10.8.2.0 255.255.255.0client-to-clientkeepalive 10 120comp-lzoexplicit-exit-notify 1persist-keypersist-tunstatus /var/log/openvpn/openvpn-status.loglog /var/log/openvpn/openvpn.loguser nobodygroup nobodyverb 3
Конфигурационный файл содержит директивы:
port
- в значение указывается порт, на котором слушает сервер;proto
- используемый протокол - tcp/udp;ca/cert/key/dh
- в значении этих директив указываются соответствующие сертификаты;auth
- тип алгоритма шифрования;cipher
- тип алгоритма шифрования данных, передаваемых через vpn;tls-version-min
- указывается минимальная используемая версия;tls-crypt
- ключ шифрования TLS control channel;server
- тут в формате указывается подсеть туннеля;route
- тут в аналогичном формате - указывается маршрут к подсети, к которой будем ходить из под vpn.client-to-client
- эта опция разрешает взаимодействие клиентов, друг с другом;
Создаем каталог под хранение логов:
[root@ovpn]# mkdir /var/log/openvpn
И открываем порт на фаерволе:
[root@ovpn keys]# firewall-cmd --add-port=59182/udp --permanent[root@ovpn keys]# firewall-cmd --reload
Ну и запускаем openvpn-сервер:
[root@ovpn]# systemctl enable --now openvpn-server@server
На данном этапе настройка сервера завершена, теперь можем сгенерить сертификаты и vpn-конфигу для проверки подключения.
С одного не мало известного сисадминского сайта я стянул скриптик, который автоматом генерит сертификаты и клиентский конфиг и немного изменил его подправив пути к файлам и папкам.
В виме открываем новым файл и вставляем в него содержимое:
#!/bin/bashproto="udp"port="59182"server="ovpn.nixhub.ru"confdir="/etc/openvpn/client"echo -n "Enter user name: "read userecho "Protect the private key with a password?"echo " 1) No, passwordless client"echo " 2) Yes, use a password for the client"until [[ $pass =~ ^[1-2]$ ]]; do read -rp "Select an option [1-2]: " -e passdoneclientexist=$(tail -n +2 /etc/openvpn/keys/pki/index.txt | grep -c -E "/CN=$user\$") if [[ $clientexist == ‘1’ ]]; then echo "" echo "The specified client name was already found in easy-rsa" exit else cd /etc/openvpn/keys/ || return case $pass in 1) easyrsa build-client-full "$user" nopass ;; 2) easyrsa build-client-full "$user" ;; esac echo "Client $user added." fitouch /etc/openvpn/ccd/$usermkdir -p $confdirecho "dev tunproto $protoremote $server $portclientresolv-retry infiniteremote-cert-tls serverauth SHA256cipher AES-256-CBCpersist-keypersist-tunresolv-retry infinitenobindcomp-lzoverb 3" > $confdir/$user.ovpn{ echo "<ca>" cat "/etc/openvpn/keys/pki/ca.crt" echo "</ca>" echo "<cert>" awk ‘/BEGIN/,/END/’ "/etc/openvpn/keys/pki/issued/$user.crt" echo "</cert>" echo "<key>" cat "/etc/openvpn/keys/pki/private/$user.key" echo "</key>" echo "<tls-crypt>" cat "/etc/openvpn/server/tc.key" echo "</tls-crypt>"} >> $confdir/$user.ovpn
Обратите внимание на список переменных в начале этого сценария. Под вашу среду, нужно будет указать имя сервера и порт.
Сохраняемся и выходим.
Делаем скрипт исполняемым:
[root@ovpn]# chmod +x /etc/openvpn/add_vpn_user.sh
И на последок, прежде чем запустить скрипт. Нам осталось создать каталог, в котором будут храниться конфиги наших клиентов:
[root@ovpn]# mkdir /etc/openvpn/client/
Ну и запускаем скриптец:
[root@ovpn openvpn]# ./add_vpn_user.sh
После запуска, по условию этого скриптика у нас попросят ввести имя пользователя, и выбрать действие которое добавляет секретный ключ. Ну и последним, нужно будет ввести phrase от рутового CA.
Готовая конфига будет лежать в каталоге - /etc/openvpn/client
. Берем ее, и переносим на устройство нашего клиента. Затем пробуем подключится.
Настройка Radius-плагина
К сожалению, готового билда я не нашел. Единственный выход это самостоятельная сборка. Для сборки требуется предварительно поставить пакет libgcrypt
/libgcript-devel
:
[root@ovpn openvpn]# yum install libgcrypt libgcrypt-devel gcc-c++ make
Затем с гитхаба качаем исходники:
[root@ovpn openvpn]# cd /tmp[root@ovpn tmp]# wget https://github.com/ValdikSS/openvpn-radiusplugin/archive/refs/tags/v2.2.tar.gz
Распаковываем архив:
[root@ovpn tmp]# tar -zxvf v2.2.tar.gz
Переходим в каталог с исходниками и запускаем сборку:
[root@ovpn tmp]# cd openvpn-radiusplugin-2.2[root@ovpn openvpn-radiusplugin-2.2]# make
Плагин собирается буквально за 3 минуты. Далее готовый исходник либы и конфигу плагина, закидываем в каталог - /etc/openvpn/
:
[root@ovpn openvpn-radiusplugin-2.2]# cp radiusplugin.so /etc/openvpn/[root@ovpn openvpn-radiusplugin-2.2]# cp radiusplugin.cnf /etc/openvpn/
Теперь нужно перенастроить работу openvpn–сервера на использование плагина. Открываем конфиг и добавляем:
[root@ovpn openvpn-radiusplugin-2.2]# vim /etc/openvpn/server/server.conf---plugin /etc/openvpn/radiusplugin.so /etc/openvpn/radiusplugin.cnf
Настраиваем конфиг плагина:
[root@ovpn openvpn-radiusplugin-2.2]# vim /etc/openvpn/radiusplugin.cnf---...NAS-IP-Address=10.8.5.10 ...OpenVPNConfig=/etc/openvpn/server/server.conf...nonfatalaccounting=trueserver{ acctport=1813 authport=1812 name=10.8.5.45 retry=1 wait=5 sharedsecret=PASSWORD}
В этом конфиге важные для нас параметры:
NAS-IP-Address
- в значении указывается ip адрес радиус-клиента;OpenVPNConfig
- тут прописывается путь к конфигу openvpn-сервера;nonfatalaccounting
- значениеtrue
, включает игнорирование ошибок при radius accounting. В нашем случаи accounting не нужен;server
- в этом блоке описываются параметры подключения к радиус-серверу;acctport
- тут указывается порт, для accounting событий (но в нашем случаи можно упустить);authport
- тут указывается порт сервера для авторизацииname
- ip адрес сервераwait/retry
- опции указывающие количество повторных запросов на radius сервер. И время ожидания;sharedsecret
- пароль для подключения клиента.
Сохраняемся и перезапускаем openvpn-сервер:
[root@ovpn openvpn-radiusplugin-2.2]# systemctl restart openvpn-server@server
На данном этапе идем на радиус сервер, который крутиться на том же серваке что и сервис PrivacyIdea.
На сервере редактируем файл с клиентами:
[root@mfa01 ~]# vim /etc/raddb/clients.conf---client OpenVPN1 { ipaddr = 10.8.5.10 # OpenVPN Server tablets netmask = 32 secret = ‘PASSWORD’ #shared secret}
И перезапускаем radius-сервер:
[root@mfa01 ~]# systemctl restart radiusd
На этом все, теперь остается только в конфигу клиента добавить опцию:
auth-user-pass
После добавления этой опции, при подключении у пользователя будет отображаться окно с вводом otp-кода. Также не забываем в скриптец add_vpn_user.sh
тоже добавить эту директиру.
Тестируем связку
Подключаемся в WebUI PrivacyIdea и создаем новый токен для тестового пользователя:
Полученный qr-code сканируем в приложении google-authenticator.
Далее создаем новый клиентский конфиг для тестового пользователя. Напомню конфиг генерим через ранее предоставленный мной скриптец:
[root@ovpn ~]# cd /etc/openvpn/[root@ovpn openvpn]# ./add_vpn_user.shEnter user name: testtest
Полученный конфиг переносим на клиентское устройство, затем добавляем новый профиль в openvpn-клиенте:
В созданном профиле указываем логин тестового пользователя и жмем на кнопку подключиться:
В окне ввода пароля вводим пинкод+код из приложения Google Authenticator:
После ввода пина, мы подключаемся:
В аудит логах на стороне PrivacyIdea, будут события об успешности авторизации пользователя:
Если мы удаляем токен пользователя или блокируем, то доступ к vpn у пользователя закрывается. Что полезно..