OpenVPN OSPF между двумя серверами, множественные тоннели

OpenVPN достаточно хорошо документирован и на хабре есть статьи по установке, к примеру:
вот эта.

Но так, чтобы сразу несколько тоннелей, между двумя серверами и автоматической отказоустойчивостью не нашел. В моем случае, серверы на которых будет располагаться OpenVPN и OSPF оба находятся за NATом. Это несколько усложняет решение, но в основном тем, что потребуется управлять трафиком, уходящим с интерфейсов пограничного маршрутизатора.

Дано:


Два пограничных маршрутизатора Centos 7:

r01:
ens0 1.1.1.1 – провайдер 1
ens1 2.2.2.2 – провайдер 2
ens2 10.0.0.1 – виртуальная сеть между шлюзом и OpenVPN сервером.
r02:
ens0 3.3.3.3 – провайдер 3
ens1 4.4.4.4 – провайдер 4
ens2 10.1.1.1 – виртуальная сеть между шлюзом и OpenVPN сервером.

Два OpenVPN/OSPF сервера Centos 7:

host01:
ens0 10.0.0.2 – SNAT через сеть провайдер 1.
ens0 10.0.0.3 – SNAT через сеть провайдер 2.
ens1 192.168.0.0/23 – локальная сеть.
host02:
ens0 10.1.1.2 – SNAT через сеть провайдер 3.
ens0 10.1.1.3 – SNAT через сеть провайдер 4.
ens1 192.168.4.0/23 – локальная сеть.

Все провайдеры в данной схеме разные, имеют разную скорость, стоимость.

Задача:


Создать 4 тоннеля между host01 и host02 так, чтобы они были всегда активны и в случае падения любого из провайдеров, маршрут должен переключаться на более медленный или дорогой канал. Даже если выйдут из строя оба провайдера (по одному на каждом сервере), канал также должен функционировать. В то же время, если более предпочтительный канал заработает – серверу придется перейти на него.

В этой статье я не буду подробно описывать процесс генерации ключей, установки OpenVPN, Quagga. Скажу лишь, что генерировать ключи для сервера и клиента достаточно один раз, так как можно использовать DH и все прочие ключи и сертификаты для всех инстансов одновременно. Но, конечно, если вы очень озабочены безопасностью – можно сгенерировать по два сертификата под каждый тоннель. В моем случае, был один сертификат на серверные службы и один на клиентские.

Установка:


Система CentOS Linux release 7.4.1708 (Core) / 3.10.0-693.5.2.el7.x86_64.
yum install openvpn easy-rsa quagga
версии ПО, которые были использованы:

openvpn 2.4.4 x86_64
easy-rsa 2.2.2-1.el7
quagga.x86_64 0.99.22.4-4.el7

Настройка:


Для тоннелей выбраны следующие порты:

udp 1150 – 1.1.1.1-3.3.3.3
udp 1151 – 2.2.2.2-4.4.4.4
udp 1152 – 1.1.1.1-4.4.4.4
udp 1153 – 2.2.2.2-3.3.3.3

Следует обратить внимание, что OpenVPN требует чтобы порт, с которого сервер и клиент отправляют пакеты был таким же как и порт приема пакетов, при использовании NAT порт исходящего пакета может отличаться и тоннель не поднимется с такой ошибкой:
TCP/UDP: Incoming packet rejected from [AF_INET]1.1.1.1:1194[2], expected peer address: [AF_INET]1.1.1.1:2364 (allow this incoming source address/port by removing --remote or adding --float)

Чтобы порт точно был всегда верным надо настроить пограничный маршрутизатор и OpenVPN сервер:

host01:

-A POSTROUTING -p udp --dport 1150 -o ens0 -j SNAT --to-source 10.0.0.2:1050
-A POSTROUTING -p udp --dport 1151 -o ens0 -j SNAT --to-source 10.0.0.3:1051

В свою очередь на пограничном маршрутизаторе будет так (r01):

-A POSTROUTING -p udp -s 10.0.0.2 --dport 1150 -o ens0 -j SNAT --to-source 1.1.1.1:1150
-A POSTROUTING -p udp -s 10.0.0.3 --dport 1151 -o ens1 -j SNAT --to-source 2.2.2.2:1151

