Дорогие читатели, добрый день. На связи Николай Едомский, руководитель группы сетевых инженеров компании Единый ЦУПИС.

В предыдущих статьях мы рассмотрели теоретическую базу построения нашего комплексного решения IPsecHub+. Мы также обозначили требования к топологии, после чего при помощи различных решений закрывали одно требование за другим. Для сохранения структуры повествования предыдущих статьях я не стал включать разделы, содержащие непосредственно конфигурацию и фрагменты кода. А сегодня мы с вами займемся тем, что шаг за шагом настроим наш концентратор.

Как уже было упомянуто в предыдущих статьях, наше решение является мультивендорным. Его можно реализовать на платформах различных вендоров. Но мы рассмотрим практическую реализацию на основе Linux-машины.


Целевая схема

Linux-маршрутизация включает в себя очень много аспектов, и все они являются темами для отдельных статей, в том числе и на Хабре. Мы же пройдемся по основным этапам создания концентратора. Назовем это неким MVP, который вам уже предлагается донастроить самостоятельно. Основной упор практикума - это собрать базу команд и конфигураций, которые помогут сориентироваться в вопросе.

Нам предстоит поэтапно выстроить что-то такое: 

Рис 1. Целевая схема концентратора.
Рис 1. Целевая схема концентратора.

Напомню, в namespace default мы организуем связность нашего концентратора с внешним миром. Отсюда же мы построим IPsec-туннель с удаленным филиалом. Вспомнить, какие задачи решает эскалаторная топология, можно здесь.

Обратите внимание, что в примере присутствует пересечение адресных пространств филиала и ЦОД. Подсеть 192.168.0.0/24 присутствует как в ЦОД, так и в филиале. В нашем практикуме мы организуем стыковку с проработкой этого пересечения.

И небольшая ремарка по поводу нейминга - VRF или namespace? На схемах я придерживаюсь классического названия сущностей - VRF, так как оно более универсально в разрезе сетевого администрирования. Но в практикуме мы будем оперировать понятием namespace, раз уж практикум посвящен целиком Linux. Эти понятия не равнозначны, но для реализации текущей функциональности в Linux нам достаточно будет применить namespace.


Связность концентратора с сетью Интернет

Хотя связность концентратора с сетью Интернет напрямую и не связана с темой цикла наших статей, я все же решил уделить этому вопросу внимание. Это важно хотя бы потому, что одна из главных наших целей - это фильтровать через межсетевой экран весь трафик, идущий к концентратору и от него.

А если ставить внешний интерфейс концентратора непосредственно в сегмент стыковки с оператором, то межсетевой экран в этом случае уже не будет фильтровать трафик из Интернета к концентратору. Вот как это выглядит:

Рис 2. Прямая стыковка.
Рис 2. Прямая стыковка.

Для решения этой проблемы можно запросить у оператора состыковаться на адресах из RFC1918, арендовать подсеть внешних адресов (4.4.4.0/28) и попросить их смаршрутизировать ее через наш "серый" СЕ-адрес (10.0.0.2). И уже внутри нашей зоны ответственности мы точечно можем распределять адреса из этой арендованной подсети по разным хостам. Вот как это выглядит (для упрощения в качестве СЕ я использую межсетевой экран):

Рис 3. Стыковка через СРЕ.
Рис 3. Стыковка через СРЕ.

Такая связка позволит:

  • Сэкономить «белые» адреса, не тратя их на broadcast, PE и net address.

  • Избежать выставления внешнего интерфейса концентратора "в мир" без фильтрации.

  • Избежать опасность DDoS на стыковочные адреса маршрутизаторов (они ведь у нас из RFC1918, не забываем).

  • Масштабировать аренду новых внешних подсетей, если необходимо. Нам просто нужно арендовать их у оператора и попросить смаршрутизировать все через тот же наш СЕ-адрес.

Если оператор не имеет возможности маршрутизировать арендованную подсеть через ваш СЕ, то аналогичную схему можно реализовать через proxy-arp. Наш СЕ-маршрутизатор будет отвечать на arp-запросы до тех внешних адресов, до которых у него самого есть маршруты внутрь нашей зоны ответственности. Но сэкономить адреса уже не получится. Предпочтительнее все же первый вариант.


