OSEN-НИЙ SAAALEСкидка 50% на виртуальный хостинг и VDS
до 30.11.2025 Подробнее
Выберите продукт

Docker и файрвол: безопасные цепочки iptables/nftables и изоляция бриджей

Docker автоматически меняет правила iptables/nftables и может нарушить привычные политики. В статье — практичные схемы: безопасные INPUT/FORWARD, цепочка DOCKER-USER, изоляция bridge-сетей, NAT и egress-контроль, публикация портов без сюрпризов и чек‑лист диагностики.
Docker и файрвол: безопасные цепочки iptables/nftables и изоляция бриджей

Зачем вообще говорить о Docker и файрволе

Docker упрощает жизнь разработчикам и админам, но вместе с удобством приходит и скрытая автоматика. Демон добавляет и удаляет правила в iptables или через совместимость — в nftables. Это влияет на FORWARD, INPUT, NAT и может неожиданно открыть лишние пути между контейнерами, между мостами, наружу и на сам хост. Без четкой модели безопасности вы рискуете либо поломать сеть контейнеров, либо оставить «дырки» в обороне.

Ниже — практическая методичка: как работает цепочка DOCKER-USER, какие политики задать по умолчанию, как изолировать bridge-сети, аккуратно настроить NAT для исходящего трафика и опубликовать порты без сюрпризов. Примеры — и для iptables, и для nftables, с подсказками по sysctl и типичным взаимодействиям с UFW и firewalld. Если готовите хост под прод — удобнее сразу строить периметр на изолированном VDS.

Как Docker меняет таблицы: что появится в системе

При запуске контейнеров Docker создаёт и обновляет несколько цепочек. Для варианта с iptables вы увидите цепочки DOCKER, DOCKER-ISOLATION-STAGE-1, DOCKER-ISOLATION-STAGE-2, DOCKER-USER и правила для MASQUERADE в таблице nat. Цепочка DOCKER-USER — специально для ваших правил: трафик проходит через неё раньше, чем попадёт в DOCKER, поэтому здесь удобно вводить общесистемные ограничения.

Если хост использует «совместимость» iptables поверх nft (iptables-nft), Docker создаёт объекты в семействе ip таблиц filter и nat внутри общего ruleset nftables. Это важно: вы можете добавлять свои собственные nft-цепочки с приоритетом выше или ниже докеровских, чтобы управлять порядком обработки.

Быстрый осмотр: iptables -S и iptables -t nat -S для iptables; nft list ruleset для nftables. Для трассировки в nft используйте nft monitor trace.

Цепочки DOCKER, DOCKER-USER и порядок обработки в iptables/nftables

Базовая модель: «закрыто по умолчанию», stateful-исключения и DOCKER-USER

Надежная схема — минимально открытые политики на INPUT и FORWARD плюс точечные разрешения. Docker сам добавляет правила, чтобы работали опубликованные порты и межконтейнерный обмен в пределах сети. Наша задача — ограничить лишнее, не ломая легитимные сценарии.

iptables: безопасный каркас

Последовательность действий должна быть аккуратной, чтобы не потерять SSH. Сначала разрешаем нужное, затем опускаем политики.

# Разрешаем уже установленные соединения
iptables -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
# Локалку
iptables -A INPUT -i lo -j ACCEPT
# SSH (подставьте свой порт)
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
# Политика по умолчанию
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

# Цепочка DOCKER-USER обрабатывается раньше DOCKER
# Разрешаем обратный трафик
iptables -A DOCKER-USER -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
# Запрещаем прямой трафик между docker bridge-интерфейсами (изоляция мостов)
iptables -A DOCKER-USER -i br+ -o br+ -j DROP
# Возвращаемся к стандартной обработке (цепочка DOCKER)
iptables -A DOCKER-USER -j RETURN

Такой каркас оставляет опубликованные порты рабочими (их примет цепочка DOCKER), но блокирует прямую связность между мостами Docker. Если в пределах одного моста нужна полная связность контейнеров — она сохранится, правило с br+ ограничивает именно межмостовую пересылку.

