MAATRIX / Блог / Site-to-site VPN между офисами на IKEv2 (strongSwan)

Site-to-site VPN между офисами на IKEv2 (strongSwan)

MAATRIX

Два офиса, два шлюза, одна общая сеть без публикации сервисов наружу — классическая задача для IPsec. WireGuard тоже справится, но когда нужна совместимость с оборудованием других вендоров или у одной из сторон уже стоит strongSwan/Cisco/Mikrotik с поддержкой IKEv2, выбор падает на IPsec. Разберём, как поднять туннель через strongSwan: конфигурацию conn на обеих сторонах и разницу между policy-based и route-based режимом — от этого выбора зависит, как потом придётся жить с маршрутизацией.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Как устроен site-to-site на IKEv2

IKEv2 — протокол согласования ключей, а не сам туннель. Он строит два уровня безопасности: IKE SA (защищённый канал между шлюзами для служебных сообщений) и один или несколько Child SA — это уже ESP-туннели, которые шифруют пользовательский трафик. В site-to-site схеме Child SA привязывается к паре подсетей: «всё из 192.168.10.0/24 в 192.168.20.0/24 идёт через этот туннель».

В отличие от remote-access, где сервер раздаёт клиентам виртуальные IP из пула, здесь оба участника — равноправные шлюзы с известными заранее подсетями и публичными адресами (или DDNS-именами при динамическом IP). Аутентификация строится на PSK (pre-shared key) для простых схем или на X.509-сертификатах для более серьёзных требований — разницу между site-to-site и remote-access архитектурами подробно разбирали в статье site-to-site или remote-access VPN: в чём разница.

Ключевая развилка: как трафик попадает в туннель — по политике IPsec (policy-based) или по обычному IP-маршруту (route-based). Это архитектурное решение, а не деталь конфига — от него зависит, сможете ли вы завтра добавить третью подсеть без пересоздания туннеля.

Установка strongSwan на обоих шлюзах

Ставится одинаково на Ubuntu/Debian с обеих сторон:

apt update
apt install -y strongswan strongswan-pki libcharon-extra-plugins

Модуль libcharon-extra-plugins нужен для дополнительных плагинов, в частности для VTI. Проверьте, что демон charon — реализация IKE в strongSwan — стартует:

systemctl enable --now strongswan
systemctl status strongswan

Дальше на обоих шлюзах включите форвардинг пакетов — без него сервер не пропустит транзитный трафик между локальной сетью и туннелем:

sysctl -w net.ipv4.ip_forward=1
echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
sysctl -p

Для site-to-site NAT (MASQUERADE) на внутреннем трафике обычно не нужен и вреден — вторая сторона увидит вместо реальной подсети адрес шлюза, что ломает симметричную маршрутизацию. NAT в этой схеме нужен только для собственного исходящего интернет-трафика шлюза, не для трафика между офисами.

Арендуйте сервер под свои задачи!

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Policy-based IPsec: conn с двух сторон в ipsec.conf

Самый распространённый вариант — подсети прописаны прямо в conn, а ядро автоматически строит SPD (Security Policy Database) на основе leftsubnet/rightsubnet. Пример: офис в Москве с публичным IP 203.0.113.10 и сетью 192.168.10.0/24, филиал в Питере с IP 198.51.100.20 и сетью 192.168.20.0/24.

Конфиг на шлюзе офиса А (/etc/ipsec.conf):

config setup
    charondebug="ike 1, knl 1, cfg 0"

conn %default
    keyexchange=ikev2
    authby=secret
    ike=aes256-sha256-modp2048!
    esp=aes256-sha256-modp2048!
    keyingtries=%forever
    dpdaction=restart
    dpddelay=30s
    dpdtimeout=120s

conn office-a-to-b
    left=%defaultroute
    leftid=203.0.113.10
    leftsubnet=192.168.10.0/24
    right=198.51.100.20
    rightid=198.51.100.20
    rightsubnet=192.168.20.0/24
    auto=start

ike= и esp= жёстко фиксируют набор алгоритмов (восклицательный знак запрещает fallback на более слабые предложения). dpddelay/dpdtimeout — Dead Peer Detection: если пир не отвечает 120 секунд, соединение считается разорванным и переподнимается по dpdaction=restart.

Общий ключ — в /etc/ipsec.secrets:

203.0.113.10 198.51.100.20 : PSK "здесь-длинный-случайный-ключ-минимум-32-символа"

На шлюзе офиса Б conn — зеркальное отражение первого, с переставленными left/right:

config setup
    charondebug="ike 1, knl 1, cfg 0"

