Pull to refresh

Failover файрвол на iptables

Reading time 6 min
Views 14K
Чем же заняться админу в новогодние праздники, как не настройкой серверов!

В этой статье описан общий подход как можно:
— сделать кластер на iptables
— настроить кластер через GUI fwbuilder
— сохранить коннекты пользователей при failover при помощи conntrack-tools

Общее окружение в котором у меня работает такой кластер:
— Внутренняя сеть из backend и frontend серверов
— Блок внешних IP-адресов
— 2 сервера под кластер на базе linux (в моем случае Fedora 13 x64_86): fw1 и fw2 в режиме Master/Backup

Задачи кластера:
— шлюз для локальной сети
— публикация сервисов на внешнем блоке ip-адресов

В общем виде это работает так:
— за состоянием кластера следит служба ucarp и дергает нужные скрипты в случае failover
— служба conntrackd синхронизирует информацию о коннектах между серверами
— fwbuilder компилирует нужные скрипты для iptables

Под катом инструкция для сборки с напильником


Подготовка серверов


Устанавливаем на fw1 и fw2 linux с минимальным набором пакетов, iptables там уже есть.

Добавляем:
yum install ucarp — heartbeat для кластера
yum install conntrack-tools — трекер коннекций
yum install pssh (для утилиты scp)

Заходим в /etc/sysconfig/network-scripts/ и настраиваем интерфейсы.
Назначаем только по одному персональному ip-адресу на интерфейс, например:
eth0 — внутренний
eth3 — интерфейс для синхронизации информации о коннектах между серверами кластера.
Рекомендуется из соображений безопасности соединять сервера кластера через этот интерфейс шнурком напрямую, т.к. протокол conntrackd небезопасный.
Внешний интерфейс будет конфигурироваться из скриптов.

Настройка ucarp


При запущенном процессе ucarp, каждый сервер будет отправлять VRRP пакеты на мультикаст-адрес 224.0.0.18
Если сервер не получает пакеты от партнера, он считает, что остался один и стартует upscript, который прописан в файле /etc/init.d/ucarp
UPSCRIPT=/usr/libexec/ucarp/vip-up
Если сервер находится в активном состоянии и получает пакеты от партнера, который главнее — стартует downscript и переходит в состояние backup
DOWNSCRIPT=/usr/libexec/ucarp/vip-down
Скрипты upscript/downscript мы немного доработаем позже.

Далее настраиваем vip-адрес, который будет переезжать при failover с одного сервера на другой.
Vip-адресом у нас будет адрес шлюза внутренней сети и внутренняя же сеть для обмена VRRP-пакетами.
Файлы настроек:
/etc/ucarp/vip-common.conf
/etc/ucarp/vip-001.conf (теоретически vip-адресов может быть много, но нам хватит и одного)

Таким образом ucarp будет управлять переходом ip-адреса шлюза при failover.

К сожалению ucarp это совсем не то же самое, что carp на OpenBSD и нужно будет решить две проблемы:
— при failover изменить ARP для ip-адреса шлюза у всех клиентов локальной сети или сделать общий MAC для серверов в кластере
— свести риск split brain к минимуму, т.е. по возможности избежать ситуации когда оба сервера думают, что их партнер помер и пытаются стать главным.

В решении первой проблемы поможет утилита arping.
В качестве рекомендаций для уменьшения вероятности split brain могу порекомендовать сначала объединить все рабочие интерфейсы в bonding, а потом уже нарезать vlan-ы для внутренней и внешней сети.
Это поможет, если что-то случится с физикой на любом из интерфейсов.

Настройка iptables при помощи fwbuilder


На сайте fwbuilder достаточно подробная документация по использованию собственно fwbuilder как удобного инструмента для визуального представления правил.
Но fwbuilder ни сколько не отменяет необходимости знать и понимать как работает iptables.

Порядок использования следующий:
— составление правил
— компиляция скрипта
— копирование скрипта через scp на сервера кластера
— запуск скрипта через ssh

fwbuilder грамотно компилирует правила: выделяет отдельные цепочки, следит, чтобы правила друг друга не перекрывали.
Для создания кластера читаем раздел документации.

Создаем кластер с названием, например «fw-cluster», в котором будут два объекта типа «файрвол на iptables», например, fw1 и fw2 (важно, чтобы имя совпадало с результатом команды «hostname -s» на сервере файрвола, т.к. это будет учитываться потом в скриптах)

В свойствах State Sync Group указываем тип: conntrack, чтобы fwbuilder добавил access правила для conntrack пакетов

Делаем кластерными все интерфейсы.
При этом создаются кластерные объекты, например:
fw-cluster:eth0:members (интерфейс внутренней сети)
fw-cluster:eth1:members
fw-cluster:eth3:members

