Обновленная версия статьи со всеми конфигами доступна на моём сайте r4ven.me.
Сегодня будем разворачивать свой VPN на базе OpenConnect сервера (ocserv), работающего поверх HTTPS и который совместим с Cisco Anyconnect. Все это добро мы упакуем в docker контейнер для простоты использования и лёгкой переносимости.
Данный сервер планируется использовать, как основной связующий элемент, с помощью которого будем настраивать сетевое взаимодействие будущих проектов и сервисов. Сама установка сервера выполняется всего в несколько команд. Будет интересно ;)
Присоединяйтесь к нашему каналу: t.me/r4ven_me и чату: t.me/r4ven_me_chat в Telegram.
Обращаю ваше внимание, что предоставленная в данной статье информация предназначена исключительно для образовательных целей. Любые действия, основанные на этой информации, осуществляются на ваш собственный риск и ответственность.
Введение
Пару слов о том, в чем смысОл всего происходящего.
В корпоративном мире существует продукт Cisco AnyConnect, который представляет собой проприетарное ПО для организации виртуальных частных сетей (VPN), разработанное компанией Cisco.
Как это часто бывает в IT индустрии, если образуется весомый спрос на продукт, который имеет закрытый исходный код, появляется его “открытая” реализация. Самым популярным примером такого явления является Linux.
Как вы могли догадаться, рассматриваемый нами сегодня OpenConnect – это open source реализация ПО для организации VPN сервиса, совместимого с Cisco AnyConnect.
Вот что говорит зарубежная вики про OpenConnect:
WikipediaOpenConnect is a free and open-source cross-platform multi-protocol virtual private network (VPN) client software which implement secure point-to-point connections.
Проект OpenConnect также включает в себя сервер, который называется ocserv (OpenConnect server) и тем самым обеспечивает полноценное клиент-серверное VPN решение.
Основные преимущества такого решения:
- Кроссплатформенность: клиенты под Linux, Windows, MacOS, Android, iOS, HarmonyOS;
- Гибкость настройки, в т.ч. для каждого пользователя;
- Шифрование соединения на основе SSL/TLS;
- Простота настройки и использования;
- Множество способов авторизации + двухфакторная;
- и многое другое.
Предварительная подготовка
Для удобства и простоты использования мы с вами будем разворачивать OpenConnect сервер в docker контейнере, путем сборки образа и его запуска с помощью docker-compose. Обязательным условием является настроенный Linux сервер с установленным и запущенным в нем docker engine. А также наличие root привилегий (для моего примера) или группы docker у пользователя, если будете выполнять установку по своему.
Если с какой-то из пунктов отсутствует, возможно вам будут полезны следующие статьи:
В статье про установку docker’а также есть ссылки на полезные материалы, где доступным языком объясняется, что это такое, для чего нужен и из чего состоит. Если вы ранее не работали с данной технологией контейнерной виртуализации, то я настоятельно рекомендую их к прочтению.
Так, как ocserv работает поверх HTTPS c SSL шифрованием, рекомендованным (но необязательным) условиям является наличие валидного доменного имени. Конкретнее – DNS записи типа A, указывающую на внешний IP адрес вашего сервера. Добавление такой записи производится в настройках DNS вашего провайдера домена. В моём примере используется адрес: vpn.r4ven.me. При настройке OpenConnect адрес DNS необходим для бесплатного получения официальных SSL сертификатов от проекта Let’s Encrypt.
Если домена у вас нет, то при настройке сервера вместо DNS имени указывайте его IP адрес. При такой настройке на VPN клиентах при подключении будет выплывать уведомление о подключении к неподтвержденному источнику. В этом нет ничего страшного, просто это неудобно, и если честно, раздражает)
Схема проекта
Для визуального подкрепления, ниже представлена схема проекта будущего OpenConnect VPN сервера:
Сохранив картинку в голову, приступаем к установке и настройке.
Развертывание OpenConnect VPN сервера в docker
Пример развертывания OpenConnect сервера из статьи выполнялся в среде дистрибутива Debian 12.
Для быстрого и удобного поднятия своего VPN сервера я подготовил небольшой проект с использованием docker, docker-compose и bash.
Весь процесс настройки сервера OpenConnect внутрни контейнера был автоматизирован.
Вот краткое описание проекта:
- Сборка образа docker на основе Debian 12;
- Установка в образ сервера ocserv и вспомогательных утилит;
- Копирование в образ bash скрипта oscerv.sh;
- При первом старте скрипт создает необходимые файлы и папки, в т.ч. основной конфиг ocserv.conf, скрипты подключения/отключения и файлы сертификатов;
- Всё это сохраняется в docker volume, который монтируется в папочку ./data;
- Файлы сервера можно с легкостью переносить на другие системы/платформы, где работает docker (просто перенесите папку ./data);
- Конфиг файлы сервера можно кастомизировать под свои нужды;
- При старте контейнера скрипт oscserv.sh проверяем наличие файлов в директории ./data, если они есть, то просто запускается сервер, если нет, файлы создаются заново, и после запускается сервер;
- Все необходимые значения для конфигов и сертификатов берутся из переменных окружения, определенные в файле .env (если не указать, будут использованы дефолтные значения);
Так, воды налил, теперь давайте приступать к установке и настройка нашего сервера.
Обновление системы
Первым делом рекомендуется обновить вашу систему до актуального состояния:
sudo -s
apt update && apt upgrade -y
Клонирование репозитория с исходными файлами проекта
Для клонирования git репозитория нам потребуется утилита командной строки, из состава пакета одноимённой системы контроля версий – git. Если эта система у вас не установлена, то выполняем:
apt install git
Теперь клонируем репозиторий с подготовленными файлами из моего GitHub, далее копируем директорию openconnect-src по пути /opt/openconnect и переходим в неё:
git clone https://github.com/r4ven-me/docker.git
cp -r ./docker/openconnect/openconnect-src /opt/openconnect
cd /opt/openconnect
Директория /opt (optional) предназначена для установки “дополнительного” программного обеспечения, которое не является стандартным для данной ОС.
Файлы проекта имеет следующую структуру:
Где:
- docker-compose.yml - файл описания сервисов (контейнеров) openconnect и certbot (Let's Encrypt)
- Dockerfile - файл описания docker образа сервера openconnect для сборки
- ocserv.sh - bash скрипт, запускаемый при старте контейнера, который выполняет начальную конфигурацию и инициацию процесса ocserv
- openconnect.service - файл unit'а systemd для автозапуска
- ssl_update.sh - bash скрипт обновления SSL сертификатов от Let's Encrypt
Переопределение переменных: домен, имя сервера, email и пр.
Теперь необходимо задать переменные окружения, которые будут использованы для автоматической подстановки при сборке и запуске контейнера. Для этого открываем любым редактором файл .env, лежащий в директории с файлами проекта:
Файл .env обычно используется для определения переменных окружения, которые считываются утилитой docker-compose, при обращении к ним в файле описания сервисов – docker-compose.yml. Также эти переменные мы передадим внутрь контейнера openconnect.
vim .env
Всего 5 переменных:
- TZ – временная зона;
- SRV_PORT – сетевой порт подключения к серверу;
- SRV_CN – тут задаём доменное имя, которое указывает на Linux сервер (если домена нет, то указываем произвольное имя);
- SRV_CA – названия центра сертификации для самоподписанных сертификатов;
- USER_EMAIL – адрес электронной почты, если используется доменное имя. Данный параметр обязателен для получения SSL сертификатов от letsencrypt.
Сохраняем файл и выходим:
:wq
К слову, в качестве консольного редактора я предпочитаю vim/neovim. Подробнее про этот редактор смотрите статьи по соответствующему тегу: Vim/Neovim.
Сборка образа и первый запуск контейнера с помощью docker-compose
Если у вас нет домена, переходите к шагам внутри спойлера ниже: “Клик сюда, если домена нет”
Теперь просто запускаем команду сборки образа с последующим запуском контейнера в фоновом режиме и после подключаемся к стандартному выводу docker-compose:
docker-compose up -d && docker-compose logs -f
Обратите внимание, что сервис openconnect, описанный в файле docker-compose.yml намеренно ограничен в аппаратных ресурсах на использование cpus: '0.50' и memory: 200M, т.е максимально разрешенное использование CPU составляет 50% одного ядра и 200 мб RAM. При необходимости скорректируйте данные параметры в соответствии со своими потребностями.Подробнее про лимиты ресурсов сервисов при использовании docker-compose читайте тут.
В docker-compose.yml параметром depends-on указан порядок запуска сервисов. Сперва отрабатывает certbot (Let’s Encrypt), который запрашивает и получает валидные SSL сертификаты, и только затем стартует контейнер с VPN сервером:
Подробную документацию по использованию certbot смотрите тут.
В случае успеха вывод будет, как на скрине выше. Просмотр вывода можно прервать комбинацией Ctrl+C.
Чтобы убедится, что контейнер запущен выполняем:
docker-compose ps
ls -l ./data
ls -l ./data/ssl/live/vpn.r4ven.me/
Должна создаться папка ./data с файлами сервера + сертификаты, полученные контейнером cerbot.
Также проверяем прослушиваемый и проброшенный в хост контейнером TCP порт, такой командой:
ss -tnap | grep -E '43443'
Всё, сервер запущен и работает. Осталось создать пользователей и настроить клиентское подключение.
Если домена нет
В таком случае правим файл описания сервисов docker-compose.yml:
vim docker-compose.yml
В этом файле необходимо закоментировать сервис certbot и директиву depends_on у сервиса openconnect, как показано на скриншоте:
После чего запускаем сборку и смотрим вывод:
docker-compose up -d && docker-compose logs -f
Если все отработало корректно, выходим из режима просмотра логов клавишей Ctrl+C и проверяем запущенный сервис:
docker-compose ps
ss -tnap | grep -E '43443'
Также проверяем наличие системных файлов ocserv:
ls -l ./data
Отлично, идём дальше.
Создание пользователей
Пару слов про способы авторизации на OpenConnect сервере.Т.к. ocserv популярен в корпоративном мире, он поддерживает множество способов авторизации пользователей. От банального логина/пароля, до интеграции с централизованными инструментами, такими, как LDAP/Active Directory, PAM, Radius и пр. Из коробки даже имеется поддержка двухфакторной аутентификации на основе токенов. Для нас это уже излишне, но вас никто не ограничивает)В качестве надежного и в тоже время удобного способа авторизации я выбрал подключение на основе пользовательского сертификата, который упаковывается в шифрованный (при указании пароля) файл с расширением .p12. В результате со стороны клиента необходимо будет лишь указать путь до файла сертификата и пароль для его расшифровки. Обычно клиенты способны запоминать пароли и вводить их более не требуется.Стоит отметить, что для создания пользователя ему все таки необходимо задать пароль, хоть и такой способ авторизации отключен в конфиг файле сервера. Если вы проявили любопытство и заглянули в содержимое скрипта создания пользователей ocuser, то могли заметить команду генерации псевдослучайной строки: tr -cd “[:alnum:]” < /dev/urandom | head -c 60Вывод которой задается в качестве пароля для пользователя при его создании. Небольшая подстраховка)
Создание пользователей для Linux/Windows/Android
И так, создаём пользователя такой командой:
docker exec -it openconnect ocuser ivan 'Ivan Cherniy'
Где ivan – это имя и идентификатор пользователя в ocserv (старайтесь указывать идентификатор без пробелов, дабы избежать ошибок), а ‘Ivan Cherniy’ это полное имя пользователя, которое будет отображено в метаданных пользовательского сертификата.
После ввода команды необходимо будет в интерактивном режиме указать имя файла сертификата и пароль для его шифрования.
Если команда создания отработала успешно, для указанного пользователя будет создан файл сертификата .p12 в директории secrets:
ls -l ./data/secrets
Список пользователей можно посмотреть в файле ./data/ocpasswd.
Создание пользователей для HarmonyOS/iOS
При создании пользователей для мобильных ОС от Huawei и Apple команде ocuser необходимо передать ключ -A. В таком случае будет использован другой алгоритм шифрования сертификата.
Пример команды:
docker exec -it openconnect ocuser -A steve 'Steve Jobs'
Проверяем созданный сертификат:
ls -l ./data/secrets
Если для устройств под управлением HarmonyOS и iOS сгенерировать сертификаты без ключа -A, то при настройке клиентского подключения, вы будете получать ошибку на этапе импорта сертификата.
linuxbabe.comNote that the Ciso AnyConnect app on iOS doesn’t support AES-256 cipher. It will refuse to import the client certificate. If the user is using iOS device, then you can choose the 3des-pkcs12cipher.
Скачивание файла p12
Скачиваем созданный файл сертификата пользователя удобным для вас способом. Например:
cp ./data/secrets/ivan.p12 /tmp
А на клиентской машине:
scp vpn.r4ven.me:/tmp/ivan.p12 .
ls -l ivan.p12
На этом этапе уже можно переходить к настройке клиентов. Но если вам нужны персональные настройки каждого пользователя, такие как IP адрес клиента, маршруты, DNS, а также настройка автозапуска сервиса OpenConnect и автопродление SSL сертификатов, то идём последовательно.
Опционально: индивидуальные настройки ocserv для каждого пользователя
Создаём системную директорию config-per-user и отдельный файл под каждого пользователя, с таким же именем, какое указывали при создании (если забыли, посмотрите в файле ./data/ocpasswd):
mkdir ./data/config-per-user
vim ./data/config-per-user/ivan
Название параметров в файле конфига пользователя в большинстве своем идентичны основному конфигу сервера:
explicit-ipv4 = 10.10.10.5
route = 10.10.10.50/32
route = 64.233.164.139/32
dns = 1.1.1.1
В примере выше я задаю для пользователя ivan конкретный IP (из подсети, что указана в основном конфиге), отдельные маршруты и адрес DNS сервера.
Upd. Если вы предпочитаете повысить уровень конфиденциальности, то при тунелировании трафика желательно иметь собственный DNS сервер. Вот инструкция по его настройке и интеграции с OpenConnect:
Поднимаем свой DNS сервер Unbound и блокировщик рекламы Pihole в docker
При такой конфигурации данный пользователь будет обращаться к указанным ресурсам через VPN сервер, а остальной трафик будет идти через его шлюз по умолчанию (или нет, в зависимости от настроек сети).
После внесения изменений в конфиг необходимо выполнить перечитывание файла конфигурации процессом ocserv внутри контейнера. Делается такой командой:
docker exec -it openconnect occtl reload
Автозапуск сервера OpenConnect с помощью systemd
Теперь настроим автоматический запуск/перезапуск нашего VPN сервера при помощи системы инициализации systemd.
Из директории с файлами проекта копируем файл openconnect.service в системную директорию systemd, перезагружаем конфигурацию systemd и останавливаем наши запущенные контейнеры:
cp ./openconnect.service /etc/systemd/system/
systemctl daemon-reload
docker-compose down
Теперь активируем автозапуск и пробуем выполнить старт контейнера с OpenConnect сервером как сервис systemd:
systemctl enable --now openconnect
systemctl status openconnect
docker-compose ps
Все отлично.
Настройка автоматического обновления SSL сертификатов (если есть домен)
Особенностью сертификатов от центра сертификации Let’s Encrypt является то, что они выдаются на 3 месяца. В такой ситуации предусмотрительно будет настроить автоматическое продление. Для этого добавляем в системный планировщик заданий cron запуск скрипта ssl_update.sh раз в неделю, например, в воскресенье в 3 часа утра:
{ crontab -l; echo "0 3 * * 0 /opt/openconnect/ssl_update.sh"; } | crontab -
crontab -l
Синтаксис фигурных скобок в bash { command1; command2 } позволяет объединить несколько команд в одну. Тут мы с его помощью первой командой выводим список заданий cron текущего пользователя, второй командой выводим строку с новым заданием и потом с помощью механизма перенаправления передаем весь вывод команде crontab -. Если команде crontab - передать только одну задачу, он затрет все предыдущие. Так делать не стоит)Хоть и в моём примере нет других заданий в планировщике, команда специально составлена с “защитой от дурака”)
Для проверки работоспособности скрипта продления сертификатов, можем выполнить его вручную:
/opt/openconnect/ssl_update.sh
Скрипт также почистит дисковое пространство от неиспользуемых образов docker:
Проверяем время обновления SSL файлов:
ls -l ./data/ssl/live/vpn.r4ven.me/
Так, вроде все хорошо)
Обратите внимание, что если слишком часто обновлять сертификаты, то certbot (letsencrypt) будет выпадать в ошибку по этой причине.
Настройка подключения клиентов
Настройка OpenConnect клиента для Linux
Способ №1: менеджер сетевых соединений – NetworkManager
Если вы пользователь популярных дестопных дистрибутивов, то вероятнее всего вашей сетевой подсистемой управлет NetworkManager.
Сразу отмечу, что данный способ предпочтителен для десктопных систем, т.к. при использовании NM для подключения к ocserv не происходит конфликтов системы DNS.
В случае deb based систем, выполняем установку специального пакета-плагина NetworkManager для подключения к ocserv.
По традиции, продемонстрирую на примере Linux Mint 21 Cinnamon (Ubuntu 22.04).
Команда установки плагина:
sudo apt update && sudo apt install network-manager-openconnect-gnome
После установки:
- Заходим в “Сетевые соединения” через трей или любым удобным вам способом;
- Затем нажимаем кнопку добавления нового соединения, в списке выбираем “Cisco AntConnect or openconnect (OpenConnect)” и нажимаем “Создать“;
- В открвшемся окошке указываем“Имя соединения” – произвольное
“Шлюз” – DNS имя нашего сервера или его IP адрес (если без домена) + порт подключения. Пример: vpn.r4ven.me:43443 - В разделе “Аутентификации по сертификату” в параметре “Сертификат пользователя” выбираем наш .p12 файл, который мы сгнерировали на этапе создания пользователя. В старых версиях nmapplet’а есть баг, когда при выборе сертификата он не видит файлы с расширенияем .p12. В таком случае просто перетащите (drag-and-drop) файл с файлового менеджера в поле данного параметра, как показано на скриншоте ниже;
- После нажимаем “Сохранить”.
Если все сделано корректно, пробуем подключиться к нашему серверу. Кликаем на апплет сетевых соединений, затем на переключатель “VPN подключения“. Должно появиться окошко, где нас любезно попросят ввести пароль от файла-сертификата (если вы его задавали), который мы устанавливали на этапе создания пользователей ocserv. Ставим галочку “Сохранить пароль” и затем “Подключиться“. При успешном соединении на рабочем столе появится соответствующее уведомление:
Также новое подключение для NetworkManager можно создать с помощью консольной утилиты nmcli. Вот пример:
nmcli connection add \
type vpn \
con-name "vpn.r4ven.me" \
ifname '*' \
vpn-type openconnect \
vpn.data "gateway=vpn.r4ven.me:43443, usercert=/home/ivan/ivan.p12"
Пробуем подключиться:
nmcli connection up vpn.r4ven.me
Успешно.
Посмотреть сетевые параметры нашего VPN подключения можно с помощью команд:
ip -c address
nmcli
Узнать внешний IP в консоли можно такой командой:
curl ifconfig.me
В выводе команды будет одна строка с вашим внешним IP адресом.
Способ №2: утилита командной строки – openconnect
Другой способ клиентского подключения в Linux, где отсутствует NetworkManager – это одноименная консольная утилита openconnect. Такой способ подключения чаще всего используется для клиентов без GUI, т.е. на Linux серверах.
Пример подключения все также для deb based систем.
Выполняем установку клиентского пакета openconnect:
sudo apt update && sudo apt install openconnect
Подключится к серверу OpenConnect можно такой командой:
# если с доменом
sudo openconnect -c /home/ivan/ivan.p12 vpn.r4ven.me:43443
# если без домена (с доп. подтверждением самоподписанного сертификата)
sudo openconnect -c /home/ivan/ivan.p12 12.345.67.89:43443
Где ключу -c передается путь до файла сертификата .p12.
Для автоматизации процесса подключения с помощью утилиты openconnect я написал небольшой скрипт. Изучить его можно в статье: Пишем bash скрипт для подключения к OpenConnect VPN серверу.
Результат команды подключения должен быть примерно таким:
Если вы используете подключение с помощью утилиты openconnect на Linux сервере, и планируете туннелировать весь его трафик, то необходимо добавить специальные правила маршрутизации, без которых вы потеряете доступ до своего сервера, в т.ч. и по SSH:
ip rule add table 128 from <public-ip>
ip route add table 128 to <public_ip_subnet> dev <ineteface_name>
ip route add table 128 default via <gateway>
Где:
- 128 – имя новой таблицы маршрутизации;
- <piblic-ip> – основной IP вашего сервера;
- <public_ip_subnet> – подсеть основного IP сервера;
- <interface_name> – имя физического интерфейса, к которому подключен основной IP;
- <gateway> – шлюз сети, через который ходит основной IP.
Настройка OpenConnect клиента для Windows/MacOS
Для настройки клиента на Windows и MacOS необходимо скачать графическую программу-клиент с официального сайта https://gui.openconnect-vpn.net/download/ или на странице релизов в GitLab: https://gitlab.com/openconnect/openconnect-gui/-/releasesGitLab:
Далее устанавливаем программу на рабочий стол Windows обычными кликами “Далее, далее..”. А вот как установить клиента на MacOS я вам не подскажу, т.к. не являюcь потребителем “фруктов не первой свежести” ;). Тут уже вы сами изучите вопрос, ссылки на все материалы будут внизу.
После установки и запуска программы OpenConnectVPN выполняем настройку, как показано на скриншотах ниже. Отмечу лишь один момент: обязательно активируйте параметр “Disable UDP“, т.к. в нашей конфигурации сервера его использование отключено:
Проверяем сетевые параметры:
Все работает.
Настройка OpenConnect клиента для Android/HarmonyOS/iOS
Для мобильных ОС необходимо установить приложение Cisco Secure Client-AnyConnect.
Пожалуйста, обратите внимание, что данное мобильное приложение не имеет открытый исходный код. При его использовании придется довериться разработчику.Существует open source мобильный клиент, но его разработка прекратилась n-е количество лет назад и у меня оно работало некорректно.
После открытия приложения необходимо создать подключение, указать адрес шлюза + порт и импортировать сертификат пользователя. Пошаговая инструкция показана на скриншотах ниже:
Ну вот, вроде бы всё.
Полезные команды docker/docker-compose/ocserv
Небольшой список команд, который может вам пригодится при настройке и обслуживании OpenConnect сервера.
# показывает список всех доступных образов
docker docker image ls
# показывает список всех контейнеров docker, включая работающие и остановленные
docker container ls -a
# удаляет все ненужные ресурсы docker, такие как неиспользуемые контейнеры, образы, сети и тома, без запроса подтверждения
docker system prune -af
# показывает статус и информацию о контейнерах, запущенных с помощью
docker-compose docker-compose ps
# запускает контейнеры из файла docker-compose.yml в фоновом режиме
docker-compose up -d
# останавливает и удаляет все контейнеры, сети, запущенные с помощью docker-compose
docker-compose down
# отображает стандартный вывод контейнеров, запущенных с помощью
docker-compose docker-compose logs -f
# перезапуск контейнера с именем "openconnect"
docker-compose restart openconnect
# запускает интерактивную оболочку bash внутри контейнера "openconnect"
docker exec -it openconnect bash
# выводит справку по команде утилиты управления VPN сервером
docker exec -it openconnect occtl --help
# перечитывает файл конфигурации ocserv
docker exec -it openconnect occtl reload
# показывает статус ocserv
docker exec -it openconnect occtl show status
# показывает список пользователей ocserv
docker exec -it openconnect occtl show users
# показывает список активных сеансов ocserv
docker exec -it openconnect occtl show sessions all
# создает пользователя с id "ivan" и именем "Ivan Cherniy" для ocserv
docker exec -it openconnect ocuser ivan 'Ivan Cherniy'
Заключение
Фух! Создание данного материала заняло приличное количество времени и сил, но они было потрачены не зря. В процессе подготовки я узнал много нового и про работу сети в Linux, и множество нюансов bash при написании скриптов проекта и многое другое.
В будущем буду писать статьи по развертыванию различных персональных сервисов, и для доступа к ним будет использоваться VPN подключения на базе OpenConnect.
Если у вас возникли трудности с настройкой или остались вопросы, то смело оставляйте комментарии к данной статье или в нашем чате телеги: @r4ven_me_chat.
Также не забудьте подписаться на наш телеграм канал:@r4ven_me. Ссылки на все новые статьи появляются там в момент публикации.
Спасибо, что вместе со мной осилили данную статью. Успехов вам!
Используемые материалы
Мои ссылки:
- Мой основной сайт - r4ven.me
- Мой телеграм - t.me/r4ven_me