nftables: эквивалентный каркас

В nftables удобно вынести свои правила в отдельную таблицу с более высоким приоритетом, чем iptables-независимые цепочки Docker. Ниже — пример. Приоритет -200 гарантирует обработку раньше «iptables-nft» цепей (у них обычно priority 0).

table inet fastfox {
  chain input {
    type filter hook input priority -200;
    ct state established,related accept
    iifname "lo" accept
    tcp dport { 22 } accept
    counter drop
  }
  chain forward {
    type filter hook forward priority -200;
    ct state established,related accept
    iifname "br+" oifname "br+" drop
    counter accept
  }
}

# NAT для исходящего (если нужен общий исход во внешку)
table ip nat_out {
  chain postrouting {
    type nat hook postrouting priority 100;
    oifname "eth0" masquerade
  }
}

Цепочка forward допускает трафик по умолчанию после нашего раннего дропа для межмостовой связности, а дальше уже подключатся правила, которые Docker добавит через iptables-совместимость. Если нужна более строгая модель — оставьте в конце не accept, а drop и явно разрешайте направления (см. ниже раздел про egress-фильтрацию).

Бриджи Docker: как изолировать сети правильно

По умолчанию Docker создаёт docker0 и user-defined bridge-сети br-* для compose-проектов. Контейнеры внутри одной такой сети связаны, а между разными сетями — изолированы на уровне iptables правил Docker. Однако межмостовая связность может появиться, если вы вручную включаете --link, публикуете порты и прокладываете маршруты. Лучше закрепить изоляцию явным правилом, как выше: -i br+ -o br+ -j DROP в DOCKER-USER или соответствующее правило в nft.

Ещё один надёжный приём — отключить дефолтный мост и создавать сети явно. Это упрощает контроль адресных пространств и политик.

# /etc/docker/daemon.json
{
  "bridge": "none",
  "iptables": true,
  "default-address-pools": [
    {"base": "172.20.0.0/16", "size": 24}
  ]
}

Дальше создавайте сети для каждого проекта отдельно, избегайте пересечений подсетей, и назначайте контейнеры только в нужные сети. Если нужен «внутренний» сегмент без выхода в интернет, создавайте сеть с флагом internal (в compose — internal: true): такая сеть не будет маскарадуваться наружу.

Тонкая настройка межконтейнерной связности: в старых конфигурациях встречается опция icc (inter-container communication). Для современных user-defined сетей разумнее опираться на сетевые ACL на уровне файрвола и избирательно публиковать порты.

NAT и egress-контроль: выпускаем контейнеры наружу безопасно

Маскарадинг (MASQUERADE) нужен, чтобы контейнеры ходили во внешнюю сеть. Docker добавляет правила POSTROUTING сам, но вы можете усилить контроль, ограничив, что именно им разрешено с хоста.

iptables: пример egress-фильтра

# Разрешаем исходящие из контейнеров только веб и DNS
iptables -A DOCKER-USER -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
iptables -A DOCKER-USER -i br+ -p udp --dport 53 -j ACCEPT
iptables -A DOCKER-USER -i br+ -p tcp -m multiport --dports 80,443 -j ACCEPT
# Остальное из docker-сетей наружу — запрет
iptables -A DOCKER-USER -i br+ ! -o br+ -j DROP
iptables -A DOCKER-USER -j RETURN

Такой набор оставляет межконтейнерный обмен в пределах одной сети на усмотрение правил Docker, но режет наружу всё, кроме явно нужного.

nftables: egress-фильтр

table inet fastfox_egress {
  chain forward {
    type filter hook forward priority -200;
    ct state established,related accept
    # Разрешаем DNS из контейнеров
    iifname "br+" udp dport 53 accept
    # Разрешаем только веб исход
    iifname "br+" tcp dport { 80, 443 } accept
    # Межмостовая изоляция
    iifname "br+" oifname "br+" drop
    # Остальное из docker-сетей наружу — запрет
    iifname "br+" drop
    counter accept
  }
}

