Разработка собственного модуля авторизации для OpenVPN


Разработка на языке Python 3 (для web-приложений используем Django Framework) Сложные сетевые решения (VPN/Routing и т.п.) VPN-технологии для объединения офисов и обхода блокировок Мое портфолио, сертификаты и разработки
auth-user-pass cv gita gita-dev.ru openvpn pass password user username-as-common-name x509
 
 

* В этом блоге я описываю свою повседневную рабочую практику, поэтому все статьи в блоге написаны лично мной и при копировании их на свой сайт пожалуйста указывайте ссылку на страницу откуда вы скопировали.
* Если какая-то статья вам помогла, то вы можете дать мне немного денег вместо простого спасибо (ссылка на форму поддержки проекта внизу страницы), если вы что-то не поняли или у вас что-то не получается, то вы можете нанять меня и я вам все подробно расскажу (расценки и ссылки в конце статьи).


(последние правки 3 недели, 6 дней)

Как вы наверное знаете помимо стандартной авторизации по ключам и сертификатам вы можете дополнительно использовать парольную защиту как дополняющий механизм к модели сертификатов или полностью перейти исключительно на парольную авторизацию. Стоит отметить, что защищенность OpenVPN с авторизацией с использованием Login/Password будет гораздо выше чем использование механизмов PPTP например.

Если вы интересовались вопросами настройки авторизации в OpenVPN, то вы наверное обращали внимание, что все статьи описывающие авторизацию с использованием например PAM относятся к коммерческой реализации OpenVPN-сервера или в редких случаях рассказывается о использовании плагина для интеграции с механизмами OpenLDAP или Windows Active Directory.

Авторизация с использованием логин-пароль в OpenVPN

Но, мало кто знает, что мы можем реализовать плагин для OpenVPN на любом скриптовом языке и фактически, нам требуется лишь вернуть требуемый код ответа, правда параметры авторизации скрипту передаются немного нестандартным способом.

Для использования внешнего скрипта проверки авторизации, используется параметр конфигурации auth-user-pass-verify, но этот параметр честно говоря не очень хорошо (от слова совсем никак) не описан в документации и для того, чтобы понять как он работает требуется изучить документацию и исходные коды серверной части OpenVPN.

Для реализации режима проверки авторизации пользователя с использованием внешнего скрипта вам необходимо задать параметр конфигурации:

auth-user-pass-verify /etc/openvpn/chek_auth.py via-file

Соответственно /etc/openvpn/chek_auth.py это скрипт который будет выполнять проверку переданных данных авторизации, а via-file или via-env, это метод которым скрипту будут переданы данные о логине и пароле которые ввел пользователь (через переменные окружения или через временный файл).

Дополнительно, необходимо задать еще два параметра конфигурации:

username-as-common-name
script-security 3

Некоторая теоретическая часть этого процесса стала нам понятна и мы можем переходить к практической часть разработки скрипта внешней авторизации.

Тестовая конфигурация сервера OpenVPN

Для тестирования механизма авторизации мы будем использовать следующую конфигурацию сервера:

port 1194
proto udp
dev tun
ca ca.crt
cert vpn-unlock-01.crt
key vpn-unlock-01.key
dh dh2048.pem
server 10.249.0.0 255.255.0.0
ifconfig-pool-persist ipp.txt
# External auth block
username-as-common-name
script-security 3
auth-user-pass-verify ./check_auth.py via-env
# End of external auth
keepalive 10 60
comp-lzo
persist-key
persist-tun
verb 3

Как вы наверное поняли, параметр script-security задает минимальный уровень безопасности, согласно документации существует 3 уровня безопасности вызываемых из конфигурации скриптов:

0 - Запрещено вызывать внешние скрипты и приложения.

1 - Вызываются стандартные скрипты конфигурации сетевой подсистемы ifconfig, ip, route, или netsh.

2 - Разрешены пользовательские скрипты.

3 - Разрешено передавать параметры авторизации через переменные окружения скрипту (потенциально небезопасно).