conn %default
    keyexchange=ikev2
    authby=secret
    ike=aes256-sha256-modp2048!
    esp=aes256-sha256-modp2048!
    keyingtries=%forever
    dpdaction=restart
    dpddelay=30s
    dpdtimeout=120s

conn office-b-to-a
    left=%defaultroute
    leftid=198.51.100.20
    leftsubnet=192.168.20.0/24
    right=203.0.113.10
    rightid=203.0.113.10
    rightsubnet=192.168.10.0/24
    auto=start

Строка в ipsec.secrets на этой стороне идентична первой — PSK один и тот же для обоих участников. Важно: leftsubnet на одной стороне обязан совпадать с rightsubnet на другой — это частая причина, почему туннель поднимается (IKE SA есть), а трафик не ходит: подсети описаны асимметрично, и Child SA не совпадают по selector'ам.

После правки конфига на обеих сторонах:

ipsec restart
ipsec status

Если всё верно, ipsec status покажет ESTABLISHED для IKE SA и INSTALLED для соответствующего Child SA с указанными подсетями.

Route-based IPsec: VTI вместо leftsubnet/rightsubnet

Policy-based удобен для схемы «одна подсеть на другую», но плохо масштабируется: чтобы добавить ещё одну подсеть, приходится создавать дополнительные conn или писать leftsubnet списком через запятую — и при каждом изменении IPsec пересчитывает и переустанавливает Child SA, что на секунду-другую рвёт трафик.

Route-based решает это иначе: туннель поднимается как обычный сетевой интерфейс (VTI — Virtual Tunnel Interface), а какой трафик в него попадает, решает не IPsec-политика, а таблица маршрутизации Linux. ESP-туннель шифрует всё, что приходит на интерфейс, а какие подсети туда направить — решает ip route add, как с любым другим интерфейсом.

Конфиг conn для route-based схемы (офис А):

conn office-a-to-b-vti
    leftsubnet=0.0.0.0/0
    rightsubnet=0.0.0.0/0
    leftid=203.0.113.10
    right=198.51.100.20
    rightid=198.51.100.20
    mark=42
    leftupdown=/etc/strongswan/updown-vti.sh
    auto=start

leftsubnet/rightsubnet здесь заведомо «широкие» — реальная фильтрация идёт не через них. mark помечает пакеты для этого туннеля, а скрипт updown-vti.sh при поднятии соединения создаёт сам VTI-интерфейс:

#!/bin/bash
# /etc/strongswan/updown-vti.sh
PLUTO_MARK_OUT_ID=${PLUTO_MARK_OUT#*/}
PLUTO_MARK_IN_ID=${PLUTO_MARK_IN#*/}

case "$PLUTO_VERB" in
    up-client)
        ip link add vti0 type vti local "$PLUTO_ME" remote "$PLUTO_PEER" \
            okey "$PLUTO_MARK_OUT_ID" ikey "$PLUTO_MARK_IN_ID"
        sysctl -w "net.ipv4.conf.vti0.disable_policy=1"
        ip addr add 169.254.42.1/30 remote 169.254.42.2/30 dev vti0
        ip link set vti0 up mtu 1436
        ip route add 192.168.20.0/24 dev vti0
        ;;
    down-client)
        ip route del 192.168.20.0/24 dev vti0 2>/dev/null
        ip link del vti0 2>/dev/null
        ;;
esac

Дальше трафик направляется через vti0 обычным маршрутом — если завтра появится третья подсеть в офисе Б, достаточно ip route add 192.168.30.0/24 dev vti0 без изменений в ipsec.conf и без пересборки Child SA. disable_policy=1 на интерфейсе критичен — без него ядро повторно прогонит пакет через IPsec policy engine поверх уже расшифрованного трафика и всё сломает.

Что выбрать: policy-based или route-based

КритерийPolicy-basedRoute-based (VTI)
Конфигурация подсетейВ leftsubnet/rightsubnet конкретного connЧерез обычные ip route на интерфейсе
Добавление новой подсетиПравка conn, пересчёт Child SAip route add, без изменений в IPsec
Совместимость с OSPF/статической маршрутизациейПлохая — маршруты внутри IPsec-политикиХорошая — VTI виден как обычный интерфейс
Один туннель с двумя фиксированными сетямиПроще и нагляднееИзбыточно
Поведение при переподъёмеМожет кратковременно ронять трафик подсетиИнтерфейс остаётся, трафик ждёт восстановления SA
Диагностикаipsec status, ip xfrm policyip link show vti0, ip route
Поддержка на стороне оборудования (Cisco, Mikrotik)УниверсальноНе всегда есть аналог VTI