Если применяете строгий egress-контроль, тестируйте обновление пакетов в контейнерах, резолвинг, время синхронизации и прочие служебные запросы — часто забывают про NTP, реестры образов, зеркала пакетов.

Изоляция bridge-сетей Docker и egress-маскарадинг на хосте

Публикация портов: DNAT и защита

Публикация портов -p 0.0.0.0:443:443 создаёт правила DNAT и соответствующие ACCEPT в FORWARD. С точки зрения безопасности надёжнее держать минимальный периметр: выносить наружу только фронтенд-прокси, а внутренние сервисы оставлять в приватных сетях. Для опубликованных портов можно добавить базовую stateful-защиту и ограничение по источникам.

iptables: ограничение источников для опубликованного порта

# Разрешаем 443 только из выбранной подсети (пример)
iptables -I DOCKER-USER 1 -p tcp -s 203.0.113.0/24 --dport 443 -j ACCEPT
iptables -A DOCKER-USER -p tcp --dport 443 -j DROP
iptables -A DOCKER-USER -j RETURN

Поскольку DOCKER-USER идёт раньше DOCKER, здесь удобно отрезать нежелательные источники до того, как трафик попадёт в докеровские правила.

nftables: ограничение источников

table inet perimeter {
  chain input {
    type filter hook input priority -200;
    ct state established,related accept
    tcp dport 443 ip saddr 203.0.113.0/24 accept
    tcp dport 443 drop
    counter accept
  }
}

Для DNAT на контейнеры правила сработают на forward, но логика та же: сначала отсечь ненужные источники, потом пропустить разрешённые к докеровским цепям.

Sysctl и ядро: что важно включить

Чтобы фильтрация на мостах работала, нужен модуль br_netfilter и соответствующие sysctl. Также включите маршрутизацию, если у вас есть форвардинг трафика.

# Разово в рантайме
modprobe br_netfilter
sysctl -w net.bridge.bridge-nf-call-iptables=1
sysctl -w net.bridge.bridge-nf-call-ip6tables=1
sysctl -w net.ipv4.ip_forward=1

# Постоянно — файл /etc/sysctl.d/99-docker.conf
net.bridge.bridge-nf-call-iptables=1
net.bridge.bridge-nf-call-ip6tables=1
net.ipv4.ip_forward=1
net.ipv6.conf.all.forwarding=1

Параметры bridge-nf-call-* направляют трафик, проходящий через Linux bridge, в стек iptables/nftables. Без них часть пакетов может обходить ваш файрвол.

UFW и firewalld: как не поссорить их с Docker

UFW и firewalld абстрагируют сложность, но Docker меняет правила напрямую. Распространённые эффекты: опубликованные порты не работают при FORWARD=DROP, или наоборот — UFW считает всё закрытым, а контейнеры доступны.

  • UFW: по умолчанию смена DEFAULT_FORWARD_POLICY на ACCEPT помогает не ломать Docker, но ослабляет общий периметр. Более контролируемый путь — оставить FORWARD DROP, а ограничения вносить через DOCKER-USER, как в примерах выше.
  • firewalld: Docker может помещать интерфейсы мостов в зону trusted. Проверьте зоны и сервисы, при необходимости зафиксируйте зону для br-* и добавьте периметровые правила на уровне nft.

Главный принцип: не пытайтесь «переписать» цепочки DOCKER. Используйте DOCKER-USER и собственные ранние nft-цепочки. Так вы не сломаете автоматику Docker и сохраните свой контроль.

Для общего каркаса и типовых пресетов под nft см. подробный разбор в материале Гид по nftables для VDS. Для периметра SSH и базовой защиты хоста обратите внимание на Безопасность VDS: SSH и файрвол.

FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

Диагностика: что смотреть, когда «ничего не работает»

  • Маршрутизация и интерфейсы: ip addr, ip route, проверьте br-*, veth, docker0.
  • Правила: iptables -S, iptables -t nat -S, nft list ruleset.
  • Conntrack: conntrack -L или ss -ntp для состояний соединений.
  • Трассировка nft: nft monitor trace покажет, какое правило сработало.
  • Пакеты: tcpdump -i br-XXXX и на соответствующем veth.

