Про OpenVPN написано много гайдов, в том числе и про авторизацию через Active Directory. Большинство из них сводится к использованию LDAP, подхода с использованием Kerberos, оформленного в полноценную статью, я не нашел. Впрочем, чего-то нового тут изобретено не будет, я лишь скомпилировал уже сделанное до меня, PAM отлично работает с Kerberos, а OpenVPN имеет нативный плагин для PAM. Также я решил отказаться от пользовательских сертификатов и советы, где рекомендуют просто всем пользователям выдавать один сертификат, меня не устроили, поэтому было найдено другое решение, работающее на всех клиентах.



Немного об NSS


В своем случае я использовал Centos 7 в связке с sssd. Впрочем, ничто не мешает использовать winbind. Главное, иметь машину в домене и тикет Kerberos. Я не буду писать о том, как это делается, т.к. не скажу ничего нового, в сети много хороших мануалов.

Будет необходимо сменить настройки /etc/nsswitch.conf, если этого не было сделано ранее. В зависимости от того, какой модуль использовался, нужно вместо module_name вписать sss или winbind соответственно. Описание параметров можно прочесть с помощью man nsswitch.conf.

Следующих настроек должно быть достаточно:

passwd:           files module_name
shadow:           files module_name
group:            files module_name

В случае с sssd не забываем, кроме всего прочего, что в /etc/sssd/sssd.conf в блоке [sssd] должен быть упомянут nss:

services = nss, pam

Насчет winbind мне сложно что-то сказать, я его не использовал.

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

> getent passwd kanlas
kanlas:*:14123583:1257570:Kanlas Kanlasovich:/home/kanlas@example.com:/bin/bash
> getent group VPN
vpn:*:13821391:kanlas,igor,marina

Примечание
Если вы использовали sssd и данные о пользователе получаются только с указанием полного имени (т.е. kanlas@example.com), добавьте в sssd.conf в блоке домена параметр use_fully_qualified_names = False

Настраиваем PAM


Теперь необходимо создать свой PAM модуль. Чтобы не использовать системный access.conf, сделаем отдельный файл, откуда будет читаться группа доступа. Я не так хорош в модулях PAM, поэтому не могу сказать, нужны ли все строки в примере, который будет ниже. В общем-то, нас интересует только строка account required pam_listfile.so onerr=fail item=group sense=allow file=/etc/openvpn/auth/access-groups.

Самый простой вариант, взять, например, модуль login и добавить в него нужную строку. Что и было сделано.

Получаем:

	
#%PAM-1.0
auth [user_unknown=ignore success=ok ignore=ignore default=bad] pam_securetty.so
auth       substack     system-auth
auth       include      postlogin
account    required     pam_listfile.so onerr=fail item=group sense=allow file=/etc/openvpn/auth/access-groups
account    include      system-auth
password   include      system-auth
session    required     pam_selinux.so close
session    required     pam_loginuid.so
session    optional     pam_console.so
session    required     pam_selinux.so open
session    required     pam_namespace.so
session    optional     pam_keyinit.so force revoke
session    include      system-auth
session    include      postlogin
-session   optional     pam_ck_connector.so

Кладем его в /etc/pam.d, назвав по своему усмотрению.

В /etc/openvpn/auth/access-groups, указанный в модуле, у нас и будет записана группа доступа, можете указать свой путь при желании. Нужно будет указать имя группы (Common Name) с доменом. В моем случае я записал туда VPN@example.com.

Осталось объяснить OpenVPN, что ему необходимо использовать PAM. Кладем в конфигурацию сервера следующие строки:

plugin /usr/lib64/openvpn/plugins/openvpn-plugin-auth-pam.so имя_модуля_pam
username-as-common-name

В разных дистрибутивах пути могут отличаться! Проверьте наличие файла по пути, либо используйте find.

Использование параметра username-as-common-name связано с тем, что в ином случае после выполнения auth-user-pass у клиента, серверу отправится имя, указанное в сертификате.

В конфиге клиента необходимо добавить строку

