Расширяем VPN-возможности MikroTik с помощью контейнеров - Блог о VPN и IT технологиях

Расширяем VPN-возможности MikroTik с помощью контейнеров

Автор: admin

data-gallery-root lang=»ru» data-v-497e2ccd>

Хочу поделиться опытом запуска серверов SoftEther VPN и ocserv (OpenConnect/AnyConnect) прямо на MikroTik. В RouterOS из коробки есть WireGuard, OpenVPN, SSTP, L2TP/IPsec и IKEv2, но нет сервера OpenConnect или SoftEther. Иногда нужен именно такой протокол: для клиентов Cisco Secure Client или для каскада с уже работающим сервером SoftEther.

Поднимать отдельную Linux-машину ради пары VPN-сервисов не хотелось. Начиная с RouterOS 7 в MikroTik есть поддержка контейнеров, совместимых с образами Docker Hub и Quay. Этим и воспользуемся.

Всё ниже проверено на MikroTik CHR 7.24.5 (x86_64) на KVM, 768 МБ памяти и 7 ГБ диска. На железных маршрутизаторах я не проверял, но, скорее всего, порядок тот же, только нужен образ под их архитектуру (arm/arm64) и внешний накопитель.

Краткое содержание статьи:

  • включение контейнеров и подготовка сети для них;

  • поднятие SoftEther VPN с SecureNAT или каскадом на другой сервер;

  • поднятие ocserv и настройка маршрутов для него;

  • грабли на которые наступил в процессе.

Итак, приступим.

Подготовка RouterOS

Для начала включаем пакет container. В Winbox: System → Packages → container → Enable → Apply Changes. Маршрутизатор уйдёт в перезагрузку.

Пакета мало: запуск контейнеров закрыт device-mode. Разрешаем их:

/system/device-mode/update container=yes

Изменение нужно подтвердить физически в течение 5 минут. На железе это кнопка reset, на CHR — выключение и включение из панели провайдера: Power off, затем Power on. /system reboot и кнопка Reboot в панели не подойдут.

Проверяем:

/system/device-mode/print

Должно быть container: yes. Если там no и attempt-count: 1, попытка была, но не подтвердилась. Повторяем.

Далее готовим сеть. Каждому контейнеру нужен свой veth-интерфейс, а все veth мы соберём в один bridge. Адреса берём из свободной подсети, у меня это 10.10.4.0/24:

/interface/bridge add name=br-containers /ip/address add address=10.10.4.1/24 interface=br-containers /ip/firewall/nat add chain=srcnat src-address=10.10.4.0/24 action=masquerade /interface/veth add name=veth-softether address=10.10.4.2/24 gateway=10.10.4.1 /interface/veth add name=veth-ocserv address=10.10.4.3/24 gateway=10.10.4.1 /interface/bridge/port add bridge=br-containers interface=veth-softether /interface/bridge/port add bridge=br-containers interface=veth-ocserv

RouterOS сам назначит контейнеру адрес и шлюз из настроек veth: внутри он станет eth0. DHCP здесь не участвует.

Внешний трафик попадает в контейнеры только через dst-nat, а наружу они выходят через masquerade роутера. Осталось указать реестр и папку для распаковки образов:

/container/config set registry-url=https://registry-1.docker.io tmpdir=pull

SoftEther VPN

Используем официальный образ softethervpn/vpnserver. У него есть нюанс: тег stable — это ветка 4.x, и настройки она хранит в /mnt. Ветка 5.x (теги вида 5.2.5188) хранит их в /var/lib/softether. Путь в mount должен соответствовать тегу, иначе пароли и пользователи будут пропадать при пересоздании контейнера. Я брал stable.

Папку для настроек заранее не создаём: если её нет, RouterOS заполнит её содержимым образа. Создаём mount и контейнер:

/container/mounts/add list=SE_DATA src=softether/data dst=/mnt /container add remote-image=softethervpn/vpnserver:stable interface=veth-softether root-dir=softether/root mountlists=SE_DATA name=softether logging=yes start-on-boot=yes

root-dir — это файловая система самого контейнера, она заменяется при обновлении образа. Настройки живут отдельно, в mount.

Ждём, пока образ скачается (status=stopped в /container print), и запускаем:

/container start softether

В логах должна появиться строка started /usr/local/bin/vpnserver execsvc. Ошибка dmesg: klogctl: Operation not permitted говорит, что сервер пытается прочитать журнал ядра, а контейнеру это запрещено.

После первого запуска пароля администратора нет. Задаём пароль до того, как откроем порт наружу:

/container shell softether vpncmd localhost /SERVER /CMD ServerPasswordSet ls -la /mnt exit