Параметр username-as-common-name подменяет механизм передачи CN-имени от сертификата на имя пользователя и сейчас я немного подробнее на этом заострю внимание. Как вы знаете можно задать для каждого клиента в отдельности параметры конфигурации которые описаны в ccd (client config dir) и вот именно в ccd хранятся конфигурационный файлы привязанные к имени сертификата клиента, а в случае использования одинаковых сертификатов, мы получаем одинаковые CN. Так вот как раз этот параметр и привязывает файлы ccd не к имени сертификата а к логину пользователя.

И наконец, самый главный параметр, это auth-user-pass-verify и как я уже говорил, мы передаем ему два доп параметра, первый это собственно скрипт который будет выполнять проверку авторизации, а второй параметр, это режим работы. Если скрипт возвращает код отличный от нуля, то это значит, что подключающийся клиент проверку не прошел.

Для тестирования работоспособности нашей конструкции создадим скрипт проверки авторизации который всегда будет сообщать, что клиент прошел проверку:

#!/usr/bin/python3
import sys

sys.exit(1)

Тестовая конфигурация клиента

Тестовый клиент довольно типовой и отличается от рассмотренных ранее, только параметром auth-user-pass:

client
proto udp
remote 127.0.0.1 1194
dev tun
resolv-retry infinite
nobind
persist-key
persist-tun
ns-cert-type server
script-security 2
comp-lzo
verb 3
auth-user-pass

Вы можете передать параметру auth-user-pass дополнительный суб-параметр "имя файла" где будет указаны логин и пароль пользователя, для того чтобы не вводить их каждый раз в интерактивном режиме, что актуально для серверных реализаций.

Тестирование передаваемых скрипту авторизации OpenVPN параметров

Стенд для тестирования мы подготовили и можем наконец, то проверить какие параметры передаются переменным окружения и как мы можем их использовать, для этого мы модифицируем скрипт проверки авторизации, который у нас сейчас работает в режиме "всегда говори да", для того чтобы он вывел все переменные окружения с которыми он был вызван:

#!/usr/bin/python3
import sys
import os

print ('Check script environment')
print(os.environ)

sys.exit(0)

Теперь запустим наше тестовую среду и проведем тестовую авторизацию с именем пользователя USER-USER-TEST и паролем Passwoed123.

Параметры передаваемые скрипту авторизации OpenVPN

Я честно говоря думал, что там будет передан только логин и пароль, но так даже лучше:

Check script environment
environ({'tls_serial_hex_0': '14', 'X509_1_CN': 'GITA-DEV-RU CA', 'local_port_1': '1194', 'route_gateway_1': '10.249.0.2',
'X509_1_emailAddress': 'anton@gita-dev.ru', 'tls_digest_1': '1c:7d:a4:23:32:c8:c7:93:ac:cc:01:d7:6f:53:01:39:31:76:fb:49',
'daemon_log_redirect': '0', 'X509_0_C': 'RU', 'remote_port_1': '1194', 'daemon_start_time': '1527480067', 'X509_1_OU': 'VPN-ROUTER',
'common_name': 'client-17', 'ifconfig_remote': '10.249.0.2', 'X509_1_ST': 'NSK', 'tun_mtu': '1500', 'untrusted_port': '56283', 
'ifconfig_local': '10.249.0.1', 'route_vpn_gateway': '10.249.0.2', 'tls_serial_1': '16592554913958741180', 'X509_0_ST': 'NSK', 
'X509_1_C': 'RU', 'dev': 'tun0', 'X509_0_CN': 'client-17', 'link_mtu': '1542', 'route_net_gateway': '10.1.1.254', 
'daemon_pid': '22371', 'X509_1_O': 'GITA-DEV-RU', 'verb': '3', 'tls_id_1': 'C=RU, ST=NSK, L=Novosibirsk, O=GITA-DEV-RU, 
OU=VPN-ROUTER, CN=GITA-DEV-RU CA, name=EasyRSA, emailAddress=anton@gita-dev.ru', 'X509_0_O': 'GITA-DEV-RU', 
'tls_serial_0': '20', 'route_netmask_1': '255.255.0.0', 'redirect_gateway': '0', 'X509_1_L': 'Novosibirsk', 'X509_0_OU': 
'VPN-ROUTER', 'dev_type': 'tun', 'username': 'USER-USER-TEST', 'password': 'Password123', 'tls_digest_0': 
'9d:2e:cf:2c:e7:b5:bf:d0:fc:0b:a5:9f:8e:32:84:2a:cd:f8:45:c4', 'tls_id_0': 'C=RU, ST=NSK, L=Novosibirsk, 
O=GITA-DEV-RU, OU=VPN-ROUTER, CN=client-17, name=EasyRSA, emailAddress=anton@gita-dev.ru', 'X509_0_L': 'Novosibirsk', 
'X509_0_name': 'EasyRSA', 'X509_1_name': 'EasyRSA', 'daemon': '0', 'untrusted_ip': '127.0.0.1', 'proto_1': 'udp', 
'X509_0_emailAddress': 'anton@gita-dev.ru', 'script_context': 'init', 'route_network_1': '10.249.0.0', 'tls_serial_hex_1': 
'e6:44:98:c8:7a:ac:44:bc', 'config': './server.conf', 'script_type': 'user-pass-verify'})

