Docker игнорирует правила iptable при использовании "-p <port>: <port>"

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

Так что я хочу довольно просто. Я хочу, чтобы он вел себя так, как ожидалось. Это, если у меня есть правило ACCEPT, чтобы пройти, и если оно не заблокировано.

Мой iptable выглядел первоначально так (так перед моими неудачными попытками):

*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [779:162776]
-A INPUT -i lo -j ACCEPT
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -s 1.2.3.4 -p tcp -m tcp --dport 123 -j ACCEPT
-A INPUT -j DROP
COMMIT

Надеюсь, что он делает именно то, что я хочу. Просто разрешите доступ к портам 22 и 80, а также разрешите порт 123 из ip 1.2.3.4. Однако, если я создаю контейнер с "-p 123: 123", каждый может получить к нему доступ. Может ли кто-нибудь помочь мне и рассказать мне, как мне изменить этот файл?

Спасибо!

Докер-версия: 1.6.2

Изменить:

Сначала изначально мои разные попытки не перекомпилировать вопрос. Однако добавление хотя бы одного из них может быть полезным.

*nat
:PREROUTING ACCEPT [319:17164]
:INPUT ACCEPT [8:436]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [16:960]
:DOCKER - [0:0]
COMMIT


*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [779:162776]
:DOCKER - [0:0]
-A INPUT -i lo -j ACCEPT
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A DOCKER -s 1.2.3.4 -p tcp -m tcp --dport 123 -j ACCEPT
-A DOCKER -j DROP
-A INPUT -j DROP
COMMIT

Вышеупомянутые виды работ. Однако, тогда получится много других проблем. Например, возникают проблемы с привязкой контейнеров, DNS больше не работает и т.д. Итак, добавьте много дополнительных правил, чтобы исправить эти проблемы, но я не получаю ни одного состояния, в котором он работает правильно. Поэтому я предполагаю, что лучше всего лучше и проще решать проблемы.

Решение:

Закончилось делать более или менее точно то, что говорили ларски. Просто не добавили его в цепочку FORWARD, вместо этого я добавил его в цепочку DOCKER. Проблема с цепочкой FORWARD заключается в том, что Docker добавляет свой материал туда, когда он перезапускается в первом положении. Это приводит к тому, что мои правила сбрасываются и не оказывают никакого эффекта. Однако для цепи DOCKER кажется, что Docker добавляет только дополнительные правила, поэтому мое пребывание в действии. Поэтому, когда я сохраняю свои правила, а затем перезагружаю сервер, все работает нормально.

Итак, теперь это выглядит примерно так:

*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [779:162776]
:DOCKER - [0:0]
# That I can access from IP 1.2.3.4
-A DOCKER -s 1.2.3.4/32 -p tcp -m tcp --dport 123 -j ACCEPT
# That I can access from other Docker containers
-A DOCKER -o docker0 -p tcp -m tcp --dport 123 -j ACCEPT
# Does not allow it for anything else
-A DOCKER -p tcp --dport 123 -j DROP

-A INPUT -i lo -j ACCEPT
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -j DROP
COMMIT

Ответ 1

Ваша конфигурация iptables выглядит немного сломанной прямо сейчас, как если бы вы очистили ее в какой-то момент без перезапуска Docker. Например, у вас есть цепочка DOCKER, доступная как в таблицах filter, так и nat, но нет правил, которые ссылаются на нее, поэтому правила, помещенные в эту цепочку, не будут влиять.

В общем, если вы хотите внедрить правила iptables, которые влияют на ваши контейнеры Docker, им нужно перейти в цепочку FORWARD filter table. Each container has it *own* ip address, which means that your host is simply accepting packets and then FORWARD, указав их на адрес контейнера.

Правила в цепочке INPUT относятся только к пакетам с конечным адресатом адреса на интерфейсе в пространстве имен глобальной сети хоста.

Однако я не уверен, что iptables на самом деле ваша проблема.

Если вы пытаетесь открыть службы в контейнерах, чтобы они были доступны другим системам, вам необходимо опубликовать эти порты, используя флаг -p, чтобы docker run. Вы можете узнать больше об этом в в этом разделе документации (Dockumentation?).

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

Обновление

Правда, когда вы публикуете порт контейнера с помощью -p, он обычно будет доступен для любого IP-адреса источника. Чтобы ограничить доступ к опубликованному порту, вам нужно добавить новое правило в цепочку FORWARD. Например, если я запускаю веб-сервер:

docker run --name web -p 80:8080 larsks/mini-httpd

Веб-сервер в контейнере теперь доступен на порту 8080 на моем хосте. Если я хочу заблокировать доступ к этому порту, мне нужно вставить правило в цепочку FORWARD, которая блокирует доступ к порту 80 на ip-контейнере. Поэтому сначала мне нужен адрес ip контейнера:

$ web_ip=$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' web)
$ echo $web_ip
172.17.0.5

Правило, созданное в цепочке FORWARD, должно появиться перед правилами, которые создает докер, поэтому мне нужно будет указать явное положение:

iptables -I FORWARD 1 -d $web_ip -p tcp --dport 80 \
  \! -s 192.168.1.10 -j DROP

Это блокирует весь трафик с хостов, отличных от 192.168.1.10.

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

-A FORWARD -o docker0 -p tcp --dport 80 \
    \! -s 192.168.1.10 -j DROP

Это запретит доступ к порту 80 в любом контейнере.

Ответ 2

Я не эксперт в iptables, но я знаю, что если вы запустите контейнер с -p 127.0.0.1:123:123, тогда порт не будет отображаться на всех интерфейсах, как раз на loopback.

Ответ 3

Закончилось делать более или менее точно то, что говорили ларски. Просто не добавил это в цепочку FORWARD, я добавил ее в цепочку DOCKER.

Я нашел то же самое в документах: https://docs.docker.com/v1.5/articles/networking/#the-world

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

Правила пересылки докеров разрешают всем внешним IP-адресам источника по умолчанию. Для разрешить доступ только к конкретным IP или сетям для доступа к контейнерам, вставить отрицательное правило в верхней части цепи фильтра DOCKER. Например, для ограничивать внешний доступ таким образом, чтобы доступ к источнику IP 8.8.8.8 контейнеры, можно добавить следующее правило:

$ iptables -I DOCKER -i ext_if ! -s 8.8.8.8 -j DROP