Skip to the content.

Глава 7. Скрипты и плагины

После развертывания персональная или корпоративная VPN может стать мощным инструментом как с точки зрения безопасности, так и с точки зрения функциональности. Хорошо спроектированная VPN позволит пользователям безопасно подключаться к удаленным ресурсам. Иногда, однако, просто иметь VPN недостаточно. Данное приложение может требовать более строгих стандартов безопасности или требовать лучшего мониторинга и контроля.

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

Скриптинг

Скрипты, вероятно, один из лучших инструментов, доступных для администратора OpenVPN. Имея возможность назначать как клиентские, так и серверные скрипты, OpenVPN может инициировать другие ответы системы, открывая брандмауэры, запуская приложения или даже отправляя сообщение администратору.

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

Начиная с версии 2.3.6 OpenVPN поддерживает 13 параметров скриптов на стороне сервера и 10 параметров на стороне клиента. Команды со звездочками являются параметрами настройки и позволяют следующим параметрам выполнять определенные действия. Серверные скрипты выглядят следующим образом (в порядке выполнения):

На стороне клиента сценарии выглядят следующим образом (в порядке выполнения):

Теперь мы кратко рассмотрим все эти параметры, объяснив их функции как на стороне сервера, так и на стороне клиента. Далее в этой главе мы предоставим подробный пример и обсудим поведение и тонкости каждого из этих сценариев.

Серверные скрипты

Давайте посмотрим на сценарии, используемые на стороне сервера.

–setenv и –setenv-safe

Параметры setenv и setenv-safe используются для установки переменных среды, которые могут использоваться как скриптами, так и плагинами. Опция setenv позволяет нам устанавливать практически любые переменные окружения, но эту опцию нельзя “передать” клиентам. Опция setenv-safe добавляет к каждой переменной среды префикс OPENVPN_ , избегая конфликтов с системными переменными среды, такими как PATH и LD_LIBRARY_PATH. Эта опция может быть передана клиентам, что обеспечивает большую гибкость.

–script-security

Опция script-security определяет какие типы приложений или скриптов могут быть выполнены из конфигурации OpenVPN. Существует четыре варианта уровней безопасности:

–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, которую мы создали для отслеживания используемого времени. Наш скрипт будет иметь несколько задач:

Для выполнения предыдущих задач мы напишем небольшой скрипт оболочки, который будет вызываться демоном 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. Вот некоторые заметки об этом файле конфигурации:

Это делает конфигурацию сервера короче и проще для чтения.


Заметка

С опцией cd было бы возможно указать опции ca, cert, key, dh и tls-auth, используя более короткий путь, например:

ca./movpn-ca.crt

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


setenv MASTERING_OPENVPN server
push "setenv-safe SPECIAL hack"

Далее мы создаем следующий скрипт:

#!/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. Порядок выполнения скриптов может показаться странным, но это можно объяснить:

В 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. Это также видно в журнале выполнения скрипта:

Обратите внимание, что скрипт 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 на смартфонах, планшетах и ​​других мобильных устройствах.