Настройка проверки переданных логина и пароля

Как вы видите из примера нам переданы логин и пароль которые ввел пользователь, причем в виде plain-text и мы можем их использовать для сверки с известными нам данными, например сделать запрос к базе данных и сверить переданный пароль с хэшем который у нас имеется в базе данных. Все ограничено лишь вашей фантазией и вы можете строить самые разные механизмы авторизации для OpenVPN более уже без искусственных ограничений.

#!/usr/bin/python3
import sys
import os

if os.environ['username']=='USER1':
        if os.environ['password']=='PASSWORD1':
                sys.exit(0)
        else:
                sys.exit(1)
else:
        sys.exit(1)

Выше я привел пример простого скрипта который разрешает доступ для пользователя:

  • login: USER1
  • password: PASSWORD1

Ну и конечно, вы можете использовать любой скриптовый язык для этих целей, а не только Python.

Моя официальная страница на FaceBook
Мой микроблог в твиттер

Как сделать Double VPN - Подробная инструкция

Как сделать Double VPN - Подробная инструкция

В мире анонимайзеров нововведение, - Double VPN. Основной особенностью его является то, что сервер к которому мы подключаемся и сервер точкой выхода которого будет исходящий трафик, это два разных сервера, причем желательно расположенные в разных странах. Особой сложности реализация такого механизма не представляет, хотя некоторые интересные моменты там есть. Типовая схема реализации маршрутизации трафика через OpenVPN сервер использует механизм NAT и собственно сам OpenVPN в режиме изменения основного шлюза. В этом случае весь трафик клиента перенаправляется на сервер OpenVPN, где уже направляется далее в сеть Internet с подменой адреса источника.


OpenVPN-сеть для LXD-кластера без назначения адресов клиентов (использование стороннего DHCP для управления клиентами VPN-сети)

OpenVPN-сеть для LXD-кластера без назначения адресов клиентов (использование стороннего DHCP для управления клиентами VPN-сети)

Представляю вашему вниманию небольшой экскурс в активно используемую мной технологию построения распределенных виртуальных сетей на базе OpenVPN в немного непривычной реализации. Если вы работаете с OpenVPN технологиями, то наверное обратили внимание что практически все руководства описывают OpenVPN сеть где OpenVPN-сервер выступет в качестве DHCP-сервера и назначает адреса для своих клиентов, но я сегодня хотел бы предложить вам уйти от типовых реализаций.


Как вы наверное понимаете, бесплатно сейчас работать никто не будет и если ответ на ваш вопрос потребует больше трех минут времени и вам требуется полноценная консультация, то расценки на мои услуги представленны ниже.


Есть вопросы?
Спрашивайте и я обязательно вам отвечу!

* Поля обязательные для заполнения .