Всем привет, на связи команда Joy Dev

Я и мой коллега Артём — backend‑разработчики, пишем на Ruby. Когда мы только начали работать, в компании использовались две сторонние службы VPN (не буду их называть), которые со временем перестали по определённым причинам работать. На одном из собраний наш тимлид предложил руководству создать свой VPN, и backend‑отдел готов был попробовать придумать что‑то своё, используя базу OpenVPN.

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

  1. OpenVPN занимает очень мало места на диске, да и вообще не сильно требовательный;

  2. в среднем на 100 пользователей хватает 1 Гб оперативной памяти.

Под эти запросы мы начали искать VPS хостинг, предварительно сделали список всех возможных кандидатов и, согласовав с руководителем, выбрали тот, на котором, как оказалось, у нас уже была снята одна машина. Хостинг пока не буду называть.

Поскольку я и мой коллега Артем никогда ничем подобным не занимались, пришлось подробно узнать, как это делается. Всю настройку сервера выполняли по найденной информации. Сам VPN мы поставили на машину под управлением Ubuntu 20.04.

Сначала мы выполнили первичную настройку сервера:

  1. Настроили вход по ssh‑ключу.

  2. Создали пользователя без привилегий root.

  3. Настроили базовый брандмауэр.

  4. Активировали внешний доступ для стандартного пользователя.

Затем настроили центр сертификации на сервере:

  1. Установили набор скриптов easy‑rsa.

  2. Создали папку для работы со скриптами.

  3. Создали PKI (инфраструктура открытых ключей) для центра сертификации.

  4. Подписали сертификат для нашего сервера.

Далее мы установили OpenVPN непосредственно на сервер и приступили к настройке.

Вот основные шаги для того, чтобы сделать всё правильно:

  1. Инициализировать PKI для OpenVPN (для создания ключей и их подписи для пользователей).

  2. Создать сертификат сервера и закрытый ключ для OpenVPN.

  3. Подписать сертификат с помощью центра сертификации, который в дальнейшем нужно провалидировать.

  4. Настроить криптографические материалы.

Для генерации ключей и защищённых подписей пользователей мы использовали криптографию на эллиптитческих кривых Elliptic Curve Cryptography (ECC). Использование ECC для обмена ключами значительно быстрее, чем использование простого алгоритма Диффи‑Хеллмана с классическим алгоритмом RSA, так как числа намного меньше, а вычисления выполняются быстрее.

  1. Настроить OpenVPN под нужные нам параметры.

OpenVPN уже идёт с примером файла конфигурации, в котором надо лишь изменить значения на нужные. Например, мы поменяли стандартный tls-auth на tls-crypt, так как при tls-crypt скрывается инициализация handhaske’а на сервере, это безопаснее и надёжнее с точки зрения обнаружения использования VPN.

Также мы поменяли стандартный криптографический шифр AES-256-CBC на AES-256-GCM, поскольку он обеспечивает более высокий уровень шифрования, производительности и лучше поддерживается современными клиентами OpenVPN.

В предыдущем шаге мы отказались от алгоритма Диффи-Хеллмана, так что надо найти строчку, которая отвечает за него, закомментировать или удалить её и указать dh none.

Далее нам нужно запустить OpenVPN без привилегий, с которыми он запущен, поэтому нам нужно указать на необходимость запуска с пользователем nobody и группой nogroup. Чтобы активировать эту возможность, найдите и раскомментируйте строки user nobody и group nogroup, удалив ";" в начале каждой строки.

Также мы изменили DNS и перенаправили весь наш трафик через сеть VPN. Для этого мы раскомментировали эти строки:

push "redirect-gateway def1 bypass-dhcp"

push "dhcp-option DNS 208.67.222.222"

push "dhcp-option DNS 208.67.220.220"

Последние две строки - это просто публичные DNS.

Помимо этого мы поменяли порт на 443 и протокол с udp на tcp.
Если вы также решите это делать, то не забудьте поменять значение с 1 на 0 в этой строке:

explicit-exit-notify 0

  1. Настроить конфигурации сети сервера OpenVPN.

    Для этого в файле /etc/sysctl.conf мы добавили следующую строчку в конце:

net.ipv4.ip_forward = 1

И применили данную настройку:

sudo sysctl -p

  1. Настроить брандмауэр под OpenVPN.

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

Вводим:

ip route list default

На выходе получаем что-то вроде такого:

Output

default via 159.65.160.1 dev eth0 proto static

Выделенный текст может отличаться - это то значение, которое нам понадобится в дальнейшем.

Далее открыли /etc/ufw/before.rules и добавили следующие правила, которые нам необходимы до загрузки обычных правил брандмауэра

# START OPENVPN RULES

*nat

:POSTROUTING ACCEPT [0:0]

-A POSTROUTING -s 10.8.0.0/8 -o eth0 -j MASQUERADE

COMMIT

# END OPENVPN RULES

Выделенный текст заменили на обнаруженный нами ранее сетевой интерфейс.

Для применения нужных нам правил в файле /etc/default/ufw мы поменяли значение с DROP на ACCEPT в данной строчке:

DEFAULT_FORWARD_POLICY="ACCEPT"

А затем просто добавили новые правила в наш брандмауэр. В нашем случае это было: 

sudo ufw allow 443/tcp 

так как мы поменяли порт и протокол. И перезапустили брандмауэр.

  1. Запустить OpenVPN на сервере, проверить рабочий статус.

  2. Настроить конфигурацию клиентской части.