auth-user-pass

На этом настройка закончена, можно тестировать.

Убираем сертификат пользователя


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

verify-client-cert none

Далее в конфигурацию клиентов добавляем

setenv CLIENT_CERT 0

Все, теперь клиенты не будут ругаться на сертификат. Забавно, что этот параметр спрятан в разделе вопросов-ответов для iOS. Я не тестировал на iOS, но Android, а так же MacOS (бета клиент) и Windows принимают эти настройки на ура. Только сторонний OpenVPN-клиент на Android пока этого не умеет (к моменту написания статьи уже могли поправить).

Комментарии (8)


  1. kuyantus
    01.10.2019 07:49

    То есть, пока мы, в дополнение к сертификату вводим двухфакторную авторизацию, в данном случае вообще достаточно пароля от AD и больше ничего? Ну, такое :)


    1. Kanlas Автор
      01.10.2019 08:16

      Авторизация через AD заменяет сертификат) У клиента все равно есть preshared key (tls-crypt или устаревшее tls-auth), без которого подключение сервер сразу отклонит (у меня такие ip сразу улетают в долгосрочный бан). Если мы выдаем всем один сертификат, что он есть, что его нет, в случае попадания конфигурации клиента к злоумышленнику, разницы не будет. От подбора паролей защищает fail2ban и мониторинг логов, в случае компрометации меняем ключ и рассылаем новый конфиг клиентам. Идея не снизить безопасность, а отказазаться от того, что ее не повысит :-) Если есть возможность выдавать всем персональный сертификат, а то и под каждое устройство, то это уже другое дело.
      Двухфакторная авторизация хороший вариант, но я пока решил, что этого достаточно.


  1. pilya_by
    01.10.2019 09:49

    Возможно я ошибаюсь, но сертификат пользователь получает по тому же логину/паролю AD.


    1. Kanlas Автор
      01.10.2019 09:55

      Сертификат пользователя по сути приватный ключ, как в ssh, например. Так что выдается заранее


  1. scruff
    01.10.2019 14:06

    Подскажите по конфе OpenVPN. Установлен сабж пару лет назад из скрипта с гитхаба. Не могу понять на сколько он безопасен. Клиенты подключаются через OpenVPNGUI и файлик *.ovpn. Файл ovpn генерится так ./newclient.sh из /etc/openvpn. Работает вроде норм, но как управлять этим чудом не пойму. Где здесь сертификаты, где ключи открытые/закрытые, как мониторить активных юзеров ума не приложу.


    1. Kanlas Автор
      01.10.2019 15:25

      Слишком много вопросов, чтобы ответить в одном комментарии) Готовые скрипты вообще зло, если не понимаешь что они делают. Проще всего будет посмотреть мануалы, либо прямо по ним переставить сервер. Вот хороший мануал, хоть и несколько устаревший, там про сертификаты тоже есть. Про безопасность, стандартный конфиг, указанный почти во всех приличных мануалах, сгодится для личного использования/небольшой компании. Но я не специалист ИБ и не держу публичных OpenVPN, чтобы поделиться опытом, поэтому могу ошибаться. В целом, оф. мануал хорошо описывает все параметры, так что можете просто по ним изучить свой конфиг.
      Мониторинг осуществляется либо через файл openvpn-status.log (в конфиге обычно указывается, если не указан, можно подсмотреть в любом мануале), либо через management interface, с которым можно общаться через telnet(пригодится для заббикса и всяких веб-морд с гитхаба, по умолчанию не включен и в мануалах обычно его нет)


      1. scruff
        02.10.2019 14:17

        Спасибо, методом тыка нашел то что мне надо /etc/openvpn/logs/openvpn.log — теперь можно смотреть кто подключен, а кто «ломится» с отозванным *.ovpn. И приятный бонус — видно реальные IP всех подключающихся.


  1. mzpwr
    03.10.2019 11:51

    Sssd очень желательно от 2.2.0 и новее. До этого была грабля с kerberos если у вас не один домен с парой DC.