Для объекта fw-cluster:eth0:members указываем тип VRRP (опять же для access-правил).
У остальных объектов, тип не указываем.

На вкладке Script в настройках объекта межсетевого экрана нужно выключить все пункты, кроме «Load iptables modules».
Это связано с тем, что скомпилированный скрипт может сам настраивать интерфейсы и vlan-ны, но в ходе использования этой фичи мы столкнулись с некоторыми багами.

По-умолчанию fwbuilder сам добавит правила для related и established коннектов.
После компилирования появятся скрипты fw1.fw и fw2.fw.
Чтобы fwbuilder мог устанавливать и запускать скрипты на удаленном сервере один из интерфейсов объекта межсетевого экрана нужно пометить как управляющий.

Настройка conntrack


В документации есть пример настройки как раз для нашего случая.
Берем как есть скрипт primary-backup.sh
Настраиваем conntrackd.conf:
— в секции «Multicast» указываем интерфейс взаимодействия
— в секции «Address Ignore» можно отфильтровать все соединения с собственными ip-адресами серверов кластера, которые при failover никуда не переедут
fwbuilder сам добавит access правила для ip-multicast адреса, поэтому в conntrackd.conf его менять не нужно.

Настройка внешнего блока ip-адресов


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

Выход есть — использовать общий MAC-адрес для внешнего интерфейса на файрволе.
К сожалению, я не смог нагуглить ни одного работающего решения, кроме модуля clusterip для iptables, буду рад если кто-то предложит другой способ.
Как неприятное следствие — приходится иметь дело с multicast MAC адресами.

Настало время доработать upstart и updown скрипты


Рядом со скриптами для удобства создадим текстовый файл(ы), в котором построчно записаны ip-адреса без маски, например, eth1.addr.external
eth1 — имя нтерфейса внешней сети
Чтобы модуль clusterip сработал раньше остальных правил для внешнего блока адресов — прописываем его в таблицу mangle

upscript

#!/bin/sh

# По-умолчанию fwbuilder копирует свои скрипты в эту папку на удаленный сервер
ROOT="/etc/fw"

# Сообщаем демону conntrackd, что данный сервер теперь primary
/etc/conntrackd/primary-backup.sh primary

# Запускаем скомпилированный при помощи fwbuilder скрипт с правилами
$ROOT/$(hostname -s).fw start

# Добавляем внутренний ip-адрес шлюза
# Параметры $2 и $1 передаются службой ucarp
# Тут и далее в явном виде прописана маска сети, что не есть гуд, если маска потом поменяется
/sbin/ip address add "$2"/24 dev "$1"

# Добавляем внешние ip-адреса

# Полезное правило для предотвращения спама в /var/log/messages модулем clusterip по поводу невалидных пакетов
iptables -t mangle -I PREROUTING -m state --state INVALID -j DROP

# Скрипт на случай, если внешних сетей несколько и соответственно файлов *.addr.external тоже несколько
for ADDRFILE in $(ls $ROOT/*.addr.external)
do
DEV=$(basename "$ADDRFILE" | awk -F "." '{print $1}')
for ADDR in $(cat $ROOT/$DEV.addr.external | grep -v ^#)
do
# Добавляем ip-адрес на интерфейс
/sbin/ip addr add $ADDR/24 dev $DEV
# Делаем ip-адрес кластерным
iptables -t mangle -A PREROUTING -d "$ADDR" -i "$DEV" -j CLUSTERIP --new --hashmode sourceip --clustermac 01:00:5E:00:01:01 --total-nodes 1 --local-node 1 --hash-init 0
done
done

# Рассылаем arp-ответ 2 раза о том, что MAC-адрес шлюза изменился
arping -A -c 2 -I "$1" "$2"


downscript

По сути удаляем все кластерные ip-адреса и чистим таблицу mangle
#!/bin/sh
ROOT="/etc/fw"

/etc/conntrackd/primary-backup.sh backup

/sbin/ip address del "$2"/24 dev "$1"

for ADDRFILE in $(ls $ROOT/*.addr.*)
do
DEV=$(basename "$ADDRFILE" | awk -F "." '{print $1}')
for ADDR in $(cat $ADDRFILE | grep -v ^#)
do
/sbin/ip addr del $ADDR/24 dev $DEV
done
done

iptables -t mangle -F

$ROOT/$(hostname -s).fw start


В результате вышеописанных действий, на обоих серверах вы стартуете службу ucarp.
Один из серверов станет активным и стартанет upscript, который в свою очередь должен поднять все ip-адреса кластера на внутренней и внешней сетях, накатить набор правил для iptables.
Tags:
Hubs:
+39
Comments 10
Comments Comments 10

Articles