Переход с iptables на nftables (или наоборот): как не обжечься

Современные дистрибутивы по умолчанию используют iptables-совместимость поверх nftables (iptables-nft). Docker с этим дружит. Определитесь, каким инструментом вы управляете вручную: если пишете nft-правила, держите их в отдельных таблицах и задавайте приоритет, чтобы они срабатывали до цепочек, созданных через совместимость. Если остаетесь на «чистом» iptables, не смешивайте подходы, чтобы не усложнять порядок обработки.

Типичные шаги миграции:

  • Зафиксировать существующий ruleset: iptables-save и nft list ruleset.
  • Определить, где Docker создаёт свои цепочки (в ip семействе фильтра/НАТ).
  • Перенести свой каркас в nftables с нужным приоритетом или оставить его в iptables, но не переписывать докеровские цепи.
  • Проверить sysctl для bridge и форвардинга.

Пример: «прод» и «стейджинг» на одном хосте

Задача: два проекта в отдельных сетях, прод публикует 443, стейджинг доступен только с админской подсети, между сетями — ноль связности, исход наружу — только 80/443 и DNS.

  1. Создаём две user-defined сети с непересекающимися подсетями (compose или docker network create).
  2. Включаем sysctl для bridge и forwarding.
  3. Применяем каркасные правила из разделов выше.
  4. Добавляем в DOCKER-USER allowlist для 443 с нужного источника (если требуется ограничение) и общий egress-фильтр.
  5. Проверяем tcpdump на br-prod и br-stage, убеждаемся, что межсетевой трафик дропается.

Частые ошибки и анти-паттерны

  • Ставить ACCEPT повсюду «чтобы заработало». Так вы теряете контроль. Оставьте stateful-правила и DOCKER-USER для точечных разрешений.
  • Менять/удалять цепочки DOCKER. Docker их восстановит, а вы получите гонки состояний. Работайте через DOCKER-USER и собственные nft-цепи.
  • Игнорировать br_netfilter и bridge-nf-call-*. Тогда фильтрация на мостах частично не сработает.
  • Смешивать UFW/firewalld с ручными правками без понимания порядка. Фиксируйте зоны, приоритеты и используйте трассировку nft.
  • Публиковать внутренние сервисы наружу. Лучше заведите обратный прокси и приватные сети.

Итог: рецепт жёсткого, но не хрупкого контура

Держите минимальные политики на INPUT и FORWARD, не ломая автоматику Docker. Все периметровые и межмостовые ограничения — в DOCKER-USER (для iptables) или в ранних цепочках nftables с отрицательным приоритетом. Разделяйте контейнеры по user-defined сетям, отключите дефолтный мост, включите фильтрацию моста в ядре, контролируйте egress. Отладку ведите через nft monitor trace, conntrack и tcpdump. При таком подходе вы сохраняете стабильность Docker-сетей и получаете предсказуемый, прозрачный контур безопасности.

Поделиться статьей

Вам будет интересно

rclone serve: S3/WebDAV/HTTP как универсальный шлюз к Object Storage OpenAI Статья написана AI (GPT 5)

rclone serve: S3/WebDAV/HTTP как универсальный шлюз к Object Storage

Покажем, как превратить Object Storage в универсальный сервис с rclone serve: отдача по HTTP, WebDAV и S3, настройка VFS‑кэша и TT ...
fscrypt на ext4: практическое шифрование каталогов на VDS и сравнение с LUKS OpenAI Статья написана AI (GPT 5)

fscrypt на ext4: практическое шифрование каталогов на VDS и сравнение с LUKS

Разбираем нативное шифрование ext4 с fscrypt: чем оно отличается от LUKS на уровне диска, когда какой подход использовать на VDS, ...
Podman Quadlet: rootless systemd на VDS — практическое руководство OpenAI Статья написана AI (GPT 5)

Podman Quadlet: rootless systemd на VDS — практическое руководство

Quadlet превращает .container/.pod в systemd‑юниты. В связке с rootless Podman и systemd --user это чистый и безопасный способ дер ...