Далее настроим туннели, приведу конфиг одной пары клиент/сервер, остальные настраиваются также, просто меняется порт, адреса и номер tun интерфейса.

Конфигурация сервера:

dev tun1
proto udp

topology subnet
remote 1.1.1.1
ifconfig 10.10.11.1 255.255.255.252

cipher AES-256-CBC
persist-tun
persist-key
ping 10
ping-restart 30

tls-server
daemon
dh /etc/openvpn/dh2048.pem
ca /etc/openvpn/ca.crt
cert /etc/openvpn/srv.crt
key /etc/openvpn/srv.key

reneg-sec 300
port 1150
verb 3


Конфигурация клиента:

dev tun1
proto udp

topology subnet
remote 3.3.3.3
ifconfig 10.10.11.2 255.255.255.252

cipher AES-256-CBC
ping 10
ping-restart 30

tls-client
daemon

ca /etc/openvpn/ca.crt
cert /etc/openvpn/cli.crt
key /etc/openvpn/cli.key

reneg-sec 300
port 1150
verb 3

Важный параметр в конфигурации тоннеля topology subnet, он позволяет сделать адресацию тоннеля так, чтобы он выглядел как подсеть и не интерфейс точка-точка. Параметр не является параметром по умолчанию и рекомендуется для современных серверов. Без него нет возможности обмениваться широковещательными пакетами внутри тоннеля, тем самым не будет возможности настроить OSPF.

При поднятии тоннеля ifconfig на сервере и клиенте будет выглядеть так:

tun1: flags=4305<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST>  mtu 1500
inet 10.10.11.1  netmask 255.255.255.252  destination 10.10.11.1

tun1: flags=4305<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST>  mtu 1500
inet 10.10.11.2  netmask 255.255.255.252  destination 10.10.11.2

После того, как все 4 тоннеля подняты, получается такая картина.

udp 1150 – 1.1.1.1-3.3.3.3 – tun1 – 10.10.11.1-10.10.11.2
udp 1151 – 2.2.2.2-4.4.4.4 – tun2 – 10.10.12.1-10.10.12.2
udp 1152 – 1.1.1.1-4.4.4.4 – tun3 – 10.10.15.1-10.10.15.2
udp 1153 – 2.2.2.2-3.3.3.3 – tun4 – 10.10.16.1-10.10.16.2

Никаких дополнительных статических маршрутов добавлять не требуется, кроме добавления правил сетевого экрана:

-A FORWARD -o tun1 -m comment --comment "1" -j ACCEPT
-A FORWARD -i tun1 -m comment --comment "1"-j ACCEPT
-A FORWARD -o tun2 -m comment --comment "2" -j ACCEPT
-A FORWARD -i tun2 -m comment --comment "2"-j ACCEPT
-A FORWARD -o tun3 -m comment --comment "3" -j ACCEPT
-A FORWARD -i tun3 -m comment --comment "3"-j ACCEPT
-A FORWARD -o tun4 -m comment --comment "4" -j ACCEPT
-A FORWARD -i tun4 -m comment --comment "4"-j ACCEPT

Отказоустойчивость.


Можно добиться переключения маршрутов и с помощью скриптов, но получилось бы громоздкое и совсем не элегантное решение. Ранее мне не доводилось использовать динамическую маршрутизацию на практике. Протоколов довольно много, остановился я на OSPF, по большому счету, потому, что информации и способов применения нашел больше. Протокол linkstate типа, учитывает состояние каналов, интерфейсов и обменивается ею. Думаю, что вполне можно реализовать подобное на BGP или RIP. С радостью бы посмотрел на BGP версию решения.
Чтобы OSPF мог получать и отправлять служебные пакеты LSA – Link State Advertisement потребуется открыть порты на сетевом экране:

-A INPUT -i tun1 -p 89 -m comment --comment "multicast tun1"-j ACCEPT
-A INPUT -i tun2 -p 89 -m comment --comment "multicast tun2"-j ACCEPT
-A INPUT -i tun3 -p 89 -m comment --comment "multicast tun3"-j ACCEPT
-A INPUT -i tun4 -p 89 -m comment --comment "multicast tun4"-j ACCEPT