Для двух офисов с одной фиксированной подсетью на каждой стороне policy-based — разумный выбор: меньше движущихся частей, конфиг читается за секунду. Route-based имеет смысл, когда точек больше двух и нужна гибкая маршрутизация (hub-and-spoke, динамическая маршрутизация поверх туннелей, рост числа подсетей) — тогда VTI избавляет от пересборки Child SA при каждом изменении топологии. Если офисов больше трёх, стоит присмотреться и к mesh-решениям поверх WireGuard, которые сами управляют таблицей маршрутов — сравнение подходов есть в статье про Netmaker: mesh VPN на WireGuard.

Проверка и диагностика туннеля

Первым делом — статус IKE и Child SA:

ipsec status
ipsec statusall

statusall покажет и согласованные алгоритмы шифрования — полезно, когда обе стороны настроены разными людьми и подозревается рассинхрон в ike=/esp=. Что реально установлено в ядре:

ip xfrm state
ip xfrm policy

Для policy-based именно ip xfrm policy покажет селекторы — если тут пусто или не те подсети, дело в leftsubnet/rightsubnet, а не в IKE. Проверка связности:

ping -c 4 192.168.20.1
tcpdump -ni any esp

tcpdump с фильтром esp покажет, идут ли зашифрованные пакеты вообще — если нет ни в одну сторону, проблема в маршрутизации или firewall до IPsec, а не в самом туннеле. Отдельно проверьте, что на промежуточном firewall открыты UDP 500 и UDP 4500 (NAT-T) — без 4500 туннель может подняться, но развалится при первой смене NAT-маппинга.

Частые ошибки при настройке

  • Асимметричные подсети. leftsubnet на одной стороне не совпадает с rightsubnet на другой — IKE SA поднимается, а Child SA — нет или поднимается только для узкого пересечения подсетей.
  • NAT без явного NAT-T. strongSwan определяет NAT автоматически и переключается на UDP 4500, но за жёстким firewall этот порт нужно открыть отдельно от 500.
  • MASQUERADE на трафике между офисами. Применённый по ошибке к транзитному трафику, а не только к исходящему в интернет, он подменяет внутренние адреса на IP шлюза — обратные пакеты не находят маршрут назад к конкретному хосту.
  • Забытый forwarding в firewall. ip_forward=1 включает форвардинг на уровне ядра, но при политике DROP по умолчанию на цепочке FORWARD в iptables/nftables пакеты всё равно не пройдут — нужно явное разрешение для интерфейса ipsec0 (policy-based) или vti0 (route-based).
  • Пересекающиеся подсети офисов. Если оба офиса сидят на одной адресации (частый случай для роутеров из коробки, например 192.168.1.0/24 на обеих сторонах), туннель поднимется, но маршрутизация станет неоднозначной. Перед настройкой стоит свериться с диапазонами — похожие нюансы IPsec разбираются и в статье про L2TP/IPsec через Libreswan, где показан альтернативный демон для той же связки.

Арендуйте сервер под свои задачи!

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Можно ли использовать сертификаты вместо PSK?

Да, и для постоянного межофисного туннеля это надёжнее — вместо authby=secret указывается authby=pubkey, генерируется CA и сертификаты для обоих шлюзов через strongswan-pki. PSK проще для старта, но при компрометации ключа его придётся менять на обеих сторонах сразу — с сертификатами можно отозвать один, не трогая остальные.

Что будет, если у одного из офисов динамический публичный IP?

Сторона, принимающая подключение, ставит right=%any и ждёт входящего соединения. Стороне с динамическим адресом нужен DDNS, а rightid на принимающей стороне указывается как доменное имя, а не IP — идентификация пира тогда идёт по DDNS-имени независимо от текущего адреса.

Route-based обязательно требует VTI, или есть альтернативы?

В Linux для strongSwan VTI — стандартный путь, но есть и XFRM interfaces (ip link add xfrm0 type xfrm) — механизм новее, поддерживает несколько туннелей на разных if_id без конфликта по mark. Для двух офисов разница некритична, XFRM интереснее при большом числе туннелей на одном шлюзе.

Как понять, что туннель разваливается, а не просто не поднимается с нуля?

Смотрите journalctl -u strongswan -f в момент проблемы — циклические rekeying или DPD-таймауты говорят о нестабильности канала или рассинхроне dpddelay. Если IKE SA не устанавливается вообще, ищите в логе NO_PROPOSAL_CHOSEN — несовпадение ike=/esp= наборов.

Нужен ли отдельный VPS под сам туннель?

Не обязательно — strongSwan легковесен и живёт на том же сервере, что и другие сервисы, если тот не перегружен по CPU (шифрование ESP — единственная заметная нагрузка, и на современном железе для типичных офисных объёмов трафика она невелика). Отдельный узел оправдан при постоянном высоконагруженном трафике или когда нужно изолировать точку отказа.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →