Привет всем,
Думаю многие уже пробовали OpenVPN в своих приватных корпоративных сетях. Задача заметки на сегодня продемонстрировать, как можно прикрутить авторизацию в 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-pki
init-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="ADMIN@NIXHUB.RU"
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 59182
proto udp
dev tun
ca /etc/openvpn/keys/pki/ca.crt
cert /etc/openvpn/keys/pki/issued/ovpn-server.crt
key /etc/openvpn/keys/pki/private/ovpn-server.key
dh /etc/openvpn/keys/pki/dh.pem
auth SHA256
cipher AES-256-CBC
tls-version-min 1.2
tls-crypt /etc/openvpn/server/tc.key
server 10.8.1.0 255.255.255.0
route 10.8.2.0 255.255.255.0
client-to-client
keepalive 10 120
comp-lzo
explicit-exit-notify 1
persist-key
persist-tun
status /var/log/openvpn/openvpn-status.log
log /var/log/openvpn/openvpn.log
user nobody
group nobody
verb 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/bash
proto="udp"
port="59182"
server="ovpn.nixhub.ru"
confdir="/etc/openvpn/client"
echo -n "Enter user name: "
read user
echo "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 pass
done
clientexist=$(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."
fi
touch /etc/openvpn/ccd/$user
mkdir -p $confdir
echo "dev tun
proto $proto
remote $server $port
client
resolv-retry infinite
remote-cert-tls server
auth SHA256
cipher AES-256-CBC
persist-key
persist-tun
resolv-retry infinite
nobind
comp-lzo
verb 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=true
server
{
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.sh
Enter user name: testtest
Полученный конфиг переносим на клиентское устройство, затем добавляем новый профиль в openvpn-клиенте:
В созданном профиле указываем логин тестового пользователя и жмем на кнопку подключиться:
В окне ввода пароля вводим пинкод+код из приложения Google Authenticator:
После ввода пина, мы подключаемся:
В аудит логах на стороне PrivacyIdea, будут события об успешности авторизации пользователя:
Если мы удаляем токен пользователя или блокируем, то доступ к vpn у пользователя закрывается. Что полезно..