Перейдем к настройке Quagga.


Для начала надо убедиться что папки и файлы, фигурирующие в работе служб Quagga принадлежали пользователю под которым служба запускается:

chown  -R quagga:quagga /etc/quagga
chown  -R quagga:quagga /var/log/quagga/ospfd.log

Запускаем службы:

systemctl start zebra 
systemctl start ospfd

После этого можно начать конфигурировать OSPF.

В консоль можно попасть двумя способами, telnet или vtysh, я выбрал второе.
Лучше сразу же попробовать сделать write, чтобы проверить права на файлы конфигурации, иначе все команды, которые вы введете не сохранятся, должно получиться так:

host01# wr
Building Configuration...
Configuration saved to /etc/quagga/zebra.conf
Configuration saved to /etc/quagga/ospfd.conf
[OK]

Проверьте, все ли ваши интерфейсы доступны для zebra.

sh inter

Если маршрутизируемые через OSPF сети и все tun интерфейсы на месте, можно продолжать.
Прежде всего, необходимо настроить стоимость туннелей, чем меньше стоимость, тем приоритетнее туннель. Сделать это можно так:

interface tun1
 ip ospf cost 10

И далее для других tun2 30, tun3 15, tun4 20 в моем случае.

После чего можно запускать маршрутизатор:

router ospf
 ospf router-id 192.168.1.0
 redistribute connected route-map LAN
 passive-interface default
 no passive-interface ens0
 no passive-interface tun1
 no passive-interface tun2
 no passive-interface tun3
 no passive-interface tun4
 network 10.10.11.0/30 area 0.0.0.0
 network 10.10.12.0/30 area 0.0.0.0
 network 10.10.15.0/30 area 0.0.0.0
 network 10.10.16.0/30 area 0.0.0.0
 network 192.168.1.0/23 area 0.0.0.0
!
ip prefix-list LAN seq 10 permit 192.168.4.0/23
ip prefix-list LAN seq 100 deny any
!
route-map LAN permit 10
 match ip address prefix-list LAN

В данной конфигурации используется параметр redistribute connected для того, чтобы анонсировать не все маршруты на другой сервер, а только нужные, а параметр route-map LAN позволяет фильтровать сети.

Точно такая же конфигурация должна быть и с другой стороны тоннеля. После активации службы ospfd примерно через 10 секунд на обоих серверах появятся маршруты соседей и тоннель будет выбран согласно стоимости. В случае, если предпочитаемый тоннель перестанет работать, автоматически произойдет переключение на другой тоннель и так далее, пока тоннелей не останется. И также, если более удачный интерфейс снова будет активирован – маршрутизация пойдет по нему.

Примерное время обновления маршрутов 10 секунд, можно варьировать параметры ip ospf hello-interval и ip ospf dead-interval для сокращения этого времени.

Не забудьте добавить все службы в автозагрузку, к примеру мои файлы конфигурации OpenVPN называются srv-1050.conf и cli-1050.conf, в этом случае команды будут выглядеть так:

systemctl enable openvpn@srv-1050
systemctl enable openvpn@cli-1050

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

