Глава 7. Скрипты и плагины
После развертывания персональная или корпоративная VPN может стать мощным инструментом как с точки зрения безопасности, так и с точки зрения функциональности. Хорошо спроектированная VPN позволит пользователям безопасно подключаться к удаленным ресурсам. Иногда, однако, просто иметь VPN недостаточно. Данное приложение может требовать более строгих стандартов безопасности или требовать лучшего мониторинга и контроля.
Интеграция плагинов и сценариев с OpenVPN может решить многие из этих организационных или функциональных потребностей. В этой главе будет продемонстрировано как плагины можно использовать для улучшения аутентификации и как скрипты могут отслеживать соединения, генерировать таблицы маршрутизации и многое другое.
Скриптинг
Скрипты, вероятно, один из лучших инструментов, доступных для администратора OpenVPN. Имея возможность назначать как клиентские, так и серверные скрипты, OpenVPN может инициировать другие ответы системы, открывая брандмауэры, запуская приложения или даже отправляя сообщение администратору.
Одним важным предупреждением при написании скриптов является время, необходимое для завершения сценария. OpenVPN - это однопоточный процесс, что означает, что во время работы скрипта вся VPN блокируется для всех подключенных или подключающихся клиентов. Скрипт медленной аутентификации может нанести вред хорошо работающему VPN. Плагины меньше подвержены этому влиянию, так как работают в отдельном потоке.
Начиная с версии 2.3.6 OpenVPN поддерживает 13 параметров скриптов на стороне сервера и 10 параметров на стороне клиента. Команды со звездочками являются параметрами настройки и позволяют следующим параметрам выполнять определенные действия. Серверные скрипты выглядят следующим образом (в порядке выполнения):
--setenv*
--setenv-safe*
--script-security*
--up-restart*
--up
--route-up
--tls-verify
--auth-user-pass-verify
--client-connect
--learn-address
--client-disconnect
--route-pre-down
--down
На стороне клиента сценарии выглядят следующим образом (в порядке выполнения):
--setenv*
--script-security*
--up-restart*
--tls-verify
--ipchange
--setenv-safe*
--up
--route-up
--route-pre-down
--down
Теперь мы кратко рассмотрим все эти параметры, объяснив их функции как на стороне сервера, так и на стороне клиента. Далее в этой главе мы предоставим подробный пример и обсудим поведение и тонкости каждого из этих сценариев.
Серверные скрипты
Давайте посмотрим на сценарии, используемые на стороне сервера.
–setenv и –setenv-safe
Параметры setenv
и setenv-safe
используются для установки переменных среды, которые могут использоваться как скриптами, так и плагинами. Опция setenv
позволяет нам устанавливать практически любые переменные окружения, но эту опцию нельзя “передать” клиентам. Опция setenv-safe
добавляет к каждой переменной среды префикс OPENVPN_
, избегая конфликтов с системными переменными среды, такими как PATH
и LD_LIBRARY_PATH
. Эта опция может быть передана клиентам, что обеспечивает большую гибкость.
–script-security
Опция script-security
определяет какие типы приложений или скриптов могут быть выполнены из конфигурации OpenVPN. Существует четыре варианта уровней безопасности:
- 0 : означает, что никакие внешние скрипты или программы не разрешены. На компьютере с Linux/Unix это приводит к тому, что OpenVPN не работает, поскольку OpenVPN всегда нужно запускать некоторые внешние команды для установки IP-адреса. На клиентах Windows, однако, допускается работа OpenVPN в этом режиме, при условии, что шлюз по умолчанию не изменен. Для этого необходимо вызвать внешнее приложение.
- 1 : означает, что разрешены определенные встроенные исполняемые файлы, например,
ip
,route
,ifconfig
и другие. Это по умолчанию. - 2 : наиболее часто требуемый уровень безопасности. Он позволяет использовать не только встроенные команды, подобные перечисленным в предыдущем пункте, но и пользовательские сценарии.
- 3 : позволяет паролям передаваться в вызываемые скрипты через переменные окружения. Это может быть небезопасно, но полезно для определенных сценариев аутентификации или даже операций смены пароля.
–up-restart
Опция up-restart
- это просто флаг, который можно установить. Если этот флаг установлен, то при перезапуске OpenVPN вызываются оба сценария: down
и up
(в указанном порядке).
–up
Сценарий up
- это первый скрипт, выполняемый после того, как OpenVPN выполнил свою первоначальную инициализацию. Обычно этот сценарий запускается сразу после того, как OpenVPN привязал себя к настроенному сетевому порту и коснулся открытия устройства TUN или TAP. На данный момент в процессе запуска ни один клиент не подключен к серверу и авторизация еще не состоялась. Некоторые люди используют сценарии up
для инициализации прокси-серверов и/или правил брандмауэра.
–route-up
После того, как устройство TUN или TAP было открыто, выполняется скрипт маршрутизации для настройки любых системных маршрутов на стороне сервера.
–tls-verify
Всякий раз, когда клиент подключается к серверу, первым сценарием, который будет выполняться как на клиенте, так и на сервере, является сценарий tls-verify
. Этот сценарий вызывается несколько раз, по одному разу для каждого сертификата, который клиент предоставляет серверу. На этом этапе удаленный узел все еще считается ненадежным. Это можно использовать для проверки информации о сертификате клиента или сервера до проверки подлинности. Если скрипт tls-verify
возвращает ненулевой код выхода, клиентское соединение отклоняется.
–auth-user-pass-verify
Помимо относительно простой аутентификации клиентского SSL-сертификата, OpenVPN поддерживает довольно надежный набор инструментов для аутентификации по имени пользователя и паролю. Этот аргумент принимает два аргумента: команду и ее метод. Метод определяет, как OpenVPN передает учетные данные аутентификации команде. Метод может быть как via-env
, так и via-file
. Чтобы использовать опцию via-env
для поддержки скрипта необходимо установить третий (3) параметр безопасности скрипта. Если скрипт auth-user-pass-verify
возвращает ненулевой код завершения, клиентское соединение отклоняется.
Важно знать, что сценарий auth-user-pass-verify
также выполняется всякий раз, когда клиент перезапускается или ему необходимо пересмотреть параметры безопасности с сервером. Повторное согласование ключей безопасности обычно происходит каждый час, но им можно управлять с помощью параметров reneg-sec
, reneg-pkts
и reneg-bytes
.
–client-connect
Выполняется после аутентификации клиента на VPN-сервере. Большинство сценариев чаще всего запускаются здесь. Скрипт client-connect
передает один аргумент, который является именем временного файла. После завершения сценария файл обрабатывается OpenVPN и все содержимое анализируется как дополнительные параметры конфигурации. Это позволяет администратору добавлять специальные настройки для конкретного клиента, обеспечивая большую гибкость, чем файл CCD. Один из наших примеров в этой главе использует сценарий подключения клиента для обновления базы данных, используемой для отслеживания и направления статистики VPN-подключений.
–learn-address
Сценарий learn-Address
позволяет OpenVPN помогать определять правила брандмауэра и другие специфичные для адреса опции. Он выполняется всякий раз, когда новый клиент добавляется, обновляется или удаляется из внутренних таблиц адресов OpenVPN. Более подробная информация доступна на странице руководства. Эта опция поддерживает как IPv4, так и IPv6. Сценарий изучения адреса фактически вызывается отдельно для адресов IPv4 и IPv6 один раз с адресом IPv4 в качестве основного параметра и один раз с адресом IPv6.
–client-disconnect
Как и в случае сценария client-connect
в предыдущем разделе, сценарий client-disconnect
является вторым наиболее часто используемым сценарием соединения. Как упоминалось ранее, в одном из примеров в этой главе client-disconnect
клиента будет использоваться для обновления записей базы данных статистикой использования и другой информацией.
–route-pre-down
Когда началось отключение туннеля, запускается сценарий route-pre-down
. Его можно использовать для автоматизации отключения удаленных прокси-серверов и закрытия дыр в брандмауэре, которые были открыты/установлены ранее в сценарии --up
.
–down
В противоположность опции up
, опция down
запускает команду после закрытия устройства TUN/TAP. Эта опция принимает команду или скрипт в качестве аргумента, а дополнительные аргументы передаются скрипту или команде. Если вам нужно выполнить команду до закрытия устройства TUN/TAP - вы можете использовать опцию down-pre
.
Заметка
Нет способа запустить скрипт как до, так и после закрытия устройства TUN/TAP.
Клиентские скрипты
Мы обсудим клиентские скрипты в этом разделе.
–setenv и –setenv-safe
Действуют точно так же, как в предыдущем разделе Серверные скрипты.
–script-security
Действует точно так же, как в предыдущем разделе Серверные скрипты.
–up-restart
Опция up-restart
- это просто флаг, который можно установить. Если этот флаг установлен, то при перезапуске OpenVPN вызываются оба сценария: down
и up
(в указанном порядке).
–tls-verify
Всякий раз, когда клиент подключается к серверу, первым сценарием, который будет выполняться как на клиенте, так и на сервере, является сценарий tls-verify
. Этот сценарий вызывается несколько раз, по одному разу для каждого сертификата, который сервер представляет клиенту. На этом этапе удаленный узел все еще считается ненадежным. Его можно использовать для проверки информации о сертификате клиента или сервера до проверки подлинности. Если скрипт tls-verify
возвращает ненулевой код выхода, клиентское соединение отклоняется.
–ipchange
На стороне клиента ipchange
после выполнения скрипта tls-verify
, а также при любом изменении удаленного (также известного как доверенный) IP-адреса. Его можно использовать для обновления правил брандмауэра или прокси-сервера перед открытием адаптера TUN/TAP.
–up
Сценарий up
является первым сценарием, который выполняется после завершения аутентификации клиента. После того как сервер успешно аутентифицировал клиента, клиенту отправляется набор параметров конфигурации. Эти параметры включают IP-адрес VPN для использования, а также любые другие параметры, которые передаются клиенту. Некоторые люди используют сценарии up
для инициализации прокси-серверов и/или правил брандмауэра.
–route-up
После проверки подлинности и установления маршрутов выполняется сценарий route-up
. При желании этот сценарий может быть задержан на определенное количество секунд с помощью опции route-delay
.
–route-pre-down
Когда началось отключение туннеля, запускается сценарий route-pre-down
. Он может быть использован для закрытия соединений с удаленными прокси-серверами, другими туннелями (SSH) или исправления записей DNS-сервера.
–down
В противоположность опции up
, опция down
запускает команду после закрытия устройства TUN/TAP. Эта опция принимает команду или скрипт в качестве аргумента, а дополнительные аргументы передаются скрипту или команде. Если вам нужно выполнить команду до закрытия устройства TUN/TAP, вы можете использовать опцию down-pre
.
Заметка
Нет способа запустить скрипт как до, так и после закрытия устройства TUN/TAP.
Примеры серверных скриптов
Сценарии сервера могут быть использованы для значительного расширения развертывания OpenVPN. Скрипты могут использоваться для аутентификации, авторизации, регистрации и многого другого. В сочетании с опциями client-config
, сценарии могут быть далее использованы для генерации директив конфигурации клиента на лету. Например, аутентификация может происходить через LDAP, а правила авторизации могут быть динамическими через тот же каталог LDAP. Правила межсетевого экрана могут быть сгенерированы и применены и маршруты могут быть переданы клиенту. В этом разделе будут продемонстрированы некоторые из этих вещей, чтобы помочь вам в применении этих методов.
Наиболее распространенными серверными сценариями являются сценарии --client-connect
и --client-disconnect
. Эти сценарии могут использоваться для многих целей, включая открытие наборов правил брандмауэра, монтирование файловых систем и даже создание файлов конфигурации клиента на лету.
В сочетании с планировщиком задач другие сценарии могут быть запущены вне прямого контекста OpenVPN, но могут по-прежнему работать с подключенными клиентами через интерфейс управления OpenVPN. Например, администратор может предоставить выделенное время конечным пользователям и отключить пользователей после того, как это выделенное время было исчерпано.
Сценарии подключения клиента
Давайте теперь посмотрим на сценарии подключения клиента.
Аутентификация клиента
Аутентификация - это определение того, кто может подключиться. Это не определяет что могут делать эти пользователи, просто им разрешено подключаться к VPN или нет. На самом базовом уровне вполне возможно разрешить пользователю подключаться, но не позволять этому пользователю фактически что-либо делать. Одним из применений для этого может быть сценарий мониторинга, который просто хочет убедиться, что ваш VPN-сервер работает и аутентифицирует пользователей. Этот псевдопользователь не должен иметь возможность маршрутизировать трафик, поскольку в этом нет необходимости.
Многие переменные и права доступа можно проверить с помощью сценариев аутентификации, включая смарт-карты, серверы LDAP или RADIUS, информацию о сертификатах, списках отзыва сертификатов и многом другом. Если вы читали эту книгу с самого начала, в Главе 5, Расширенные сценарии развертывания в туннельном режиме, вы должны иметь встроенные конфигурации сервера VPN, который уже использует LDAP и другие движки. С помощью сценариев вы можете расширить поддержку этих бекендов без текущего плагина или запросить дополнительные источники.
Наиболее распространенным сценарием на стороне сервера, вероятно, является сценарий --client-connect
. Этот скрипт выполняется после того, как вся проверка TLS прошла. В тех случаях, когда сценарий подключения к клиенту имеет много общего, это идеально для предотвращения атаки типа Denial of Server (DoS), вызванной вашими собственными сценариями. Перед запуском этого сценария клиент был проверен на наличие надлежащего ключа tls-auth
и действительного сертификата. Сценарий client-connect
может использоваться как своего рода предварительная аутентификация, поскольку он выполняется перед сценарием --auth-user-pass-verify
. Он также может быть использован для динамического создания конфигурации клиента.
При использовании сценария убедитесь, что для параметра --script-security
установлено значение 2 или 3 (см. определения ранее в этой главе). Если не указать эту опцию, клиенту будет возвращено сообщение AUTH_FAIL
. В качестве примера мы создали очень простой скрипт, который печатает среду оболочки и завершает работу с нулем (0
), что указывает на успех запуска демона OpenVPN. В нашей конфигурации сервера мы добавили следующие две директивы:
script-security 2
client-connect /usr/local/etc/openvpn/cc.sh
Заметка
Существует переменная окружения script_type
, которая определяет тип вызываемого скрипта. Используя эту переменную, можно иметь один монолитный скрипт для обработки всех вызовов скриптов OpenVPN.
Вот наш пример скрипта client-connect
:
#!/bin/sh
printenv > /tmp/movpn
exit 0
Код выхода важен, поскольку все, кроме нуля (0
), приведет к отключению клиента. С помощью предыдущего скрипта и конфигурации, когда появится новое клиентское соединение, наш скрипт будет выполнен. Этот скрипт разрешает соединение, но печатает среду оболочки во временный файл. Содержимое этого файла интересно и будет применяться ко всем остальным скриптам:
daemon_start_time=1425344172
daemon_pid=4004
local_1=SERVER_IP
trusted_ip=CLIENT_IP
redirect_gateway=0
untrusted_port=1194
tun_mtu=1500
X509_0_ST=Enlightenment
X509_0_CN=client1
X509_0_emailAddress=root@example.org
time_ascii=Mon Mar 2 18:56:17 2015
proto_1=udp
X509_1_emailAddress=root@example.org
tls_id_0=C=ZA, ST=Enlightenment, O=Mastering OpenVPN, CN=client1,
emailAddress=root@example.org
tls_id_1=C=ZA, ST=Enlightenment, L=Overall, O=Mastering OpenVPN,
CN=Mastering OpenVPN, emailAddress=root@example.org
ifconfig_ipv6_local=2001:db8:100::1
untrusted_ip=CLIENT_IP
daemon=1
tls_serial_hex_0=02
trusted_port=1194
dev_type=tun
tls_serial_hex_1=d2:93:32:f0:8e:bc:58:ee
X509_1_ST=Enlightenment
X509_1_CN=Mastering OpenVPN
script_context=init
tls_serial_0=2
PWD=usrlocaletcopenvpn
daemon_log_redirect=1
tls_serial_1=15173527578309581038
ifconfig_local=10.200.0.1
dev=tun0
local_port_1=1194
time_unix=1425344177
link_mtu=1541
remote_port_1=1194
X509_0_C=ZA
tls_digest_0=1b:27:a6:b4:5f:7a:9c:3f:17:fb:ff:33:05:61:3f:2a:56:89:
16:d3
tls_digest_1=e4:f1:43:37:34:51:de:99:7a:dc:e3:6d:f2:4c:5b:84:34:4b:
f3:64
script_type=client-connect
X509_1_C=ZA
ifconfig_broadcast=10.200.0.255
ifconfig_pool_remote_ip=10.200.0.2
ifconfig_ipv6_remote=2001:db8:100::2
ifconfig_ipv6_netbits=64
ifconfig_netmask=255.255.255.0
config=usrlocaletcopenvpn/openvpn.conf
ifconfig_pool_netmask=255.255.255.0
X509_0_O=Mastering OpenVPN
X509_1_L=Overall
verb=4
common_name=client1
X509_1_O=Mastering OpenVPN
Используя эти переменные среды, опытный администратор OpenVPN может настроить конфигурацию в на первый взгляд простой настройке сервера.
Авторизация клиента
Авторизация может происходить в нескольких местах, включая файл client-config-dir
или дополнения могут быть сделаны через скрипт client-connect
.
Заметка
Аутентификация доказывает, кто вы есть. Авторизация определяет, что вам разрешено делать.
Первым аргументом, передаваемым сценарию client-connect
- будет путь к временному файлу, который скрипт может использовать для передачи параметров конфигурации подключающегося клиента демону OpenVPN. Этот скрипт проверяет переменную среды common_name
и, если это client1
- устанавливает отключене в конфигурации клиента:
#!/bin/sh
if [ "$common_name" = "client1" ];
then
echo "disable" >> $1
fi
exit 0
Когда client1
подключается, опция отключения будет передана на сервер, предотвращая продолжение соединения. Могут быть переданы другие параметры, такие как ifconfig
для статических IP-адресов, передача различных маршрутов и многое другое.
Пример 1 - выбранные клиентом маршруты
Рассмотрим сетевого администратора с двумя центрами обработки данных, каждый со своей парой серверов OpenVPN. Был случай, когда необходимо было работать с одним центром обработки данных, при этом гарантируя, что если другой стал недоступен, службы и системы все еще были бы доступны в работающем центре обработки данных.
Чтобы помочь в тестировании, мы создали несколько сценариев (client-connect
и auth-user-pass-verify
), чтобы выбрать, какие маршруты были переданы клиенту.
Следующая диаграмма должна дать приблизительное представление о концепции. У VPN-клиента есть три варианта конфигурации: полные маршруты (полные), маршруты для Data Center 1 (dc1
) и маршруты для Data Center 2 (dc2
). Кроме того, клиент может подключиться к любому центру обработки данных и получить только необходимые маршруты для любого из этих трех.
В нашей схеме client1
подключается к центру обработки данных и запрашивает их имя пользователя и пароль. В действительности мы игнорируем пароль и читаем имя пользователя, чтобы определить желаемые маршруты.
Чтобы зафиксировать выбор маршрута, мы использовали скрипт auth-user-pass-verify
. OpenVPN принимает два аргумента: путь к сценарию и via-file
или via-env
, чтобы определить как передавать учетные данные в скрипт. В этом примере мы выбрали via-file
.
Сценарий считывает учетные данные из скрипта и переписывает его в файл, который будет доступен сценарию подключения клиента:
#!/bin/sh
echo 'head -n1 $1' > \
/tmp/openvpn-${untrusted_ip}-${untrusted_port}.tmp
exit 0
Затем запускается наш скрипт подключения к клиенту, который читает созданный ранее файл .tmp
. На основе прочитанного аргумента он записывает выбор маршрута в файл, переданный client-connect
для аргументов конфигурации:
#!/bin/sh
creds="tmpopenvpn-${untrusted_ip}-${untrusted_port}.tmp"
if [ -f "$creds" ];
then
selected='head -n1 $creds'
if [ "$selected" = "dc1" ];
then
cat >> $1 <<- EOF
push "route 10.10.0.0 255.255.255.0"
push "route 10.10.1.0 255.255.255.0"
EOF
elif [ "$selected" = "dc2" ];
then
cat >> $1 <<- EOF
push "route 10.20.0.0 255.255.255.0"
push "route 10.20.1.0 255.255.255.0"
EOF
else
cat >> $1 <<- EOF
push "route 10.10.0.0 255.255.255.0"
push "route 10.10.1.0 255.255.255.0"
push "route 10.20.0.0 255.255.255.0"
push "route 10.20.1.0 255.255.255.0"
EOF
fi
fi
exit 0
Хотя это и не идеально и на это можно нападать разными способами, это позволило нам создать одну конфигурацию OpenVPN для каждого из системных администраторов и обеспечить им некоторый уровень динамической маршрутизации в зависимости от их задач.
Пример 2 - отслеживать статистику клиентских подключений
Используя скрипты client-connect
и client-disconnect
возможно создавать клиентские записи статистики подключения к базе данных или в другом месте. В этом примере мы просто хотим отслеживать, когда пользователи подключаются и сколько времени они проводят, подключившись к VPN-серверу.
Мы предполагаем, что вы, по крайней мере, знакомы с SQL и поэтому не будем фокусироваться на семантике. SQLite 3 используется в следующем примере для хранения информации о сеансе. Схема для нашего примера базы данных выглядит следующим образом:
CREATE TABLE vpn_session (
session_id integer primary key autoincrement not null,
cn test not null,
connect_time timestamp default CURRENT_TIMESTAMP,
disconnect_time timestamp default null,
vpn_ip4 char(15),
vpn_ip6 char(40),
remote_ip4 char(40),
connection_time integer default 0
);
Схема может быть загружена в базу данных с помощью следующей команды:
ecrist@example:~-> sqlite3 movpn.sqlite3 < file.schema
Подсказка
Каталог и файл, который вы используете для SQLite, должны быть доступны для чтения и записи пользователю OpenVPN. Если в вашем файле конфигурации определены --user
или --group
этому пользователю понадобится этот доступ. Без него, ваши скрипты client-connect
и client-disconnect
не смогут обновить базу данных.
На этот раз, мы собираемся создать скрипт, который будет вызываться как для client-connect
, так и для client-disconnect
. Мы будем обнаруживать и обрабатывать тип сценария в коде. Для типа client-connect
мы собираемся вставить новую запись для нового сеанса. В случае отключения клиента мы обновим эту запись, чтобы обеспечить дальнейший учет.
Код выглядит следующим образом:
#!/bin/sh
DBFILE="/var/openvpn/movpn.sqlite3"
DBBUFFER="/var/openvpn/buffer.sql"
db_query (){
SQL="$1"
/usr/local/bin/sqlite3 $DBFILE "$SQL"
if [ $? -ne 0 ];
then
# There was an error, write the SQL out to a buffer file
echo "$SQL" | tr -d "\t" | tr -d "\n" | tee -a $DBBUFFER
echo ";" | tee -a $DBBUFFER
fi
}
logger "OpenVPN Type: $script_type"
case "$script_type" in
client-connect)
# do record insert
logger "OpenVPN: client-connect"
SQL="
INSERT INTO vpn_session (
cn, connect_time, vpn_ip4,
vpn_ip6, remote_ip4
) VALUES (
'$common_name', '$time_unix',
'$ifconfig_pool_remote_ip',
'$ipconfig_ipv6_remote',
'$untrusted_ip'
)"
db_query "$SQL"
;;
client-disconnect)
# update the record, if it's found
logger "OpenVPN: client-disconnect"
SQL="
UPDATE
vpn_session
SET
disconnect_time = '$time_unix'
WHERE
cn = '$common_name'
AND disconnect_time IS NULL
AND session_id = (
SELECT MAX(session_id)
FROM vpn_session
WHERE cn = '$common_name'
)
"
db_query "$SQL"
;;
esac
exit 0
Этот скрипт использует функцию переключения регистра, чтобы определить тип сценария и вести себя соответственно. При новом клиентском соединении он обновит таблицу базы данных с информацией о соединении и обновит эту запись базы данных, когда клиент отключится. Схема, которую мы здесь использовали, довольно проста и может быть легко расширена для поддержки отслеживания использования полосы пропускания и нескольких клиентских подключений.
Используя команду sqlite3
, мы можем получить три самые последние записи в базе данных:
ecrist@example:/usr/local/etc/openvpn-> sqlite3
/var/openvpn/movpn.sqlite3 "SELECT * FROM vpn_session ORDER BY session_id DESC LIMIT 3"
10|client1|1426430834||10.200.0.2||CLIENT_IP|
9|client1|1426430759|1426430759|10.200.0.2||CLIENT_IP|0
8|client1|1426429888|1426429888|10.200.0.2||CLIENT_IP|0
Пример 3 - отключить пользователя через X минут
Есть несколько способов справиться с этим сценарием. Если вы предоставляете пользователям короткий доступ, скажем, 30 минут за раз, сценарий client-connect
с простым режимом ожидания может выполнить отключение и блокировку учетной записи. Допустим, вы продаете короткие одноразовые сеансы VPN продолжительностью до 30 минут. В этом случае после того, как пользователь достиг 30 минут использования, задание cron
отключит пользователя и заблокирует его учетную запись, используя запись в каталоге CCD.
Этот пример будет основываться на предыдущем примере с использованием базы данных SQLite, которую мы создали для отслеживания используемого времени. Наш скрипт будет иметь несколько задач:
- Рассчитать время подключения VPN
- Блокировка пользователя по истечении выделенного времени подключения
- Отключить клиента, если в он данный момент подключен
Для выполнения предыдущих задач мы напишем небольшой скрипт оболочки, который будет вызываться демоном cron
. Здесь мы проверим информацию о соединении, запросив порт управления и базу данных, которую мы создали в предыдущем примере. Альтернативой запросу порта управления может быть опрос файла журнала состояния OpenVPN и работа с этими данными в режиме реального времени. Один серьезный недостаток для опроса интерфейса управления заключается в том, что он является однопоточным и допускает только одно соединение за раз. Если скрипт зависает или кто-то подключен к интерфейсу, последовательные опросы также будут зависать. Код выглядит следующим образом:
#!/bin/sh
##
Determines if user ($1) has been connected more than $2 seconds
if [ $# -lt 2 ];
then
echo "usage: $0 <user> <time_in_seconds>"
exit 1
fi
USER=$1
TO=$2
# DB seconds
SQL="SELECT SUM(connection_time) FROM vpn_session WHERE cn='$USER'"
DBTIME='/usr/local/bin/sqlite3 /var/openvpn/movpn.sqlite3 "$SQL"'
if [ "$DBTIME" = "" ];
then
DBTIME=0
fi
# Check management port
CTIME='echo "status 2" | nc -N localhost 1194 | grep -E
"CLIENT_LIST.*$USER" | cut -f8 -d,'
if [ "$CTIME" != "" ];
then
# we have an active connection
D='date +"%s"'
CTIME='expr "$D - $CTIME"'
else
CTIME=0
fi
UTIME='expr $DBTIME + $CTIME'
if [ $UTIME -gt $TO ];
then
logger "Disconnecting $USER, activity time exceeded ($UTIME/$TO)."
echo "disable" >> /usr/local/etc/openvpn/ccd/$USER
echo "kill $USER" | nc localhost 1194
fi
Теперь, когда у нас есть скрипт, мы можем вызвать его:
root @ example:~-> timeout.sh client1 1800
Он подсчитает сколько секунд client1
был подключен к VPN. Если время превышает 1800
(или любое другое число, которое вы там указали), оно отключит эту конфигурацию через директорию client-config-directory
и уничтожит все активные сеансы, используя интерфейс управления.
Подсказка
Интерфейс управления OpenVPN допускает только одно соединение за раз. Убедитесь, что ваш скрипт правильно обрабатывает это ограничение.
Примеры клиентских скриптов
Многие сторонние клиентские пакеты OpenVPN интенсивно используют сценарии на стороне клиента для обеспечения надежной интеграции с различными операционными системами. Tunnelblick, первоначально написанный Angelo Laub, использует сценарии на стороне клиента для интеграции настроек DNS сервера OpenVPN с операционной системой Mac OS X.
Моникер “client” для сценариев на стороне клиента может быть немного неправильным. Во многих случаях клиент OpenVPN может фактически быть другим сервером. Возможно, у вас есть несколько разрозненных офисов и вы используете OpenVPN для их подключения. Клиентские сценарии могут использоваться для запуска демона, процесса резервного копирования или других служб, для которых локальная сеть зависит от сеанса OpenVPN.
Клиентские сценарии написаны аналогично серверным и имеют почти идентичный список доступных переменных среды.
Пример 4 - монтирование общего ресурса NFS
Обычной задачей подключения клиента является подключение удаленных общих ресурсов после подключения к корпоративной сети. Давайте рассмотрим веб-разработчика, которому необходимо подключить веб-каталог после подключения к VPN.
Первая задача состоит в том, чтобы написать на стороне клиента сценарии up
и down
. Сценарий up
соединит сетевой ресурс, а скрипт down
удалит его. Сценарий up
этом случае довольно прост - монтирование директории webroot
через NFS от 10.200.0.53. Этот пример написан для системы Mac OS X, использующей osascript
для предоставления графических всплывающих окон, чтобы уведомить пользователя, когда смонтирован общий ресурс NFS. Код выглядит следующим образом:
#!/bin/sh
# make webroot in home if it doesn't exist
mkdir -p /remote_shares/webroot
if [ $? -eq 0 ];
then
mount 192.168.19.53:/webroot /remote_shares/webroot
if [ $? -eq 0 ];
then
osascript -e 'tell app "System Events" to display dialog "~/remote_shares/webroot is mounted"'
else
osascript -e 'tell app "System Events" to display dialog "Unable to mount webroot directory."'
fi
else
osascript -e 'tell app "System Events" to display dialog "Unable to create remote share path."'
fi
Следующий скрипт довольно прост:
#!/bin/sh
umount -f ~/remote_shares/webroot
После создания сценариев необходимо обновить конфигурацию клиента, чтобы разрешить внешние сценарии, добавив директиву script-security
вместе с директивой up
:
script-security 2
up /путь/к/скриптуt/up.sh
Подсказка
Tunnelblick выполняет довольно много собственных сценариев и переопределяет оба вызова сценариев - up
и down
. Чтобы обойти это, следуйте инструкциям для именования и расположения сценариев. Эти инструкции можно найти по адресу https://tunnelblick.net/cUsingScripts.html.
Пример 5 - использование всех скриптов одновременно
В следующем примере мы будем использовать все сценарии на стороне клиента и сервера одновременно. Хотя это не похоже на ситуацию в реальной жизни, оно дает некоторое хорошее представление о порядке выполнения сценариев, а также об аргументах и переменных среды для каждого из сценариев.
Мы начнем со следующего файла конфигурации сервера:
tls-server
proto udp
port 1194
dev tun
server 10.200.0.0 255.255.255.0
server-ipv6 FD00::200:0/112
ca /etc/openvpn/movpn/movpn-ca.crt
cert /etc/openvpn/movpn/server.crt
key /etc/openvpn/movpn/server.key
dh /etc/openvpn/movpn/dh2048.pem
tls-auth /etc/openvpn/movpn/ta.key 0
persist-key
persist-tun
keepalive 10 60
topology subnet
user nobody
group nobody
daemon
log-append /var/log/openvpn.log
route 10.100.0.0 255.255.0.0
route 192.168.0.0 255.255.255.0
ask-pass /etc/openvpn/mopvn/secret
script-security 3
cd /etc/openvpn/movpn
setenv MASTERING_OPENVPN server
push "setenv-safe SPECIAL hack"
up ./movpn-07-01-script.sh
tls-verify ./movpn-07-01-script.sh
auth-user-pass-verify ./movpn-07-01-script.sh via-env
client-connect ./movpn-07-01-script.sh
route-up ./movpn-07-01-script.sh
client-disconnect ./movpn-07-01-script.sh
learn-address ./movpn-07-01-script.sh
route-pre-down ./movpn-07-01-script.sh
down ./movpn-07-01-script.sh
Мы сохраняем его как movpn-07-01-server.conf
. Вот некоторые заметки об этом файле конфигурации:
- Маршруты, указанные в конфигурации сервера, предназначены только для демонстрационных целей, как мы увидим позже.
- Чтобы обойти ошибку в OpenVPN 2.3.7, мы добавили следующую строку:
ask-pass /etc/openvpn/movpn/secret
- В этом файле
secret
(фраза-пароль для расшифровки закрытого ключа сервера) хранится в виде открытого текста. -
В этой конфигурации сервера мы также использовали следующую опцию, чтобы перейти в каталог, где расположен скрипт:
cd /etc/openvpn/movpn
Это делает конфигурацию сервера короче и проще для чтения.
Заметка
С опцией cd
было бы возможно указать опции ca
, cert
, key
, dh
и tls-auth
, используя более короткий путь, например:
ca./movpn-ca.crt
Тем не менее, рекомендуется всегда использовать абсолютные имена путей или параметр --cd
и относительные пути для элементов, связанных с безопасностью, чтобы избежать путаницы.
- Мы также установили переменную среды на стороне сервера
MASTERING_OPENVPN
со значениемserver
, используя следующую команду:
setenv MASTERING_OPENVPN server
- Мы передаем безопасную переменную среды всем клиентам, используя следующую команду:
push "setenv-safe SPECIAL hack"
- Внутри клиентских скриптов и плагинов эта переменная должна отображаться как
OPENVPN_SPECIAL
.
Далее мы создаем следующий скрипт:
#!/bin/bash
exec >> /tmp/movpn-07-01.log 2>&1
date +"%H:%M:%S: START $script_type script ==="
echo "argv = $0 $@"
echo "user = 'id -un''id -gn'"
env | sort | sed 's^/ /'
date +"%H:%M:%S: END $script_type script ==="
Мы сохраняем это как movpn-07-01-script.sh
в каталоге /etc/openvpn/movpn
. Убедитесь, что скрипт исполняемый, создайте пустой файл журнала и запустите openvpn
:
# chmod 0755 /etc/openvpn/movpn/mopvn-07-01-script.sh
# touch /tmp/movpn-07-01.log
# chown nobody /tmp/movpn-07-01.log
# openvpn --config /etc/openvpn/movpn/movpn-07-01-server.conf
Прежде чем мы продолжим, взглянем на файл /tmp/movpn-07-01.log
. Когда OpenVPN запускается, некоторые скрипты уже были выполнены:
15:46:57: START up script ===
argv = ./movpn-07-01-script.sh tun0 1500 1541 10.200.0.1
255.255.255.0 init
user = root/root
[...]
15:46:57: END up script ===
15:46:57: START route-up script ===
argv = ./movpn-07-01-script.sh
user = root/root
Сценарии up
и route-up
были выполнены. Параметры, переданные в скрипт up
представляли имя устройства TUN/TAP (tun0
), tun-mtu
(1500
), и значения link-mtu
(1541
), IP-адрес VPN и маску сети (10.200.0.1/255.255.255.0
) и тип вызова (возможные значения: init
или restart
).
Обратите внимание, что оба сценария были выполнены с привилегиями «root». Мы кратко рассмотрим вывод файла журнала каждого скрипта.
На стороне клиента мы настроили аналогичную конфигурацию. Сначала создайте следующий файл конфигурации:
client
proto udp
remote openvpnserver.example.com
port 1194
dev tun
nobind
remote-cert-tls server
tls-auth /etc/openvpn/movpn/ta.key 1
ca /etc/openvpn/movpn/movpn-ca.crt
cert /etc/openvpn/movpn/client1.crt
key /etc/openvpn/movpn/client1.key
persist-tun
persist-key
explicit-exit-notify 3
auth-user-pass
script-security 3
cd /etc/openvpn/movpn
setenv MASTERING_OPENVPN client
tls-verify ./movpn-07-01-script.sh
ipchange ./movpn-07-01-script.sh
up ./movpn-07-01-script.sh
up-restart
route-up ./movpn-07-01-script.sh
route-pre-down ./movpn-07-01-script.sh
down ./movpn-07-01-script.sh
Сохраните его как movpn-07-01-client.conf
и заново создайте или скопируйте файл movpn-07-01-script.sh
с сервера.
Опять же, мы гарантируем, что скрипт является исполняемым, создаем пустой файл журнала и запускаем openvpn
:
# chmod 0755 /etc/openvpn/movpn/mopvn-07-01-script.sh
# openvpn --config /etc/openvpn/movpn/movpn-07-01-client.conf
OpenVPN 2.3.7 x86_64-redhat-linux-gnu [SSL (OpenSSL)] [LZO] [EPOLL]
[PKCS11] [MH] [IPv6] built on Jun 9 2015
library versions: OpenSSL 1.0.1e-fips 11 Feb 2013, LZO 2.08
Enter Auth Username: *****
## введите "movpn"
Enter Auth Password: ******
## введите "secret"
NOTE: the current --script-security setting may allow this configuration to call user-defined scripts
Control Channel Authentication: using 'etcopenvpn/movpn/ta.key' as a OpenVPN static key file
UDPv4 link local: [undef]
UDPv4 link remote: [AF_INET]<IP>:1194
WARNING: this configuration may cache passwords in memory -- use
the auth-nocache option to prevent this
[Mastering OpenVPN Server] Peer Connection Initiated with [AF_INET]
<IP>:1194
TUN/TAP device tun0 opened
do_ifconfig, tt->ipv6=1, tt->did_ifconfig_ipv6_setup=1
usrsbin/ip link set dev tun0 up mtu 1500
usrsbin/ip addr add dev tun0 10.200.0.2/24 broadcast 10.200.0.255
usrsbin/ip -6 addr add fd00::200:1000/112 dev tun0
./movpn-07-01-script.sh tun0 1500 1541 10.200.0.2 255.255.255.0
init
Initialization Sequence Completed
Вы можете заполнить как захотите для Auth username
и Auth password
, так как серверный скрипт всегда будет возвращать успех.
После установления соединения мы проверяем, что VPN-клиент и сервер могут связаться друг с другом, используя ping
и ping6
.
Затем мы перезапускаем VPN-соединение, отправляя специальный сигнал OpenVPN клиенту:
# killall -USR1 openvpn
Это вызовет «программный сброс» клиента OpenVPN. После восстановления соединения мы еще раз проверяем, что VPN полностью функционирует. Программные сбросы происходят в реальных ситуациях, в основном, когда опция persist-tun
используется на стороне клиента, а клиент OpenVPN находится в мобильной сети с роумингом, или когда сеть между клиентом и сервером не очень стабильна. В этом сценарии серверные сценарии вызываются с немного другими параметрами, как мы увидим ниже.
Наконец, завершите VPN-соединение, завершив работу клиента. Теперь мы пройдемся по журналам сценариев на сервере и клиенте.
Журналирование серверных сценариев
Журнал серверных сценариев может легко вырасти до тысяч строк, но, к счастью, в нем есть некоторая структура. Давайте сначала проверим порядок, в котором сценарии вызываются:
15:46:57: START up script ===
argv = ./movpn-07-01-script.sh tun0 1500 1541 10.200.0.1
255.255.255.0 init
15:46:57: START route-up script ===
argv = ./movpn-07-01-script.sh
15:47:15: START tls-verify script ===
argv = ./movpn-07-01-script.sh 1 C=ZA, ST=Enlightenment,
L=Overall, O=Mastering OpenVPN, CN=Mastering OpenVPN,
emailAddress=root@example.org
15:47:15: START tls-verify script ===
argv = ./movpn-07-01-script.sh 0 C=ZA, ST=Enlightenment,
O=Mastering OpenVPN, CN=client1,
emailAddress=root@example.org
15:47:15: START user-pass-verify script ===
argv = ./movpn-07-01-script.sh
15:47:15: START client-connect script ===
argv = ./movpn-07-01-script.sh
tmpopenvpn_cc_5b1f0d25ac0f71c98c44ec128e5c21d6.tmp
15:47:15: START learn-address script ===
argv = ./movpn-07-01-script.sh add 10.200.0.2 client1
15:47:15: START learn-address script ===
argv = ./movpn-07-01-script.sh add fd00::200:1000 client1
17:37:18: START tls-verify script ===
argv = ./movpn-07-01-script.sh 1 C=ZA, ST=Enlightenment,
L=Overall, O=Mastering OpenVPN, CN=Mastering OpenVPN,
emailAddress=root@example.org
17:37:18: START tls-verify script ===
argv = ./movpn-07-01-script.sh 0 C=ZA, ST=Enlightenment,
O=Mastering OpenVPN, CN=client1,
emailAddress=root@example.org
17:37:18: START user-pass-verify script ===
argv = ./movpn-07-01-script.sh
17:37:18: START client-disconnect script ===
argv = ./movpn-07-01-script.sh
17:37:18: START client-connect script ===
argv = ./movpn-07-01-script.sh
tmpopenvpn_cc_8528c57f838033a03f38ddb72b57ae30.tmp
17:37:18: START learn-address script ===
argv = ./movpn-07-01-script.sh update 10.200.0.2 client1
17:37:18: START learn-address script ===
argv = ./movpn-07-01-script.sh update fd00::200:1000 client1
17:38:50: START client-disconnect script ===
argv = ./movpn-07-01-script.sh
17:38:50: START learn-address script ===
argv = ./movpn-07-01-script.sh delete fd00::200:100017:38:50: START learn-address script ===
argv = ./movpn-07-01-script.sh delete 10.200.0.2
17:39:08: START route-pre-down script ===
argv = ./movpn-07-01-script.sh tun0 1500 1541 10.200.0.1
255.255.255.0 init
17:39:09: START down script ===
argv = ./movpn-07-01-script.sh tun0 1500 1541 10.200.0.1
255.255.255.0 init
Сначала вызываются сценарии up
и route-up
, как мы уже видели.
Когда первый клиент подключается, сценарий tls-verify
вызывается дважды: сначала для сертификата CA, который использовался для подписи сертификата клиента, а затем для самого сертификата клиента.
Затем выполняется скрипт auth-user-pass-verify
. Когда этот сценарий возвращает успех (код выхода 0
), клиент аутентифицируется и считается доверенным.
Следующий скрипт - это скрипт client-connect
, который вызывается с временным файлом. Этот сценарий часто используется для установки специальных параметров для конкретного клиента или для регистрации активности клиента в базе данных. Этот сценарий может по-прежнему влиять на IP-адрес, назначенный клиенту, распечатывая параметр для временного файла, например:
echo "ifconfig-push 10.200.0.88 255.255.255.0"> $ 1
Последний скрипт, который вызывается при подключении клиента, это скрипт learn-address
. Этот скрипт вызывается дважды, один раз с адресом IPv4 и другой - с IPv6. Этот сценарий на самом деле лучше всего подходит для обновления правил брандмауэра, но большинство людей склонны использовать для этого сценарий client-connect
. Сценарий learn-address
необходим, особенно при настройке на основе ТАР в сочетании с внешним сервером DHCP.
Заметка
В настройке на основе TAP вторым параметром в сценарии с learn-address
является MAC-адрес клиентского адаптера TAP. Клиентский IP-адрес VPN доступен в качестве переменной среды.
Из файла журнала видно, что клиент OpenVPN получил триггер soft-restart
в 17:37:18
. Порядок выполнения скриптов может показаться странным, но это можно объяснить:
- Обнаружено новое входящее соединение. Для этого выполняются сценарии
tls-verify
иauth-user-pass-verify
чтобы определить, является ли он действительным клиентом. - Как только определено что это действительный клиент и этот конкретный клиент уже подключен, старый экземпляр клиента сначала отключается. Таким образом вызывается cценарий
client-disconnect
. - Затем вызывается сценарий
client-connect
для нового экземпляра клиента. Обратите внимание, что новый экземпляр клиента может поступать с нового удаленного IP-адреса. Наконец, скриптlearn-address
вызывается дважды с действием, установленным дляupdate
, один раз для адреса IPv4 и один раз для адреса IPv6. Если необходимо изменить какие-либо правила брандмауэра, то это будет лучшим местом для этого.
В 17:38:50
клиент был отключен. Поскольку мы указали explicit-exit-notify
в конфигурации клиента, сервер немедленно уведомляется об этом и выполняется сценарий client-disconnect
.
Обратите внимание, что сценарии learn-address
теперь выполняются с действием, установленным на delete
.
В 17:39:08
сам процесс сервера OpenVPN останавливается и вызываются сценарии route-pre-down
и down
. Обратите внимание, что в этот сценарий передаются те же параметры, что и в сценарий up
.
Переменные среды, установленные в серверных сценариях
Теперь, когда мы понимаем порядок, в котором вызываются скрипты, пришло время более внимательно посмотреть на переменные среды, которые доступны для скриптов.
–up
Переменные среды, доступные для скрипта up
, следующие:
MASTERING_OPENVPN=server
PWD=etcopenvpn/movpn
SHLVL=1
=/bin/env
config=movpn-07-01-server.conf
daemon=1
daemonlog_redirect=1
daemon_pid=8070
daemon_start_time=1437659216
dev=tun0
dev_type=tun
ifconfig_broadcast=10.200.0.255
ifconfig_ipv6_local=fd00::200:1
ifconfig_ipv6_netbits=112
ifconfig_ipv6_remote=fd00::200:2
ifconfig_local=10.200.0.1
ifconfig_netmask=255.255.255.0
link_mtu=1541
local_port_1=1194
proto_1=udp
remote_port_1=1194
route_gateway_1=10.200.0.2
route_gateway_2=10.200.0.2
route_net_gateway=<SERVER-IP>
route_netmask_1=255.255.0.0
route_netmask_2=255.255.255.0
route_network_1=10.100.0.0
route_network_2=192.168.0.0
route_vpn_gateway=10.200.0.2
script_context=init
script_type=up
tun_mtu=1500
verb=1
Большинство параметров, передаваемых в сценарий up
, также представлены в виде переменных среды. Информация о маршрутизации на стороне сервера также уже доступна здесь, но лучше всего иметь дело с этими переменными в скрипте route-up
.
–route вверх
В сценарии route-up
доступна та же среда, что и в предыдущем коде, с одним добавлением:
script_type=route-up
redirect_gateway=0
Эта переменная среды имеет значение 1
, если шлюз по умолчанию также необходимо перенаправить. Все операторы маршрута, которые перечислены в файле конфигурации сервера, также представлены как переменные среды. Для каждого маршрута доступны route_network
, route_netmask
и route_gateway
. Также обратите внимание, что ключевые слова OpenVPN net_gateway
и vpn_gateway
представлены здесь как route_net_gateway
и route_vpn_gateway
.
–tls-verify
Сценарий tls-verify
вызывается с полным именем сертификата, которое также называется Distinguished Name (DN). Еще больше информации о сертификате доступны как переменные среды:
X509_0_C=ZA
X509_0_CN=client1
X509_0_O=Mastering OpenVPN
X509_0_ST=Enlightenment
X509_0_emailAddress=root@example.org
X509_1_C=ZA
X509_1_CN=Mastering OpenVPN
X509_1_L=Overall
X509_1_O=Mastering OpenVPN
X509_1_ST=Enlightenment
X509_1_emailAddress=root@example.org
script_type=tls-verify
tls_digest_0=1b:27:a6:b4:5f:7a:9c:3f:17:fb:ff:33:05:61:3f:2a:56:89:16:d3
tls_digest_1=e4:f1:43:37:34:51:de:99:7a:dc:e3:6d:f2:4c:5b:84:34:4b:f3:64
tls_id_0=C=ZA, ST=Enlightenment, O=Mastering OpenVPN, CN=client1, emailAddress=root@example.org
tls_id_1=C=ZA, ST=Enlightenment, L=Overall, O=Mastering OpenVPN, CN=Mastering OpenVPN, emailAddress=root@example.org
tls_serial_0=2
tls_serial_1=15173527578309581038
tls_serial_hex_0=02
tls_serial_hex_1=d2:93:32:f0:8e:bc:58:ee
untrusted_ip=<CLIENT-IP>
untrusted_port=46171
Все это можно использовать для определения того, действительно ли этот конкретный сертификат клиента является доверенным. Обратите внимание, что есть две переменные среды: untrusted_ip = <CLIENT-IP>
и untrusted_port = 46171
, которые обозначают еще не доверенный адрес клиента.
–auth-user-pass-verify
Сценарий auth-user-pass-verify
имеет ту же среду, что и предыдущий сценарий, с добавлением трех новых переменных:
common_name=client1
username=movpn
password=secret
common_name
устанавливается после успешного завершения сценария tls-verify
. username
и password
передаются как переменные среды, потому что мы установили script-security
на 3
, и добавили параметр via-env
к опции auth-user-pass-verify
в файле конфигурации.
–client-connect
Наиболее часто используемый скрипт client-connect
имеет почти ту же среду, но переменная password
была удалена. Кроме того, поскольку процесс аутентификации теперь завершен, есть две новые переменные, trusted_ip=<CLIENT-IP>
and trusted_port=<port>
, с точно такими же значениями, что и у их ненадежных аналогов. Обратите внимание, что ненадежные версии также все еще доступны.
–learn-address
Сценарий learn-address
имеет ту же среду, что и скрипт client-connect
. Для этого требуется команда и несколько необязательных аргументов:
- операция: добавить, обновить или удалить
- адрес: адрес, который изучается или не изучается
- общее имя: общее имя сертификата клиента для связи с адресом
В настройке на основе TAP вторым параметром, передаваемым сценарию, является MAC-адрес клиентского адаптера TAP. IP-адрес VPN, который был назначен клиенту сервером (если настроен таким образом), доступен в переменных среды ifconfig_pool_remote_ip
и ifconfig_pool_netmask
, соответственно,
как показано здесь:
ifconfig_pool_remote_ip=10.200.0.2
ifconfig_pool_netmask=255.255.255.0
–client-disconnect
Сценарий client-disconnect
имеет ту же самую среду, что и client-disconnect
, но он также возвращает некоторую статистику аккаунта:
bytes_received=7553
bytes_sent=8105
Эта информация в основном интересна для нужд аккаунта.
–route-pre-down и –down
И, наконец, сценарии route-pre-down
и down
вызываются с одинаковыми параметры в качестве скрипта up
. Когда вызывается сценарий route-pre-down
, системные маршруты все еще присутствуют. При вызове сценария down
системные маршруты будут удалены при условии, что у OpenVPN были для этого полномочия. Переменная среды signal=sigint
предоставляет информацию о типе сигнала, который вызвал отключение OpenVPN.
Журнал клиентского скрипта
Журнал клиентских скриптов имеет очень похожую структуру и поток, как и журнал на стороне сервера. Опять же, давайте сначала проверим порядок вызова скриптов:
15:47:15: START tls-verify script ===
argv = ./movpn-07-01-script.sh 1 C=ZA, ST=Enlightenment,
L=Overall, O=Mastering OpenVPN, CN=Mastering OpenVPN,
emailAddress=root@example.org
15:47:15: START tls-verify script ===
argv = ./movpn-07-01-script.sh 0 C=ZA, ST=Enlightenment,
O=Mastering OpenVPN, CN=Mastering OpenVPN Server,
emailAddress=root@example.org
15:47:15: START ipchange script ===
argv = ./movpn-07-01-script.sh [AF_INET]<SERVER-IP> [AF_INET]1194
15:47:17: START up script ===
argv = ./movpn-07-01-script.sh tun0 1500 1541 10.200.0.2
255.255.255.0 init
15:47:17: START route-up script ===
argv = ./movpn-07-01-script.sh
17:37:16: START down script ===
argv = ./movpn-07-01-script.sh tun0 1500 1541 10.200.0.2
255.255.255.0 restart
17:37:18: START tls-verify script ===
argv = ./movpn-07-01-script.sh 1 C=ZA, ST=Enlightenment,
L=Overall, O=Mastering OpenVPN, CN=Mastering OpenVPN,
emailAddress=root@example.org
17:37:18: START tls-verify script ===
argv = ./movpn-07-01-script.sh 0 C=ZA, ST=Enlightenment,
O=Mastering OpenVPN, CN=Mastering OpenVPN Server,
emailAddress=root@example.org
17:37:18: START ipchange script ===
argv = ./movpn-07-01-script.sh [AF_INET]<SERVER-IP> [AF_INET]1194
17:37:20: START up script ===
argv = ./movpn-07-01-script.sh tun0 1500 1541 10.200.0.2
255.255.255.0 restart
17:38:53: START route-pre-down script ===
argv = ./movpn-07-01-script.sh tun0 1500 1541 10.200.0.2
255.255.255.0 init
17:38:53: START down script ===
argv = ./movpn-07-01-script.sh tun0 1500 1541 10.200.0.2
255.255.255.0 init
Когда клиент впервые подключается, сценарий tls-verify
вызывается дважды, сначала для сертификата CA, который использовался для подписи сертификата сервера, а затем для самого сертификата сервера. Таким образом, клиент может проверить, что он подключается к доверенному серверу.
После этого вызывается малоизвестный скрипт ipchange
. Этот сценарий еще не знает, какому IP-адресу клиента он будет назначен. Он используется главным образом для настройки параметров брандмауэра на клиенте или для уведомления другого приложения о том, что выполняется настройка VPN-подключения.
Как только клиент проходит проверку подлинности на сервере, блок информации передается с сервера на клиент. Затем этот блок анализируется локально как параметры конфигурации, после чего вызываются сценарии up
и route
.
Когда мы отправили сигнал USR1
клиенту OpenVPN, он заставил OpenVPN выполнить soft-restart
. Это также видно в журнале выполнения скрипта:
- Во-первых, сценарий
down
вызывается с последним набором параметров, чтобыrestart
вместоinit
. - Затем вызываются скрипты
tls-verify
иipchange
, так как нам необходимо повторно пройти аутентификацию на сервере. - Наконец, сценарий
up
вызывается еще раз для настройки IP-адреса VPN. Здесь последний параметр скрипта также устанавливается дляreboot
вместоinit
.
Обратите внимание, что скрипт route-up
в этом случае не вызывается. Это связано с тем, что мы включили persist-tun
в конфигурацию клиента. Поскольку интерфейс TUN/TAP не был закрыт или отключен, вся маршрутизация на стороне клиента остается в силе, и, следовательно, скрипт route-up
не выполняется.
Когда клиент отключается, сценарии route-pre-down
и down
вызываются еще раз, на этот раз с параметром, установленным в init
.
Переменные среды, установленные в клиентских скриптах
Теперь, когда мы понимаем порядок, в котором вызываются сценарии, снова пришло время взглянуть на переменные среды.
Большинство переменных среды на стороне клиента напоминают переменные на серверной стороне. Некоторые переменные являются зеркальными, например common_name
, которое содержит общее имя сертификата на стороне сервера, что можно найти в средах сценариев up
и ipchange
:
common_name=Mastering OpenVPN Server
Также в среде up script
присутствует переменная, которая была передана с сервера на клиент:
OPENVPN_SPECIAL=hack
Клиент OpenVPN получил безопасную переменную SPECIAL
и создал для нее переменную среды, добавив к ней OPENVPN_
.
Заметка
Нет способа отправить информацию или переменные обратно с клиента на сервер. В версии 2.4 некоторая системная информация будет отправлена обратно, но это не может быть настроено на клиенте.
Когда клиент OpenVPN перезапускается с использованием сигнала USR1
, сценарии down
и up
вызываются с последним параметром, установленным для reboot
вместо init
. Это также отражается в переменных среды обоих сценариев:
script_context=restart
script_type=down ## or up
signal=sigusr1
Когда OpenVPN завершается, эти переменные среды содержат следующее:
script_context=init
script_type=down
signal=exit-with-notification
Плагины
Из-за простоты написания сценариев интерфейс плагина OpenVPN является относительно недостаточно используемым инструментом, доступным администраторам серверов OpenVPN. OpenVPN по умолчанию поставляется с парой плагинов, один - для аутентификации PAM, а другой для выполнения сценариев --down
с привилегиями root, независимо от того, отменяет ли администратор де-эскалацию привилегий.
down-root
Это хорошая идея, чтобы отбросить привилегии в OpenVPN, и плагин down-root
позволяет вам это делать. Такие приложения, как брандмауэры, требуют повышения привилегий для добавления и удаления правил брандмауэра. Используя плагин down-root
, администратор может предоставить новые правила брандмауэра при подключении клиента, а также возможность удаления этих правил после отключения клиента.
Сценарий использования может быть одним экземпляром OpenVPN, который поддерживает весь персонал компании. Административному и офисному персоналу, как правило, не нужен доступ к интерфейсам управления отключением и другим подобным системам в сети компании. С добавлением правил брандмауэра OpenVPN может ввести разрешенный доступ для определенных клиентских подключений на основе CN или других переменных среды. Как только этот техник отключается, удаление правил брандмауэра не позволяет другому нетехническому сотруднику получить такой доступ, даже если он находится в той же подсети или получает тот же IP, что и ранее подключенный сотрудник.
Плагин auth-pam
Второй плагин, с которым поставляется OpenVPN, это плагин auth-pam
. Он взаимодействует со стеком подключаемых модулей аутентификации операционной системы (PAM). Используя PAM, администратор может использовать любой бэкэнд, который также может взаимодействовать таким образом. LDAP - это пример использования auth-pam
.
Многие системы Unix и Linux имеют возможность аутентификации с помощью LDAP. В случае OpenLDAP существует несколько общих объектов, таких как pam-ldap
и nss-ldap
от PADL Software. После их настройки и добавления в системный стек PAM OpenVPN можно связать с несколькими простыми параметрами конфигурации.
Подсказка
Плагин auth-pam
не может быть использован в системах Windows из-за отсутствия поддержки PAM.
В простейшей форме к конфигурации сервера можно добавить следующее:
plugin openvpn-auth-pam.so login
Это активирует плагин и дает ему команду использовать сервис PAM для входа в систему. Обратите внимание, что это может быть любая служба PAM, включая настройки OpenVPN, определенные администратором. Третий параметр в предыдущем коде идентифицирует услугу. Более сложная конфигурация может включать передаваемые параметры:
plugin openvpn-auth-pam.so login login USERNAME password PASSWORD
В этом случае мы все еще используем сервис PAM для входа в систему, но для этого требуются два параметра: логин и пароль. OpenVPN потенциально передаст три параметра, заменив ключевые слова PASSWORD
, USERNAME
и COMMONNAME
их очевидными аналогами. USERNAME
и PASSWORD
требуют, чтобы auth-user-pass
был установлен в конфигурации клиента.
Чтобы определить запросы, сделанные службой PAM, или отладить сам модуль auth-pam
, установите для OpenVPN детальность ведения журнала уровня 7 или выше. Запуск auth-pam
вместе с OpenVPN 2.3.6 дает следующий вывод в файле журнала:
AUTH-PAM: BACKGROUND: received command code: 0
AUTH-PAM: BACKGROUND: USER: ecrist
AUTH-PAM: BACKGROUND: my_conv[0] query='Login:' style=2
AUTH-PAM: BACKGROUND: name match found, query/match-string
['Login:', 'login'] = 'USERNAME'
AUTH-PAM: BACKGROUND: my_conv[0] query='Password:' style=1
AUTH-PAM: BACKGROUND: name match found, query/match-string
['Password:', 'password'] = 'PASSWORD'
Глядя на строки с my_conv
, мы видим два значения запроса Login:
и Password:
. Те успешно частично совпадают с login
и password
. Чтобы продемонстрировать частичное совпадение, я изменил строку конфигурации следующим образом:
plugin openvpn-auth-pam.so login log USERNAME password PASSWORD
В журнале видно, что модуль смог успешно сопоставить log
с Login: and password to Password:
.
AUTH-PAM: BACKGROUND: received command code: 0
AUTH-PAM: BACKGROUND: USER: ecrist
AUTH-PAM: BACKGROUND: my_conv[0] query='Login:' style=2
AUTH-PAM: BACKGROUND: name match found, query/match-string
['Login:', 'log'] = 'USERNAME'
AUTH-PAM: BACKGROUND: my_conv[0] query='Password:' style=1
AUTH-PAM: BACKGROUND: name match found, query/match-string
['Password:', 'password'] = 'PASSWORD'
Как бы ни было полезно это слабое соответствие, вам нужно быть осторожным, поскольку есть вероятность возникновения коллизий в зависимости от используемого вами плагина PAM.
Список проектов, которые предоставляют различные подключаемые модули аутентификации, а также различные интерфейсы и менеджеры сертификатов, можно найти по адресу https://community.openvpn.net/openvpn/wiki/RelatedProjects.
Резюме
Скрипты и плагины являются мощными инструментами для расширения OpenVPN. Это позволяет администратору лучше интегрировать OpenVPN в существующую инфраструктуру, например, путем включения аутентификации в отдельной бэкэнд-системе или путем записи статистики использования клиента.
Написание скриптов OpenVPN может быть непростым делом, так как нужно соблюдать особую осторожность в отношении сроков написания скриптов. Текущая версия OpenVPN является монолитной и однопоточной - это означает что длинный или некорректно работающий серверный скрипт может заблокировать весь VPN для всех пользователей.
Также важно понимать последовательность и порядок вызова сценариев. В этой главе мы рассмотрели, как работает этот порядок и какие переменные среды присутствуют в каждом из серверных и клиентских сценариев.
В следующей главе мы увидим больше графических пользовательских интерфейсов, поскольку углубимся в использование OpenVPN на смартфонах, планшетах и других мобильных устройствах.