Назад | Перейти на главную страницу

Симметричная маршрутизация Docker / маршрутизация на основе политик

Задний план

У меня есть сервер debian с 3 сетевыми интерфейсами:

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

По этой причине я добавил несколько правил на основе политик, чтобы IP-адрес назначения / источника остался прежним. Я добился этого, отредактировав свой /etc/network/interfaces как это:

# The primary network interface
allow-hotplug eno1
iface eno1 inet dhcp
  post-up ip route add 10.0.0.0/24 dev eno1 table 1
  post-up ip route add default via 10.0.0.1 table 1
  post-up ip rule add from 10.0.0.35/32 table 1 priority 100
  post-up ip route flush cache
  pre-down ip rule del from 10.0.0.35/32 table 1 priority 100
  pre-down ip route flush table 1
  pre-down ip route flush cache

# VLANS
auto eno1.10
iface eno1.10 inet dhcp
  post-up ip route add 10.0.10.0/24 dev eno1.10 table 2
  post-up ip route add default via 10.0.10.1 table 2
  post-up ip rule add from 10.0.10.65/32 table 2 priority 110
  post-up ip route flush cache
  pre-down ip rule del from 10.0.10.65/32 table 2 priority 110
  pre-down ip route flush table 2
  pre-down ip route flush cache

auto eno1.40
iface eno1.40 inet dhcp
  post-up ip route add 10.0.40.0/24 dev eno1.40 table 3
  post-up ip route add default via 10.0.40.1 table 3
  post-up ip rule add from 10.0.40.40/32 table 3 priority 120
  post-up ip route flush cache
  pre-down ip rule del from 10.0.40.40/32 table 3 priority 120
  pre-down ip route flush table 3
  pre-down ip route flush cache

Все сервисы работают на сервер теперь работал так, как должен.

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

Проблема

Теперь проблема в том, что созданные мной правила, по-видимому, не применяются к трафику, исходящему из контейнеров докеров, и я не могу получить к ним доступ, потому что трафик блокируется как недействительный.

Что мне нужно сделать здесь, чтобы контейнеры докеров знали, какой маршрут использовать в соответствии с исходным IP-адресом?

Быстрое решение:

  • Добавьте правила маршрутизации по отметке брандмауэра. Пакеты с соответствующей отметкой будут маршрутизироваться через отдельную таблицу маршрутизации.
ip rule add fwmark 0x1 lookup 1 pref 10001
ip rule add fwmark 0x2 lookup 2 pref 10002
ip rule add fwmark 0x3 lookup 3 pref 10003
  • Отметка входящих соединений зависит от входного интерфейса. Цель connmark сохраняет значение отметки внутри записи conntrack.
iptables -t mangle -A PREROUTING -m conntrack --ctstate NEW -i eno1 -j CONNMARK --set-mark 0x1
iptables -t mangle -A PREROUTING -m conntrack --ctstate NEW -i eno1.10 -j CONNMARK --set-mark 0x2
iptables -t mangle -A PREROUTING -m conntrack --ctstate NEW -i eno1.40 -j CONNMARK --set-mark 0x3
  • Скопируйте значение метки из записи conntrack в метку брандмауэра. После этого ответный пакет будет маршрутизироваться по дополнительным правилам маршрутизации, которые были добавлены. Используйте дополнительные -i сопоставить или сопоставить по адресу источника, в противном случае вам нужно добавить напрямую подключенные маршруты в дополнительные таблицы.
iptables -t mangle -A PREROUTING -i docker0 -j CONNMARK --restore-mark
  • Также вы можете использовать совпадение по адресу источника вместо интерфейса ввода.
iptables -t mangle -A PREROUTING --src <container-subnet> -j --restore-mark
  • Это решение отлично работает с DNAT.
  • Использовать tcpdump и conntrack инструмент для устранения проблем.
  • Также проверьте rp_filter. В некоторых случаях он может отбрасывать пакеты. Лучше установите его в loose Режим (sysctl -w net.ipv4.conf.all.rp_filter=2).

Обновить

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

  • Для каждого восходящего канала создайте дополнительную таблицу маршрутизации и назначьте метку межсетевого экрана.
ip route add <uplink-subnet> dev <uplink-iface> table <uplink-table>
ip route add 0/0 via <uplink-gw> dev <uplink-iface> table <uplink-table>

ip rule add fwmark <uplink-mark> table <uplink-table>
  • Для каждого интерфейса восходящего канала добавьте одно правило для отметки входящих соединений:
iptables -t mangle -A PREROUTING -i <uplink-iface> -m conntrack --ctstate NEW --ctdir ORIGINAL -j CONNMARK --set-mark <uplink-mark>
...
  • Добавьте два правила для всех аплинков, чтобы отмечать ответные пакеты:
iptables -t mangle -A PREROUTING -m conntrack ! --ctstate NEW --ctdir REPLY -m connmark ! --mark 0x0 -j CONNMARK --restore-mark

iptables -t mangle -A OUTPUT -m conntrack ! --ctstate NEW --ctdir REPLY -m connmark ! --mark 0x0 -j CONNMARK --restore-mark