· 17 мин чтения

Site-to-site IPsec на Linux: как я соединил три офиса строительной компании за две недели

Site-to-site IPsec на Linux: как я соединил три офиса строительной компании за две недели

Привет! Сразу предупрежу: это не какой-то сухой мануал. Это живой кейс из нашей практики, история реального проекта. Меня зовут Семёнов Евгений Сергеевич, я возглавляю АйТи Фреш. Год назад к нам обратилась одна строительная компания. У них головной офис в Москве, плюс два филиала — в Питере и Казани. Штат немаленький, целых 150 человек. И вот представьте: вся их 1С и ERP висела на сервере в центральном офисе. А сотрудники из филиалов? Они подключались по RDP прямо через открытый интернет! Можно ли это назвать нормальной работой? Это было не просто медленно, это было ужасно небезопасно, да ещё и постоянно рвалось. Мы взяли и развернули IPsec site-to-site на strongSwan, полностью решив эту боль за каких-то две недели. Расскажу обо всём по порядку, покажу конфиги и, да, честно поделюсь факапами, без них никуда.

Что было в начале

Когда я впервые приехал к ним на встречу, увидел, честно говоря, до боли знакомую картину. Знаете, когда файлы проектной документации летают по электронной почте, а в 1С все входят под одним и тем же паролем? Или Wi-Fi в офисе вообще без шифрования, как в Казани? Вот это оно. Руководство, разумеется, не интересовал абстрактный VPN. Им было важно одно: избавить проектировщиков в Казани от этих кошмарных тормозов, на которые они жаловались каждый день.

Наш аудит показал: все три офиса существовали словно в параллельных вселенных. Никакой защищённой связи между ними, в каждом — свой Windows Server и свой локальный домен. Про общий файлообменник вообще можно было забыть. Ну, что тут думать? Моё решение было очевидным: нужно собрать эту разрозненную структуру в единую, защищённую сеть. И IPsec для этого подходил идеально. А ERP-систему? Её мы вынесли прямо в московский DMZ — теперь доступ к ней шёл строго через VPN-туннель.

Архитектура, которую я нарисовал

Мы приняли решение о full-mesh архитектуре для трёх узлов. Что это значит на практике? Это три отдельных, независимых туннеля: Москва—Санкт-Петербург, Москва—Казань и, конечно же, Санкт-Петербург—Казань. Сразу возникает вопрос: почему не hub-and-spoke? При таком сценарии весь трафик шёл бы через Москву, а нагрузка на центральный шлюз оказалась бы просто колоссальной и очень неравномерной. Full-mesh же позволяет отлично распределять трафик, и именно это было критически важно для нашего клиента.

ОфисWANLANЖелезо шлюза
Москва (HQ)2 провайдера, статика10.10.0.0/24 + 10.11.0.0/24 VLAN серверовDell PowerEdge R350, Debian 12
СПбStatic IP10.20.0.0/24Intel NUC i5, Debian 12
КазаньЗа NAT провайдера, dynamic10.30.0.0/24Intel NUC i5, Debian 12

На оборудование для двух филиалов, Питера и Казани, мы выделили 72 000 рублей. А вот в Москве шлюзом у нас выступила уже существующая виртуалка на ProxMox. Отличная экономия, да? Никаких дополнительных вложений там не потребовалось.

Создание PKI

Мы всегда держим корневой CA на отдельной машине. Обычно для этого задействуем наш технический ноутбук, на котором стоит Debian. Это принципиальный момент: я никогда не разворачиваю CA на том же шлюзе, который непосредственно шифрует трафик. Считаю, что это просто неправильно с точки зрения безопасности.

cd /etc/ipsec.d
# Корневой CA на 10 лет
ipsec pki --gen --type rsa --size 4096 --outform pem > private/ca-key.pem
ipsec pki --self --ca --lifetime 3650 \
    --in private/ca-key.pem \
    --dn "C=RU, O=Stroy, CN=Stroy VPN CA" \
    --outform pem > cacerts/ca-cert.pem