В /mnt должен появиться конфиг файл vpn_server.config. Затем пробрасываем порт. Берём 444 для примера:

/ip/firewall/nat add chain=dstnat in-interface-list=WAN protocol=tcp dst-port=444 action=dst-nat to-addresses=10.10.4.2 to-ports=443

Дальше удобнее работать через SoftEther VPN Server Manager: подключаемся к IP:444 с паролем администратора и создаём пользователей в хабе (Manage Users → New). Как клиенты получат IP-адреса и выход в интернет, зависит от режима.

Режим SecureNAT

SecureNAT — встроенный в хаб DHCP и NAT, который работает полностью в userspace. TUN, iptables и дополнительные права ему не нужны, поэтому в контейнере RouterOS он работает сразу. Включаем в Manage Virtual Hub → Virtual NAT and Virtual DHCP Server (SecureNAT) → Enable SecureNAT. Клиенты получат адреса из 192.168.30.0/24, а DNS будет пересылаться в DNS маршрутизатора.

Каскад на другой сервер SoftEther

У меня уже был сервер SoftEther на Linux с Local Bridge на TAP-интерфейс и dnsmasq в роли DHCP. Cascade Connection соединяет хабы SoftEther на уровне L2 в одну логическую сеть.

Порядок действий:

  1. На удалённом сервере SoftEther создаём отдельного пользователя для каскада.

  2. На SoftEther в MikroTik выключаем SecureNAT в хабе. Иначе его DHCP через каскад начнёт раздавать адреса устройствам удалённой сети.

  3. Manage Cascade Connections → New: адрес и порт удалённого сервера, имя его хаба, пользователь из первого шага.

  4. Нажимаем Online. Статус должен смениться на Online (Established).

Важно: каскад настраиваем только в одну сторону, иначе каскад с обеих сторон даст петлю.

ocserv

С ocserv сложнее: ему нужны TUN, ip_forward и iptables. В Docker их даёт cap_add: NET_ADMIN, а в RouterOS такого параметра нет. На практике контейнер RouterOS спокойно создаёт TUN и меняет сетевые настройки внутри своего сетевого пространства. Режим privileged=yes мне не понадобился.

Берём образ aminvakil/ocserv. Актуальные версии лежат на Quay: на Docker Hub есть образ с таким же именем, но он не обновлялся с 2020 года.

Запуск

Сеть для VPN-клиентов задаём переменными окружения. У меня это 10.10.5.0/24. Всю папку /etc/ocserv монтируем наружу: там конфиг, сертификаты и пользователи.

/container/envs/add list=OC_ENV key=OC_IPV4_NETWORK value=10.10.5.0 /container/envs/add list=OC_ENV key=OC_IPV4_NETMASK value=255.255.255.0 /container/mounts/add list=OC_DATA src=ocserv/conf dst=/etc/ocserv

Реестр в RouterOS задаётся одной общей настройкой на все контейнеры. Временно переключаем его на Quay и создаём контейнер:

/container/config set registry-url=https://quay.io /container add remote-image=aminvakil/ocserv:latest interface=veth-ocserv root-dir=ocserv/root envlist=OC_ENV mountlists=OC_DATA name=ocserv logging=yes start-on-boot=yes

Когда образ скачался, возвращаем Docker Hub, иначе SoftEther потом не обновится. Запускаем:

/container/config set registry-url=https://registry-1.docker.io /container start ocserv

При первом запуске образ сам создаёт самоподписанный сертификат и тестового пользователя test с паролем test. Создаём своего пользователя и не забываем удалить тестового:

/container shell ocserv ocpasswd -c /etc/ocserv/ocpasswd user1 ocpasswd -c /etc/ocserv/ocpasswd -d test exit

Пробрасываем порт. ocserv работает по TCP и по UDP (DTLS), поэтому нужны оба протокола:

/ip/firewall/nat add chain=dstnat in-interface-list=WAN protocol=tcp dst-port=8443 action=dst-nat to-addresses=10.10.4.3 to-ports=443 /ip/firewall/nat add chain=dstnat in-interface-list=WAN protocol=udp dst-port=8443 action=dst-nat to-addresses=10.10.4.3 to-ports=443

Маршрутизация и NAT

RouterOS должен знать, что сеть клиентов ocserv находится за контейнером. Добавляем маршрут и masquerade:

/ip/route add dst-address=10.10.5.0/24 gateway=10.10.4.3 /ip/firewall/nat add chain=srcnat src-address=10.10.5.0/24 out-interface-list=WAN action=masquerade