Базовая конфигурация интерфейсов

Настройку концентратора мы начнем с конфигурации базовых интерфейсов - vlan и bond.

Давайте предположим, что для подключения сервера к коммутатору мы используем бонд с LACP. На основе этого бонда мы создадим vlan-интерфейсы, которые уже затем поместим в соответствующие namespace.

Настройку интерфейсов при помощи конфигурационного файла netplan можно представить следующим образом:

Скрытый текст

network:
version: 2

ethernets:
enp138s0f0: {}
enp138s0f1: {}

bonds:
bond0:
interfaces:
- enp138s0f0
- enp138s0f1
parameters:
mode: 802.3ad
lacp-rate: fast
transmit-hash-policy: layer3+4

vlans:
bond0.9:
id: 9
link: bond0
addresses:
- 172.16.1.2/24

bond0.10:
id: 10
link: bond0
dhcp4: no

bond0.11:
id: 11
link: bond0
dhcp4: no

Эту конфигурацию можно положить, например, в файл /etc/netplan/01-vlans.yml.

И конфигурация для loopback, можно положить в/etc/netplan/99-lo.yml.

Скрытый текст

network: 
version: 2 

renderer: networkd 
ethernets:   
lo:    
addresses:
        - 4.4.4.4/32

Стоит отметить, что адреса следует настраивать при помощи netplan только в случае, если интерфейс находится в namespace default. Если интерфейс в последствии будет помещен в другой namespace, то его ip-адрес будет удален из настроек. К сожалению, netplan на 2025 год не поддерживает namespace, поэтому все связанные манипуляции мы будем выполнять в bash.

Итак, для того, чтобы погрузить vlan-интерфейсы в namespace, их сначала нужно создать:

ip netns add ipsecTo
ip netns add ipsecFrom

Вывести список существующих на машине namespace можно следующим образом:

ip netns

Удалить namespace: 

ip netns delete <nsName>

Погрузим vlan-интерфейсы в соответствующие namespace (ipsecTo в данном случае):

ip link set bond0.10 netns ipsecTo

После этого можно добавить адрес и поднять интерфейс. Чтобы изменить ip-настройки интерфейса, находящегося в namespace, нам нужно будет выполнять  все команды с определенной преамбулой - ip netns exec <nsName>. Это относится к любой системной команде, которая должна быть выполнена в рамках namespace (например, tcpdump). Делаем:

ip netns exec ipsecTo ip a add 172.16.2.2/24 dev bond0.10
ip netns exec ipsecTo ip link set bond0.10 up

Посмотреть ip-настройки всех интерфейсов, находящихся в namespace ipsecTo, можно командой:

ip netns exec ipsecTo ip a

На этом этапе у нас получится вот такая картина:

Рис 4. Создание ipsecTo.
Рис 4. Создание ipsecTo.

Для завершения базовых настроек нужно проделать аналогичные действия с vlan-интерфейсом bond1.11:

ip link set bond0.11 netns ipsecFrom
ip netns exec ipsecFrom ip a add 172.16.3.2/24 dev bond0.11
ip netns exec ipsecFrom ip link set bond0.11 up

В итоге получаем:

Рис 5. Создание ipsecTo и ipsecFrom.
Рис 5. Создание ipsecTo и ipsecFrom.

Стыковочный контур

После того, как мы завершили настройку базовой стыковки концентратора с межсетевым экраном, давайте приступим к настройке стыковочного контура. Он будет использоваться непосредственно для приема трафика с филиала.

Начнем с того, что добавим namespace, предназначенный для стыковки с внешним филиалом. В него будут приниматься необработанные маршруты до филиальных подсетей. Назовем его site1_ext.

ip netns add site1_ext

В этом namespace, напомню, мы будем прикрывать адреса филиала суррогатными адресами. Далее можно создать GRE-интерфейс и добавить его в namespace. Создание GRE возможно и через netplan, но я предпочитаю делать это в bash, так как настройка gre уже не входит в базовую конфигурацию сети концентратора, и я не вижу смысла выносить настройку GRE-интерфейса в netplan.