Ну. И что?
Реклама
Комментарии 11
    0
    Redistribute connected вы используете из-за режима tun? От того и фильтруете сети? Почему бы не использовать tap и задавать в quagga нормальные зоны (и OSPF сам выбирет, какие анонсировать)? Выглядит все как костыли в местах, где они не нужны. Или экономили пару байт в MTU (режим tap требует больших накладных расходов, чем tun)?
      0
      Без этого параметра вообще не анонсировались сети, а с ним анонсировалось слишком много — поэтому этот костыль с route map, хотя мне кажется что выглядит нормально. tun был выбран потому, что изначально был один тоннель на нем.
        0
        Так проблема решается переходом на tap, и установкой point-to-multipoint на тунельном интерфейсе quagga. Да еще очень странно, что при вашей конфигурации пиры вообще получают анонс, broadcast на tun сам по себе не работает. Вы настроили unicast пиринг в OSPF? Если так, то где конфа?
          0
          broadcast проходит через tun если в параметрах указать topology subnet.
          у интерфейса есть адрес, маска и destination.
          tun1: flags=4305<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST> mtu 1500
          inet 10.10.11.1 netmask 255.255.255.252 destination 10.10.11.1
          unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 txqueuelen 100 (UNSPEC)
          RX packets 2170309 bytes 844381041 (805.2 MiB)
          RX errors 0 dropped 0 overruns 0 frame 0
          TX packets 2312094 bytes 983294406 (937.7 MiB)
          TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

          # tcpdump -nnn -i tun1 | grep --line-buffered OSPF
          tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
          listening on tun1, link-type RAW (Raw IP), capture size 262144 bytes
          18:53:47.776600 IP 10.10.11.2 > 224.0.0.5: OSPFv2, Hello, length 48
          18:53:48.759615 IP 10.10.11.1 > 224.0.0.5: OSPFv2, Hello, length 48
          18:53:57.776685 IP 10.10.11.2 > 224.0.0.5: OSPFv2, Hello, length 48
          18:53:58.760139 IP 10.10.11.1 > 224.0.0.5: OSPFv2, Hello, length 48

            0
            Проморгал iptables. Но в остальном, все равно не анонсит из-за типа туннеля.
      0

      а точно на неработоспособность OSPF влияет именно topology subnet? в общем случае, ospf на p2p линках нормально работает.


      и, конечно, с конфигурацией ospf, Вы, IMHO "переусердствовали": wan-линки зафигачить в backbone area и при этом "поскупиться" добавить туда lan, чтобы извращаться с redistribute connected… ну, каждому своё, как говорится. [у Вас] работает — и слава Богам ;)

        0
        а точно на неработоспособность OSPF влияет именно topology subnet?

        да, но смысл такой:
        1. пакет с одного сервера отправляется, но другой на него не реагирует.
        18:24:08.652299 IP 10.10.12.1 > 224.0.0.5: OSPFv2, Hello, length 48
        2. но не реагирует потому, что интерфейс в режиме p2p.
        3. в Quagga есть комманда:
        proxy# conf t
        proxy(config)# interface tun1
        proxy(config-if)# ip ospf network
        broadcast point-to-multipoint
        non-broadcast point-to-point
        proxy(config-if)# ip ospf network

        но к сожалению, она не помогает, более того, когда ее вводишь, ошибок нет, но при сохранении, в конфигурации интерфейса этого параметра нет. (причем параметр point-to-multipoint работает нормально), возможно особенность этой версии Quagga.
        и, конечно, с конфигурацией ospf, Вы, IMHO «переусердствовали»: wan-линки зафигачить в backbone area и при этом «поскупиться» добавить туда lan, чтобы извращаться с redistribute connected

        Я упомянул выше, что первый раз реализую динамическую маршрутизацию. Подскажите как было бы правильнее, в виде router ospf etc.
          0
          Вы меня натолкнули на мысль правильную. По поводу wan-линков вы были неправы их там нет, а вот то, что можно обойтись без redistribute connected и route-map похоже что это правда, пока работает верно. Конфигурация такова:
          router ospf
          ospf router-id 192.168.1.0
          passive-interface default
          no passive-interface tun1
          no passive-interface tun2
          no passive-interface tun3
          no passive-interface tun4
          network 10.10.11.0/30 area 0.0.0.0
          network 10.10.12.0/30 area 0.0.0.0
          network 10.10.15.0/30 area 0.0.0.0
          network 10.10.16.0/30 area 0.0.0.0
          network 192.168.1.0/23 area 0.0.0.0
          !

          0
          Исправьте пожалуйста написание OpenVpn на OpenVPN, уж очень глаз режет.
            0

            Интересное решение.
            Не думали как такую схему резервировать на случай отказа одного из серверов? Мне представляется сразу вариант на 4 сервера и туннели между ними ("квадрат", если нет локальной сети), но что-то уж слишком сумасшедше звучит.

              0
              такая схема реализуется довольно просто с помощью CARP, к примеру. Реплицировать даже ничего не надо. Имею ввиду, что можно обойтись самостоятельными серверами без сихронизации данных между ними.

            Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

            Самое читаемое