# Шаблон подписи для шлюза Москвы
ipsec pki --gen --type rsa --size 4096 --outform pem > private/gw-msk-key.pem
ipsec pki --pub --in private/gw-msk-key.pem | \
  ipsec pki --issue --lifetime 1825 \
    --cacert cacerts/ca-cert.pem --cakey private/ca-key.pem \
    --dn "C=RU, O=Stroy, CN=gw-msk.stroy.local" \
    --san gw-msk.stroy.local --san 203.0.113.10 \
    --flag serverAuth --flag ikeIntermediate \
    --outform pem > certs/gw-msk-cert.pem

Сертификаты для шлюзов gw-spb и gw-kzn я подписал точно так же. А вот ключи копировал на каждый шлюз через SCP только тогда, когда сам находился рядом с нужной машиной. Это железное правило: приватные ключи ни при каких обстоятельствах нельзя передавать удалённо по незашифрованному каналу. Никогда.

Базовая настройка шлюзов

Чтобы не терять время, для начала я поднял PSK-вариант. Это был такой экспресс-тест: убедиться, что всё вообще связывается, прежде чем переходить к более серьёзной аутентификации на сертификатах. Вот, посмотрите, фрагмент конфигурации для Москвы:

# /etc/ipsec.conf — GW-MSK, первый этап с PSK
config setup
    charondebug="ike 2, knl 2, cfg 2"
    uniqueids=yes

conn %default
    keyexchange=ikev2
    ikelifetime=24h
    lifetime=8h
    dpdaction=restart
    dpddelay=30s
    dpdtimeout=150s
    keyingtries=%forever
    ike=aes256-sha256-modp2048!
    esp=aes256gcm16-sha256!

conn msk-spb
    auto=start
    authby=secret
    left=203.0.113.10
    leftsubnet=10.10.0.0/24,10.11.0.0/24
    leftid=@gw-msk.stroy.local
    right=198.51.100.5
    rightsubnet=10.20.0.0/24
    rightid=@gw-spb.stroy.local

conn msk-kzn
    auto=start
    authby=secret
    left=203.0.113.10
    leftsubnet=10.10.0.0/24,10.11.0.0/24
    leftid=@gw-msk.stroy.local
    right=%any
    rightid=@gw-kzn.stroy.local
    rightsubnet=10.30.0.0/24

На сторонах Питера и Казани конфиги были, естественно, зеркальными. PSK-секрет? Длинная строка, сгенерированная из /dev/urandom, 40 символов. Для тестов это сгодится, но для реального продакшена — категорически нет.

Переход на сертификаты

Как только убедился, что все три туннеля стабильно поднялись и пинг пошёл без проблем, я тут же приступил к переводу всего этого на pubkey-аутентификацию. Вот фрагмент московского конфига, это уже после всех этих изменений:

conn msk-spb
    auto=start
    authby=pubkey
    ike=aes256gcm16-sha384-ecp384!
    esp=aes256gcm16-sha384!

    left=203.0.113.10
    leftsubnet=10.10.0.0/24,10.11.0.0/24
    leftid=@gw-msk.stroy.local
    leftcert=gw-msk-cert.pem
    leftsendcert=always

    right=198.51.100.5
    rightsubnet=10.20.0.0/24
    rightid=@gw-spb.stroy.local
    rightca="C=RU, O=Stroy, CN=Stroy VPN CA"

Файл ipsec.secrets — одна строка: : RSA gw-msk-key.pem. Права 600, владелец root. И никаких PSK-строк больше не осталось.

Казанский офис за NAT

Самый настоящий квест ждал нас с казанским офисом. Провайдер выдавал им серый IP-адрес через какой-то жуткий карьерный NAT! И что самое обидное, статические адреса за деньги они просто не продавали. Пришлось нам креативить, действуя от имени клиента.