ip tunnel add gre_site1 mode gre local 4.4.4.4 remote 9.9.9.9 ttl 32 
ip link set gre_site1 netns site1_ext

Затем настроим для него адреса и поднимем интерфейс:

ip netns exec site1_ext ip a add 172.16.4.1/30 dev gre_site1
ip netns exec site1_ext ip link set gre_site1 up

Вот что у нас получилось:

Рис 6. Создание GRE.
Рис 6. Создание GRE.

После этого можно приступить к созданию namespace site1_int. В этом namespace мы при помощи NAT прикроем адреса ЦОД перед тем, как они будут смаршрутизированы в филиал. Подробнее про необходимость каскада стыковочных namespace можно почитать здесь, раздел "Ситуация с конфликтами адресов".

ip netns add site1_int

Далее нам нужно обеспечить связность между namespace site1_int и site1_ext. Мы будем делать это при помощи veth-интерфейсов. Подробнее про них можно глянуть здесь. А сейчас давайте создадим их. Пара veth создается одной командой:

ip link add t_site1_ext type veth peer name t_site1_int

Представьте, что это два интерфейса, связанных виртуальным патчкордом (virtual Ethernet). Они будут находиться в виртуальной L2-связности друг с другом, даже будучи разнесенными в разные namespace.

И пару слов про нейминг интерфейсов. Имейте в виду, что в Linux имя сетевого интерфейса ограничено 12 символами, поэтому наш нейминг может быть несколько вычурным. А именно:

  • "t_site1_int" читаем как "to namespace site1_int", то есть интерфейс, ведущий из site1_ext до site1_int.

  • "t_site1_ext" читаем как "to namespace site1_ext". Ведет в namespace site1_ext из namespace site1_int.

Далее помещаем эти два интерфейса в соответствующие namespece:

ip link set t_site1_ext netns site1_int
ip link set t_site1_int netns site1_ext

И добавляем адреса на интерфейсы. Я использую /31 маску с целью упрощения подсчета стыковочных подсетей для veth-интерфейсов. Но можно и применять классическую /30 подсеть.

ip netns exec site1_int ip addr add 10.90.0.4/31 dev t_site1_ext
ip netns exec site1_int ip link set t_site1_ext up

ip netns exec site1_ext ip addr add 10.90.0.5/31 dev t_site1_int
ip netns exec site1_ext ip link set t_site1_int up

Несмотря на то, что эти два интерфейса находятся в разных namespace, связность между адресами10.90.2.1и 10.90.2.0сохраняется, так как они соединены тем самым виртуальным патчкордом.

Вот что получилось:

Рис 7.  Связность site1_int и site1_ext.
Рис 7. Связность site1_int и site1_ext.

И давайте по аналогии создадим veth-интерфейсы, которые свяжут namespace "ipsecTo" с namespace "site1_int":

ip link add t_site1 type veth peer name f_fw_site1
ip link set t_site1 netns ipsecTo
ip link set f_fw_site1 netns site1_int

ip netns exec site1_int ip addr add 10.90.0.1/31 dev f_fw_site1
ip netns exec site1_int ip link set f_fw_site1 up

ip netns exec ipsecTo ip addr add 10.90.0.0/31 dev t_site1
ip netns exec ipsecTo ip link set t_site1 up

При этом:

  • "t_site1" читаем как "to namespace site1", то есть ведущий в namespace site1_int из namespace ipsecTo.

  • "f_fw_site1" читаем как "From firewall to namespace site1", то есть ведущий в namespace site1_int от межсетевого экрана.

И по аналогии обеспечим связность namespace ipsecFrom и site1_int:

ip link add f_site1 type veth peer name t_fw_site1
ip link set f_site1 netns ipsecTo
ip link set t_fw_site1 netns site1_int

ip netns exec site1_int ip addr add 10.90.1.0/31 dev f_site1
ip netns exec site1_int ip link set f_site1 up