Так как предполагалось, что ключей будет создаваться достаточно много, то мы решили, что возьмём некую базовую конфигурацию, которая будет применяться для всех, меняя лишь сертификаты и ключи, которые индивидуальны для каждого. Для этого мы воспользовались готовым файлом client.conf, который предлагает OpenVPN и поменяли некоторые значения под наши:

  • в строчке с remote мы указали адрес нашего сервера, на котором находится OpenVPN,

  • указали 443 порт, 

  • поменяли протокол на tcp, 

  • закомментировали строки, которые указывают на файлы с ключами и сертификатами, 

  • указали зеркальные настройки шифрования, как на нашем сервере, 

  • закомментировали директиву tls-auth, так как указываем ключ в файле и используем tls-crypt,

  • добавили строку:

key-direction 1

Затем создали простейший скрипт, который берёт базовый файл с конфигом и компонует его с необходимыми нам клиентским ключом и сертификатом.

  1. Создать первые тестовые сертификаты клиента и пары ключей.

  2. Скачать и протестировать.

Вуаля, всё работает!

Хочу посоветовать вам быть внимательнее на выше описанных пунктах, так как какая-либо неправильно записанная строка может нарушить работоспособность VPN. 

Также рекомендуем выполнить необязательный пункт и изменить настройки DNS для перенаправления всего трафика через сеть VPN. Вышеуказанные настройки создадут соединение VPN между вашим клиентом и сервером, но не будут заставлять соединения использовать туннель, а если мы немного поменяем настройки, то тогда весь трафик точно будет шифроваться. 

Это то, что мы делали в 5 пункте: указывали

push "redirect-gateway def1 bypass-dhcp".

Эти строки будут сообщать вашему клиенту о необходимости использования бесплатных интерпретаторов OpenDNS на перечисленных IP-адресах. Если вы предпочитаете использовать другие интерпретаторы DNS, вставьте их на место выделенных IP-адресов.

Это изменит настройки DNS, чтобы туннель VPN использовался как шлюз по умолчанию.

На выходе мы получили моментальный коннект, который до этого ни на одном платном VPN мы не встречали, а также стабильное высокоскоростное соединение. Приводим сравнительные замеры с сайта speedtes:

  1. обычное соединение с офисного Wi-Fi

  1. тот же сервер, но с VPN

Да, есть некоторая просадка по скорости, но в целом результат очень даже неплох.

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

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

Стоит отметить, что некоторые коллеги скачали себе OpenVPN также на телефоны и другие мобильные устройства, где тоже всё стабильно работает. 

Однако если заходить с одной клиентской конфигурации на разных устройствах, то начинается конфликт, отчего коннект может отваливаться. На сегодняшний день мы пока не решили, как сделать лучше: запускать VPN с опцией возможности коннекта нескольких устройств с одной конфигурации или же под отдельное устройство создавать новую конфигурацию. Пока что мы создаём новую конфигурацию с отметкой <user>_phone. Но дебаты ещё ведутся. 

Если есть замечания или предложения по этому вопросу, отпишитесь, пожалуйста, в комментариях.

Что мы имеем на выходе: 

  1. свой личный VPN, который обходится гораздо дешевле, чем платные аналоги;

  2. стабильный и качественный коннект для всех сотрудников;

  3. неограниченное количество подключений на организацию, ограниченное только возможностью сервера (можно масштабировать согласно росту компании).

Да, нет возможности переключать IP и выбирать разные страны, но с основными поставленными задачами наш VPN справляется на все 100%. Далее в планах запустить VPN за границей.

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


  1. interrupt
    00.00.0000 00:00

    Если тунелируете через tcp то посмотрите на tcp-nodelay опцию.


  1. aborouhin
    00.00.0000 00:00

    Однако если заходить с одной клиентской конфигурации на разных устройствах, то начинается конфликт, отчего коннект может отваливаться.

    Откройте для себя опцию duplicate-cn

    А вообще, раз уж OpenVPN - то логично прикрутить и авторизацию через LDAP/AD, и 2FA, это в нём довольно просто реализуется. Я из-за этого выбрал OpenVPN вместо более шустрого WireGuard (про Tailscale/Headscale знаю, тестировал, по ряду причин не подошло).


  1. KillJ0y
    00.00.0000 00:00
    +1

    Если подымали личный openvpn в принципе сойдёт, для корп уже с ходу не читая статью вижу ошибки, 1 - easy-rsa на той же машине что и сервер. 2 - авторизация, нет ни какой доп авторизации для конфига (ldap, даже просто пароли пользователей) tls crypt круто, я уже начал внедрять tls crypt v2, с динамическими ключами пользователей. Очередной вопрос почему easy rsa? Потому что все статьи вокруг него крутятся? Уже давно использую xca (цепочка: root ca подписал ещё пару уц (назовём их sub ca и vpn ca) и там же создаётся шаблон и по нему идёт выпуск для клиентов vpn, серт ключ экспортируются в tmpfs, там собирается конфиг. Там же генерируется список отзыва.


    1. KillJ0y
      00.00.0000 00:00

      Добавлю, лучше использовать свой dns сервер, можно реализовать запрещённые сайты и заглушку на них.


  1. merinoff
    00.00.0000 00:00

    Напилите все, что в статье, на ансибле, с сохранением ключей, и будете переезжать внутри хостинга (может даже, в разные регионы, если он поддерживает) или между хостерами.

    Технологии можете выбрать другие, но смысл вы поняли)


  1. vvv1965
    00.00.0000 00:00

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