# /etc/ipsec.conf на gw-kzn
conn to-msk
    auto=start
    authby=pubkey
    left=%defaultroute
    leftsubnet=10.30.0.0/24
    leftid=@gw-kzn.stroy.local
    leftcert=gw-kzn-cert.pem
    leftfirewall=yes

    right=203.0.113.10
    rightsubnet=10.10.0.0/24,10.11.0.0/24,10.20.0.0/24
    rightid=@gw-msk.stroy.local

    forceencaps=yes
    ike=aes256gcm16-sha384-ecp384!
    esp=aes256gcm16-sha384!

Строка `forceencaps = yes` оказалась просто критичной. Вот без неё провайдерский NAT напрочь ломал ESP. А с ней? Весь трафик аккуратно завернулся в UDP 4500 и пролетел, как ни в чём не бывало.

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

Да, в каждом офисе я сначала, конечно, добавил статические маршруты прямо на маршрутизаторах, указывая пути к удалённым подсетям через VPN-шлюз. Это, по сути, самая банальная часть работы. Но клиент, что вполне логично, очень хотел, чтобы маршруты раздавались автоматически по DHCP. Зачем? Чтобы, если вдруг появится ещё один филиал, не пришлось бы вручную бегать и переписывать маршруты на сотнях компьютеров. И я его прекрасно понимаю! Поэтому мы настроили DHCP Option 121, то есть classless static routes:

# /etc/dhcp/dhcpd.conf на маршрутизаторе МСК
option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;
subnet 10.10.0.0 netmask 255.255.255.0 {
    range 10.10.0.100 10.10.0.200;
    option routers 10.10.0.1;
    option rfc3442-classless-static-routes
        24, 10, 20, 0, 10, 10, 0, 1,
        24, 10, 30, 0, 10, 10, 0, 1;
}

Что приятно, и Windows-, и Linux-клиенты отлично подхватывают эту опцию. И каждый раз, при обновлении DHCP-лизы, маршруты автоматически актуализируются. macOS, конечно, как всегда со своими 'особенностями' — но к счастью, в офисе стройки 'яблок' почти не встречалось.

Failover через второго провайдера

Московский офис, само собой, стал настоящим центром, ключевой точкой — весь трафик стекался именно туда. Чтобы обеспечить максимальную стабильность, мы просто обязаны были добавить резервный канал от второго провайдера. В итоге у нас получилось две конфигурации: основная (primary) и резервная (backup). Мы написали скрипт, который умеет автоматически переключать трафик, если вдруг основной канал не отвечает дольше минуты, то есть 60 секунд.

#!/bin/bash
# /usr/local/bin/vpn-failover.sh
REMOTE=10.20.0.1
PRIMARY=msk-spb-primary
BACKUP=msk-spb-backup

if ! ping -c3 -W2 "$REMOTE" >/dev/null 2>&1; then
    if ! ipsec status | grep -q "$BACKUP.*ESTABLISHED"; then
        ipsec down "$PRIMARY"
        sleep 2
        ipsec up "$BACKUP"
        logger -t vpn "failover: switched to backup channel"
    fi
else
    if ipsec status | grep -q "$BACKUP.*ESTABLISHED"; then
        ipsec down "$BACKUP"
        sleep 2
        ipsec up "$PRIMARY"
        logger -t vpn "recovery: switched back to primary"
    fi
fi

Мы настроили проверку так, что она срабатывает каждые 60 секунд через systemd timer. За год работы системы, знаете, сколько было реальных переключений? Всего два! Один раз наш провайдер занимался обслуживанием узла, а второй — вообще кабель порвали на стройке прямо возле офиса. Ну что тут скажешь!

Мониторинг и уведомления

Подключил Zabbix-агент к каждому шлюзу, написал простой item, который парсит ipsec statusall и отдаёт количество ESTABLISHED-SA. При падении любого SA — алерт в Telegram техническому директору клиента и мне.