Есть тонкий момент. Скрипт образа при каждом старте добавляет свой MASQUERADE для сети клиентов. Тогда RouterOS видит трафик с адреса контейнера 10.10.4.3, а не с адресов клиентов. Для интернета это не важно, но правила firewall и маршрутизации по адресам клиентов срабатывать не будут.

Правило строится по переменной OC_IPV4_NETWORK, а сам ocserv берёт сеть из уже созданного ocserv.conf. Поэтому после первого запуска перенаправляем правило на документационную сеть TEST-NET-1, пакетов из которой не бывает:

/container/envs/set [find list=OC_ENV key=OC_IPV4_NETWORK] value=192.0.2.0 /container stop ocserv /container start ocserv

Если когда-нибудь удалите ocserv.conf, сначала верните переменную на 10.10.5.0. Иначе клиенты начнут получать адреса 192.0.2.x.

Доступ к внутренним сетям

Следующая проблема: с клиента не открывалась внутренняя сеть 172.31.0.0/16, хотя маршрутизация на RouterOS была в порядке. Образ добавляет в конфиг исключения для всех частных сетей, чтобы у клиентов не пропадал доступ к домашним сетям:

route = default no-route = 192.168.0.0/255.255.0.0 no-route = 10.0.0.0/255.0.0.0 no-route = 172.16.0.0/255.240.0.0 no-route = 127.0.0.0/255.0.0.0

no-route говорит клиенту не отправлять этот трафик в VPN. Убираем нужное исключение и добавляем явный маршрут:

/container shell ocserv sed -i ‘/^no-route = 172.16.0.0/255.240.0.0/d’ /etc/ocserv/ocserv.conf echo «route = 172.31.0.0/255.255.0.0» >> /etc/ocserv/ocserv.conf exit /container stop ocserv /container start ocserv

Маршруты передаются клиенту только при подключении, поэтому переподключаемся и проверяем.

Грабли

Собрал в одном месте всё, что отняло время.

Симптом

Причина

Решение

device-mode остаётся container: no

мягкая перезагрузка не считается подтверждением

Power off и Power on из панели VPS в течение 5 минут

Winbox не сохраняет контейнер: Error in Shm Size

Winbox не читает своё же значение по умолчанию 64.0 MiB

стереть поле или создавать контейнер из терминала

Образ не скачивается

по умолчанию реестр — lscr.io

задать registry-url в /container/config

После ocserv не обновляется SoftEther

registry-url один на все контейнеры и остался quay.io

вернуть Docker Hub после скачивания

Настройки SoftEther сбрасываются

mount не совпадает с веткой образа

stable → /mnt, 5.x → /var/lib/softether

Ошибки iptables про nf_tables в логе ocserv

ядро RouterOS может не поддерживать nft-вариант iptables

NAT делает RouterOS, самому ocserv iptables не нужен

Правила по адресам клиентов ocserv не срабатывают

MASQUERADE внутри контейнера подменяет адрес клиента

OC_IPV4_NETWORK=192.0.2.0 после первого запуска

С клиента не видно внутреннюю сеть

no-route для частных сетей в ocserv.conf

удалить исключение и добавить route

Режим privileged=yes в RouterOS 7.24 есть, но включать его ради VPN не стоит. Privileged-контейнер может менять firewall и форматировать диски маршрутизатора, а в том, что описано выше, он не нужен.

Итоги

Оба VPN-сервера работают на MikroTik без privileged и без отдельной Linux-машины. SoftEther заводится проще, ocserv требует больше внимания к маршрутизации.

SoftEther VPN

ocserv

Образ

softethervpn/vpnserver:stable (Docker Hub)

aminvakil/ocserv:latest (Quay)

Настройки

/mnt

/etc/ocserv

Клиенты

SoftEther Client, OpenVPN, SSTP, L2TP/IPsec

Cisco Secure Client, OpenConnect

Адреса клиентам

SecureNAT или DHCP удалённой стороны через каскад

пул из ocserv.conf, маршрут на RouterOS

Управление

Server Manager (GUI) и vpncmd

ocpasswd и правка ocserv.conf

Порты у меня

444/tcp

8443/tcp и 8443/udp

Если нужен просто надёжный VPN, сначала стоит посмотреть на встроенные в RouterOS WireGuard или OpenVPN. Контейнеры имеют смысл, когда нужен конкретный протокол или совместимость с уже работающей инфраструктурой.

Источники:

  • MikroTik — Containers

  • SoftEtherVPN-docker — Dockerfile.stable

  • SoftEtherVPN — Dockerfile (5.x)

  • aminvakil/docker-ocserv

Вам также может понравиться

Оставить комментарий