Привет, Хабр! Меня зовут Олег, я архитектор клиентских решений в Selectel. Недавно мы столкнулись с интересным клиентским кейсом при создании Full-Mesh сети. Расскажу, как пришлось тестировать VPN-сервисы, чтобы найти оптимальное решение.
Все результаты собрал в сводной таблице, чтобы наглядно показать разницу и аргументировать выбор.
К нам обратился клиент с задачей по переносу данных с арендованных выделенных серверов одного популярного в России поставщика услуг из Германии. На то было две причины:
Невозможность простой и быстрой оплаты услуг, поскольку привязанная карта российского банка перестала работать.
Защита от возможной эскалации санкционного давления (то есть полный запрет работы).
Если в первом случае мы помогли временно решить проблему, то во втором никаких гарантий дать не могли. Поэтому клиент принял решение мигрировать в Selectel, воспользовавшись специальным предложением.
C чем мы столкнулись
Компания арендовала в Германии такую инфраструктуру:
два сервера-гипервизора на базе Qemu/KVM с управлением через libvirtd,
два сервера c Docker-контейнерами для разработчиков и их заказной CRM/ERP-системой,
несколько виртуальных машин на Linux и Windows Server 2019.
Со схемой можно ознакомиться ниже:
Сначала мы изучили текущее клиентское решение и предложили на его основе свою схему миграции, которая бережно относилась к текущей IT-инфраструктуре и при этом не теряла в отказоустойчивости.
Далее мы занялись обеспечением сетевой связности на втором уровне стека протоколов TCP/IP. Так мы смогли обеспечить клиенту «бесшовный» перенос виртуальных машин и сохранить IP-адреса. Чтобы оптимизировать бюджет, клиент выбрал серверы линейки Chipcore, в которых отсутствует «приватная сеть».
На этапе миграции остановились на следующей организации сетевой топологии. Так мы обеспечили единую L2-связность между дата-центром Selectel и зарубежным ЦОД:
Потенциальные кандидаты
Дело осталось за малым — подобрать VPN, который прост в настройке, поддерживает L2, полносвязную топологию и использует быстрые, криптостойкие алгоритмы шифрования.
Вариант с Wireguard был отброшен сразу: он не работает по L2, только по L3, хотя продукт достойный.
OpenVPN — в данном случае не лучший выбор, так как имеет клиент-серверную архитектуру. В случае возникновения проблем или при регламентном обслуживании сервера связность на L2 потеряется. Нам не хотелось создавать точку отказа.
Во время миграции можно было бы использовать OpenVPN, но хотелось сразу подготовить решение, которое не нужно дорабатывать.
Рассматривались следующие варианты:
fastd,
VpnCloud,
Tinc.
Стоит отметить, что у разработчика VpnCloud удобный
К сожалению, там нет даже упоминания fastd, который использовался в проекте.
Выбирать, основываясь на субъективном мнении пользователей и разработчиков, не хотелось, поэтому решили провести лабораторное тестирование VPN-систем и составить свое предвзятое мнение 🙂.
Критерии, по которым оценивались кандидаты:
скорость передачи данных через туннель,
стабильность работы,
простота и удобство настройки,
кроссплатформенность, наличие готовых пакетов под различные дистрибутивы Linux,
документация.
Важное лирическое отступление по MTU
При использовании VPN мы имеем дело с инкапсуляцией пакетов, поэтому важно правильно выставить значение MTU. Новый туннель добавляет дополнительные заголовки к пакету и снижает возможное количество передаваемых полезных данных (payload). Накладные расходы зависят как от типа туннельного интерфейса, так и от используемых алгоритмов шифрования данных.
Например, для нашего проекта получаем:
Базовый MTU — 1 500 байт (стандарт для IEEE 802.3 Ethernet).
TAP-интерфейс — дополнительно 28+14=42 байта.
IPv4 дополнительных байт не добавляет. Если бы использовался IPv6, то общий MTU уменьшился еще на 20 байт.
Шифрование — еще 24 байта.
Итого: 1500-42-24 = 1 434 байта
Что это означает на практике:
При создании сетевого моста Linux или программного коммутатора (если вы захотите использовать Open vSwitch), в который предполагается добавить VPN-интерфейс, то MTU моста/свитча, как и MTU всех подключенных к нему Ethernet и виртуальных интерфейсов должен быть одинаковый, но при этом меньше или равен 1 434 байтам.
Нужно убедиться, что в ОС на виртуальной машине на сетевом адаптере также выставлен правильный MTU, например, для ВМ с ОС Windows:
Во избежании проблем с path mtu discovery blackhole на хостах Qemu/KVM нужно создать правило netfilter. Например, при использовании iptables: sudo iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
С дополнительной информацией по решению проблемы можно ознакомиться здесь и здесь.
Тестирование
План тестирования:
На нашей облачной платформе создаются три виртуальные машины в разных зонах доступности (и регионах). При этом используются разные дистрибутивы Linux (rpm-based и deb-based).
Один раз запускаем iperf для измерения скорости передачи данных между машинами без VPN, фиксируем результат.
Средствами пакетного менеджера из репозиториев устанавливаем тестируемый VPN на все серверы и настраиваем его для взаимодействия с другими пирами. Также настраиваем автоматический старт при перезагрузке машины. Если позволяет ПО, выставляем либо самый быстрый, либо рекомендуемый разработчиком алгоритм шифрования трафика. Важно: VpnCloud не позволяет задать алгоритм шифрования вручную — только автоматически после запуска внутреннего бенчмарка.
Запускаем iperf на 30 минут, фиксируем скорость передачи данных, задержки, затем заносим данные в таблицу.
Последовательно осуществляем остановку и запуск VPN-сервиса на всех виртуальных машинах и фиксируем прохождение трафика между остальными включенными пирами (убеждаемся, что VPN действительно полносвязный).
После теста пакет с машины удаляется.
Оцениваем VPN-сервисы по объявленным выше критериям, выставляя места от 1 до 3.
Виртуальные машины создаются с образами AlmaLinux 8 64-bit, CentOS 7 Minimal 64-bit и Ubuntu 22.04 LTS 64-bit. Так мы достигли следующей сетевой топологии:
Переходим к тестированию.
fastd
По установке все тривиально. Для RHEL-based дистрибутивов собранный пакет присутствует в EPEL, для Ubuntu — в universe.
Для AlmaLinux и CentOS убеждаемся, что EPEL задействован и ставим пакет:
Содержимое раздела с пирами уникально на каждой виртуальной машине. У каждого будет свой secret и скрипты on up/down, а также закомментирован peer, в котором фигурирует непосредственно хост. Для примера здесь приведена конфигурация fastd на peer-01:
sudo cat /etc/fastd/vpntest/fastd.conf
Что получилось
# Log warnings and errors to stderrlog level warn;# Log informational messages to sysloglog to syslog level info;# Hides IP addresses in log outputhide ip addresses no;# Hides MAC addresses in log outputhide mac addresses no;# Sets the mode of the interface; the default is TAP mode.# In TAP mode, a single interfacewillbecreatedforallpeers# inmulti-TAPandTUNmode, eachpeergetsitsowninterface.# modemultitap;modetap;# UsetheL2TPkernelimplementationforthe “null@l2tp” method.# Enablingoffloadingallowsforsignificantlyhigherthroughput,# asdatapacketsdon’tneedtobecopiedbetweenkernelanduserspace.# Wedonotusemethodswithoutencryptionsosettingthisoptionto# "yes" doesnotmakeanysenseoffloadl2tpno;# Settheinterfacenameinterface "mesh-vpn";# Ifsettono, fastdwillcreatepeer-specificinterfaces# onlyaslongasthere’sanactivesessionwiththepeer.# DoesnothaveaneffectinTUNmode.#persistinterfaceno;persistinterfaceyes;# SettheinterfaceMTUforTAPmodewithxsalsa20/aes128overIPv4withabaseMTUof 1492 (PPPoE)# (seeMTUselectiondocumentation)# ThebasicoverheadofafastdpacketinTUNmodeoverIPv4is 28 bytesplusmethod-specificoverhead# Method “null” uses 1 additionalheaderbyte, “null@l2tp” 8 bytes, andallothermethods 24 bytes# TAPmodeneeds 14 bytesmorethanTUNmode# TunnelingoverIPv6needs 20 bytesmorethanIPv4# IfyourbaseMTUis 1500 andyouwanttouseTUNmodeoverIPv4withanycryptomethod# Choose 1500 - 28 - 24 = 1448 bytes.mtu 1434;# Enablesordisabledforwardingpacketsbetweenpeers.forwardyes;# Supportsalsa2012+umac #andnullmethods, prefersalsa2012+umacmethod "salsa2012+umac";# Bindtoafixedport, IPv4onlybind 0.0.0.0:10000;# Setstheusertorunfastdas.user "nobody";# Setsthegrouptorunfastdas.# Usegroup "nogroup" inDebian/Ubuntuand "nobody" onRHEL-baseddistros.group "nobody";#group "nogroup";# Bydefault, fastdswitchestotheconfigureduser# and/ordropsitsPOSIXcapabilitiesaftertheon-upcommandhasbeenrundropcapabilitiesyes;# Configuresashellcommandthatisrunaftertheinterfaceiscreated,# beforetheinterfaceisdestroyed, whenahandshakeissenttomake# anewconnection, whenanewpeerconnectionhasbeenestablished,# orafterapeerconnectionhasbeenlost#onpre-up [ sync | async ] "<command>";#onup [ sync | async ] "<command>";#ondown [ sync | async ] "<command>";#onpost-down [ sync | async ] "<command>";#onconnect [ sync | async ] "<command>";#onestablish [ sync | async ] "<command>";#ondisestablish [ sync | async ] "<command>";#onupsync "/usr/local/bin/peer-fastdupvirtsrvbr0";onup "ipaddradd 172.16.0.11/24 devmesh-vpn";# Secretkeygeneratedby `fastd --generate-key`secret "f0a31725e3750e40c7664599359ef80dc209431c865ed3b56f94346c2009d96c";# Aninlinepeerconfiguration.# peer "peer-01" { remote 198.51.100.11:10000; key "71fdf3236cd5e26a528449b5a9a7ab8c1d78382fa7c740685d4e717a67d21f2d"; }
peer "peer-02" { remote 192.0.2.12:10000; key "b5b9a0187324e9581c332f9701411ee32da2d0d8c875f2bc0e6d1a72b4241ee2"; }peer "peer-03" { remote 203.0.113.13:10000; key "c7eeafa25a59b910f85dd570dc27dd6889cf3acdf3f1561200f754b377b9d693"; }# Include peers from the directory 'peers'#include peers from "peers";
Запускаем демон и задействуем его при включении сервера:
sudo systemctl enable --now fastd@vpntest
Проверяем:
sudo systemctl status fastd@vpntest
fastd@vpntest.service - Fast and Secure Tunnelling Daemon (connection vpntest)
Loaded: loaded (/usr/lib/systemd/system/fastd@.service; enabled; vendor preset: disabled)
Active: active (running) since Thu 2022-03-03 11:45:52 MSK;
Main PID: 8021 (fastd)
Tasks: 1 (limit: 203248)
Memory: 948.0K
CGroup: /system.slice/system-fastd.slice/fastd@vpntest.service
└─8021 /usr/bin/fastd --syslog-level info --syslog-ident fastd@vpntest -c /etc/fastd/vpntest/fastd.conf
После подключения всех пиров в логах будут следующие строки:
sudo journalctl -u fastd@vpntest.service --no-pager --no-hostname | grep "connection with"
мар 05 11:47:36 fastd@vpntest[8021]: connection with <peer-02> established.
мар 05 11:47:39 fastd@vpntest[8021]: connection with <peer-03> established.
Устанавливаем iperf. Для RHEL-based дистрибутивов:
sudo yum -y install iperf
Для Debian соответственно:
sudo apt-get --yes install iperf
Запускаем утилиту в режиме сервера на одном из пиров, на втором — в режиме клиента и замеряем скорость соединения без использования туннеля:
peer-01>iperf -c 192.0.2.12 -e
peer-02>iperf -s
Результат
------------------------------------------------------------Client connecting to 192.0.2.12,TCP port 5001with pid 13242Write buffer size:128 KByteTCP window size:85.0KByte (default)------------------------------------------------------------[ 3] local 198.51.100.11 port 38160 connected with192.0.2.12 port 5001[ ID] Interval Transfer Bandwidth Write/Err Rtry Cwnd/RTT[ 3] 0.00-1800.00 sec 197.40 GBytes 942 Mbits/sec /03 462K/2543 us
ICMP-пинги:
peer-02>ping -c 120 -s -A 198.51.100.11
……
198.51.100.11 xmt/rcv/%loss = 120/120/0%, min/avg/max = 0.38/0.44/0.80
1 targets
1 alive
0 unreachable
0 unknown addresses
0 timeouts (waiting for response)
120 ICMP Echos sent
120 ICMP Echo Replies received
0 other ICMP received
0.38 ms (min round trip time)
0.44 ms (avg round trip time)
0.80 ms (max round trip time)
120.000 sec (elapsed real time)
Далее повторяем измерения, но уже через VPN-туннель:
------------------------------------------------------------Client connecting to 172.16.0.12,TCP port 5001with pid 15233 (1 flows)Write buffer size:131072 ByteTOS set to 0x0 (Nagle on)TCP window size:45.0KByte (default)------------------------------------------------------------[ 1] local 172.16.0.12%mesh-vpn port 42552 connected with 172.16.0.11 port 5001 (MSS=1382) (sock=3) (irtt/icwnd=475/13) (ct=0.55 ms) on 2022-03-03 07:04:56 (MSK)
[ ID] Interval Transfer Bandwidth Write/Err Rtry Cwnd/RTT(var) NetPwr……………[ 1] 0.00-1800.03 sec 187 GBytes 894 Mbits/sec 1534056/068845 149K/1278(59) us 87406
VpnCloud
Разработчик предоставляет готовые пакеты, которые доступны для скачивания и установки в разделе releases на GitHub. Для Debian/Ubuntu также можно воспользоваться репозиторием.
Для установки последней стабильной версии в AlmaLinux и CentOS выполняем:
sudo yum -y install
Для Ubuntu подключаем репозиторий и устанавливаем:
Далее для конфигурирования можно воспользоваться мастером, который предоставляет TUI, работающий в трех режимах: базовом, продвинутом и экспертном. Запускается мастер следующим образом:
sudo vpncloud config
Вводим запрашиваемые данные и после его успешного выполнения по пути /etc/vpncloud/${your_network_name}.net создастся YAML-файл с настройками. Я мастером пользоваться не стал, изучил man vpncloud, пример из /etc/vpncloud/example.net.disabled и сделал конфигурацию самостоятельно, предварительно сгенерировав ключи. На каждом из peer запускаем:
vpncloud genkey
Private key: gLtF7RuP4Jbew55N1wGDr81TXgD10OeipRTjPtL28Hr
Public key: J1UYpeLbR9Jq51jbsfPKfyfPCKPcgoTpEsecxgSgDIW
Attention: Keep the private key secret and use only the public key on other nodes to establish trust.
Приведенные ключи в production-конфигурациях не используются.
Вносим ключи в конфигурацию на каждой виртуальной машине, не забываем добавить публичную часть ключа в доверенные на других серверах.
cat iperf_vpncloud_btest.txt>------------------------------------------------------------Client connecting to 172.16.0.12,TCP port 5001with pid 153600 (1 flows)Write buffer size:131072 ByteTOS set to 0x0 (Nagle on)TCP window size:45.0KByte (default)------------------------------------------------------------[ 1] local 172.16.0.11%mesh-vpn-0 port 42620 connected with 172.16.0.12 port 5001 (MSS=1361) (sock=3) (irtt/icwnd=400/13) (ct=0.42 ms) on 2022-03-03 16:04:08 (MSK)
[ ID] Interval Transfer Bandwidth Write/Err Rtry Cwnd/RTT(var) NetPwr[ 1] 0.00-60.00 sec 6.23 GBytes 892 Mbits/sec 51056/0300 1133K/10113(61) us 11029[ 1] 60.00-120.00 sec 6.25 GBytes 894 Mbits/sec 51162/0252 1031K/9197(102) us 12152[ 1] 0.00-120.04 sec 12.5 GBytes 893 Mbits/sec 102219/0552 1034K/10616(2769) us 10514
Результат идентичен показателям fastd в пределах погрешности.
Tinc
Tinc — весьма популярный проект. Готовые бинарные пакеты присутствуют, пожалуй, во всех дистрибутивах Linux и BSD. Для RHEL-based дистрибутивов собранный пакет присутствует в EPEL, для Ubuntu — в universe.
Для AlmaLinux и CentOS убеждаемся, что EPEL задействован и ставим пакет:
sudo tincd -n vpntest -K
Generating 2048 bits keys:
.........+++++ p
.............................................................................+++++ q
Done.
Please enter a file to save private RSA key to [/etc/tinc/vpntest/rsa_key.priv]:
Please enter a file to save public RSA key to [/etc/tinc/vpntest/rsa_key.pub]:
Создадим конфигурацию. Для примера здесь приведена конфигурация Tinc на peer-01:
Затем в папке /etc/tinc/vpntest/hosts нужно создать конфигурационные файлы для других участников mesh-сети с сгенерированными публичными ключами (даны для примера, в production не используются и не должны использоваться).
peer-01>cat iperf_tinc_btest.txt------------------------------------------------------------Client connecting to 172.16.0.12,TCP port 5001with pid 15407 (1 flows)Write buffer size:131072 ByteTOS set to 0x0 (Nagle on)TCP window size:45.0KByte (default)------------------------------------------------------------[ 1] local 172.16.0.11%mesh-vpn port 42670 connected with 172.16.0.12 port 5001 (MSS=1385) (sock=3) (irtt/icwnd=474/13) (ct=0.61 ms) on 2022-03-03 18:42:45 (MSK)
[ ID] Interval Transfer Bandwidth Write/Err Rtry Cwnd/RTT(var) NetPwr[ 1] 0.00-60.00 sec 5.42 GBytes 776 Mbits/sec 44390/03209 489K/5152(68) us 18822[ 1] 60.00-120.00 sec 5.45 GBytes 780 Mbits/sec 44641/02692 403K/3807(116) us 25616[ 1] 0.00-120.05 sec 10.9 GBytes 778 Mbits/sec 89032/05901 409K/4249(132) us 22878
Скорость у Tinc заметно «просела», а задержки оказались выше.
Результаты
Скорость передачи данных. Первое место между собой поделили VpnCloud и fastd, Tinc — на втором месте.
Стабильность работы. Все программы работали стабильно: ошибок, аварийных завершений и утечек памяти во время тестирования не наблюдалось. Все участники теста разделили первое (или последнее третье, если угодно) место.
Простота, удобство настройки. Этот пункт для оценки достаточно субъективный. Мне показалось, что fastd гибче в настройке, так как позволяет создать как монолитную конфигурацию, так и «разнести» по отдельным файлам.
Также для fastd был создан Ansible Playbook для его массового развертывания и настройки. Если эта тема интересна — могу написать отдельную статью или добавить ссылку в GitHub gists без подробного разбора.
Из плюсов — VpnCloud поддерживает beaconing. Это позволяет облегчить конфигурирование, но я его не использовал ни в тестировании, ни в production, так как ни в одном из случаев не было большого количества узлов.
Кроссплатформенность, наличие готовых пакетов. Как уже было упомянуто, пакеты собраны для всех распространенных дистрибутивов Linux. Но что касается других платформ (Windows, MacOS X, BSD), то тут Tinc — безусловный лидер. На втором месте — fastd (без поддержки Windows), а на третьем — VpnCloud, который на данный момент поддерживает только Linux.
Документация. Выскажу субъективное мнение. Считаю, что документация fastd лучше структурирована, используется Read the Docs со всеми вытекающими. Безусловно, стоит отметить VpnCloud. Документация Tinc хороша, если рассматривать ее с точки зрения принципа KISS: вся нужная информация в одном man-файле. Отдаю приз fastd, а второе место делят VpnCloud и Tinc.
Место
ПО
Версия
ЯП
Поддержка ОС Linux/Windows/BSD
Транспортные протоколы
Выбор алгоритма шифрования данных
Алгоритм(-ы) шифрования передаваемых данных
1
fastd
v22
C
да/нет/да
UDP
вручную
AES-256, AES-128, ChaCha20
2
VpnCloud
2.3.0
Rust
да/нет/нет
UDP
авто
AES-128-CTR, Salsa20, Salsa2012
3
Tinc
1.0.36
C
да/да/да
UDP+TCP
вручную
AES-256 (все поддерживаемые OpenSSL)
Что в итоге
По результатам тестирования был выбран fastd, который и был использован в проекте.
Демоны fastd были сконфигурированы на всех серверах и при старте добавлялись в уже работающие мосты с предварительно настроенным MTU 1 400 байт, которые использует libvirtd, настроена сеть на серверах с Docker. После чего была осуществлена миграция виртуальных машин и persistent-данных для контейнеров. В эксплуатации новая информационная система находится с апреля текущего года и проблем с сетью и стабильностью работы мы не наблюдаем. Стоит отметить, что такое решение можно при необходимости использовать и в Proxmox VE.
Нам удалось предоставить клиенту кастомное решение, которое полностью закрывало его потребности во время миграции. Для этого пришлось проделать исследование и провести ряд тестов, что положительно сказалось на результате и комфорте эксплуатации проекта.