ip netns exec ipsecFrom ip addr add 10.90.1.1/31 dev t_fw_site1
ip netns exec ipsecFrom ip link set t_fw_site1 up

При этом:

  • "f_site1" читаем как "from namespace site1", то есть ведущий из namespace site1_int в namespace ipsecFrom, к межсетевому экрану.

  • "t_fw_site1" читаем как "to firewall from namespace site1", то есть ведущий из namespace site1_int к межсетевому экрану в namespace ipsecFrom.

Итого:

Рис 8. Донастройка vEth.
Рис 8. Донастройка vEth.

NAT

После того, как мы подготовили namespace-сегментацию и создали все необходимые интерфейсы, нужно разрешить пересечение адресных пространств ЦОД и филиала.

Для начала спрячем за суррогатными адресами филиал. В сегменте ЦОД филиал будет представлен подсетью из RFC6598 - 100.64.0.0/24. При этом в филиале подсеть ЦОД мы будем представлять уже другой суррогатной подсетью - 100.65.0.0/24

Рис 9. Диспозиция правил NAT.
Рис 9. Диспозиция правил NAT.

Сначала прикроем трафик, идущий из филиала (для соединений из филиала):

ip netns exec site1_ext iptables -t nat -A POSTROUTING  -s 192.168.0.0/24   -j NETMAP --to 100.64.0.0/24

Затем прокинем до реальной сети трафик, идущий на суррогат филиала (для соединений в филиал):

ip netns exec site1_ext iptables -t nat -A PREROUTING   -d 100.64.0.0/24 -j NETMAP --to 192.168.0.0/24

Проделаем ту же процедуру, но уже для подсети ЦОД. Спрячем ее для филиала за суррогатом 100.65.0.0/24. Результирующие правила выполняем в namespace site1_int:

ip netns exec site1_int iptables -t nat -A POSTROUTING  -s 192.168.0.0/24 -j NETMAP --to 100.65.0.0/24

ip netns exec site1_int iptables -t nat -A PREROUTING   -d 100.65.0.0/24 -j NETMAP --to 192.168.0.0/24

При корректной настройке правил трафик из пересекающихся сетей никогда не соприкоснется, так как на выходе с namespace site_int или site_ext он всегда будет прикрыт суррогатом. Пересечение адресов мы таким образом разрешили.

Рассмотрим пример, где хост в филиале с адресом 192.168.0.1 желает пингануть адрес ЦОД, закрытый за суррогатом 100.65.0.200:

src_ip: 192.168.0.1, dst_ip: 100.65.0.200

Что мы увидим, если запустим tcpdump на интерфейсе t_site1_int в namespace site1_ext, то есть после отработки всех NAT-правил?

src_ip: 100.64.0.1, dst_ip: 100.65.0.200

А tcpdump на интерфейсе t_fw_site1 в namespace site1_int после отработки всех NAT-правил уже покажет вот это:

src_ip: 100.64.0.1, dst_ip: 192.168.0.200

Уважаемые коллеги, на этом первый этап нашего практикума завершен. В следующей статье мы настроим деймоны маршрутизации и шифрования.

Навигация по циклу:

  1. Обзор IPsec

  2. Сегментирование на IPsec-хабе

  3. Эскалаторная топология

  4. Сложные сценарии

  5. Отказоустойчивость и динамическая маршрутизация

  6. Масштабирование и распределение нагрузки

  7. Практикум. Интерфейсы

  8. Практикум. Деймоны

Комментарии (2)


  1. ValdikSS
    18.12.2025 15:32

    И небольшая ремарка по поводу нейминга - VRF или namespace? На схемах я придерживаюсь классического названия сущностей - VRF, так как оно более универсально в разрезе сетевого администрирования. Но в практикуме мы будем оперировать понятием namespace, раз уж практикум посвящен целиком Linux.

    VRF и Namespace это разные сущности, и в Linux есть и то, и то. Вы настраиваете Namespace, это не VRF.

    https://docs.kernel.org/networking/vrf.html


    1. Gidral88 Автор
      18.12.2025 15:32

      Да, согласен. Чуть поправлю в тексте.