# UserParameter для Zabbix
UserParameter=vpn.established,ipsec status | grep -c ESTABLISHED

# Триггер: если меньше 3 — алерт
{gw-msk:vpn.established.last()}<3

Представьте, за 8 месяцев до окончания проекта мы получили 11 алертов. Из них 9 система разобрала сама буквально за 3–10 минут — DPD просто подтянул туннель. И только дважды потребовалось наше прямое вмешательство. Что интересно, в обоих случаях виноваты были… да, вы угадали, провайдеры!

Что получил клиент в итоге

Давайте посмотрим на смету по этому проекту. Железо для наших двух филиалов вышло всего в 72 000 рублей. А все работы и, конечно, документация — это ещё 195 000 рублей. Итоговая сумма? Получилось 267 000 рублей. Теперь самое интересное: если сравнивать это с покупкой коммерческих VPN-шлюзов, скажем, того же Fortinet, наш клиент сэкономил приличные деньги. Только на железе — около 380 000 рублей! А ещё ежегодно — примерно 60 000 рублей на лицензиях. По-моему, это просто отличный результат, согласитесь?

Типовые ошибки, с которыми я столкнулся

Соберу VPN-сеть для ваших филиалов

Проектирую, строю, документирую. Для объединения двух-пяти офисов срок обычно 7–14 рабочих дней. Железо подбираем под бюджет — от Intel NUC до Dell PowerEdge. После сдачи — обучение вашего админа и 30 дней бесплатной поддержки.

Телефон: +7 903 729-62-41
Telegram: @ITfresh_Boss
Семёнов Евгений Сергеевич, директор АйТи Фреш

FAQ — частые вопросы по site-to-site IPsec

Сколько времени у меня заняло объединение трёх офисов?
Чистое внедрение — 8 рабочих дней: три дня PKI и сбор шлюзов, два дня установка в Москве, по дню на СПб и Казань, и финальный день на failover и мониторинг. Весь проект с документацией и обучением админа клиента уместился в две недели.
Почему я не выбрал WireGuard для этой задачи?
Потому что в казанском офисе стоял Cisco ISR, который отдавать и менять клиент не хотел. Cisco умеет IKEv2 IPsec, но не знает WireGuard. strongSwan идеально вставал и туда, и на Debian, и на Mikrotik.
Что делать, если филиал сидит за NAT провайдера?
Ставим на филиале left=%defaultroute и forceencaps=yes. На NAT-маршрутизаторе пробрасываем UDP 500, UDP 4500 и протокол ESP (IP 50) — но если есть forceencaps, ESP не нужен.
PSK или сертификаты?
Сертификаты X.509. Всегда. PSK для site-to-site — это дыра, которую рано или поздно найдут. У каждой стороны должен быть свой приватный ключ, это азы.
Выдержит ли 1С через такой VPN?
Выдержит, и неплохо. В нашем проекте скорость работы 1С через VPN выросла в 3–4 раза по сравнению с предыдущим RDP-через-интернет. Главное — обеспечить минимум 10–20 Мбит/с симметричного канала и следить за MTU.

Подпишитесь на рассылку ITfresh

Раз в неделю мы делимся чем-то действительно полезным! Это практические гайды для всех: и для руководителя IT-отдела, и для системного администратора. Что там внутри? Мы раскрываем темы безопасности, тонкости работы с 1С, делимся опытом по миграциям, рассказываем о резервных копиях, и, конечно, даём ценные лайфхаки, которые мы сами подсмотрели на реальных проектах.

Реквизиты оператора персональных данных

ООО «АЙТИ-ФРЕШ», ИНН 7719418495, КПП 771901001. Юридический адрес: 105523, г. Москва, Щёлковское шоссе, д. 92, корп. 7. Контакт: info@itfresh.ru, +7 903 729-62-41. Оператор обрабатывает e-mail подписчика в целях рассылки информационных и рекламных материалов до момента отзыва согласия.