Docker iptables как настроить

Docker and iptables

Estimated reading time: 4 minutes

On Linux, Docker manipulates iptables rules to provide network isolation. While this is an implementation detail and you should not modify the rules Docker inserts into your iptables policies, it does have some implications on what you need to do if you want to have your own policies in addition to those managed by Docker.

If you’re running Docker on a host that is exposed to the Internet, you will probably want to have iptables policies in place that prevent unauthorized access to containers or other services running on your host. This page describes how to achieve that, and what caveats you need to be aware of.

Add iptables policies before Docker’s rules

Docker installs two custom iptables chains named DOCKER-USER and DOCKER , and it ensures that incoming packets are always checked by these two chains first.

All of Docker’s iptables rules are added to the DOCKER chain. Do not manipulate this chain manually. If you need to add rules which load before Docker’s rules, add them to the DOCKER-USER chain. These rules are applied before any rules Docker creates automatically.

Rules added to the FORWARD chain — either manually, or by another iptables-based firewall — are evaluated after these chains. This means that if you expose a port through Docker, this port gets exposed no matter what rules your firewall has configured. If you want those rules to apply even when a port gets exposed through Docker, you must add these rules to the DOCKER-USER chain.

Restrict connections to the Docker host

By default, all external source IPs are allowed to connect to the Docker host. To allow only a specific IP or network to access the containers, insert a negated rule at the top of the DOCKER-USER filter chain. For example, the following rule restricts external access from all IP addresses except 192.168.1.1 :

Please note that you will need to change ext_if to correspond with your host’s actual external interface. You could instead allow connections from a source subnet. The following rule only allows access from the subnet 192.168.1.0/24 :

Finally, you can specify a range of IP addresses to accept using —src-range (Remember to also add -m iprange when using —src-range or —dst-range ):

You can combine -s or —src-range with -d or —dst-range to control both the source and destination. For instance, if the Docker daemon listens on both 192.168.1.99 and 10.1.2.3 , you can make rules specific to 10.1.2.3 and leave 192.168.1.99 open.

iptables is complicated and more complicated rules are out of scope for this topic. See the Netfilter.org HOWTO for a lot more information.

Docker on a router

Docker also sets the policy for the FORWARD chain to DROP . If your Docker host also acts as a router, this will result in that router not forwarding any traffic anymore. If you want your system to continue functioning as a router, you can add explicit ACCEPT rules to the DOCKER-USER chain to allow it:

Prevent Docker from manipulating iptables

It is possible to set the iptables key to false in the Docker engine’s configuration file at /etc/docker/daemon.json , but this option is not appropriate for most users. It is not possible to completely prevent Docker from creating iptables rules, and creating them after-the-fact is extremely involved and beyond the scope of these instructions. Setting iptables to false will more than likely break container networking for the Docker engine.

For system integrators who wish to build the Docker runtime into other applications, explore the moby project.

Setting the default bind address for containers

By default, the Docker daemon will expose ports on the 0.0.0.0 address, i.e. any address on the host. If you want to change that behavior to only expose ports on an internal IP address, you can use the —ip option to specify a different IP address. However, setting —ip only changes the default, it does not restrict services to that IP.

Integration with Firewalld

If you are running Docker version 20.10.0 or higher with firewalld on your system with —iptables enabled, Docker automatically creates a firewalld zone called docker and inserts all the network interfaces it creates (for example, docker0 ) into the docker zone to allow seamless networking.

Consider running the following firewalld command to remove the docker interface from the zone.

Restarting dockerd daemon inserts the interface into the docker zone.

Источник

Docker: docker и iptables или файерволы

По умолчанию, docker daemon модифицирует iptables правила файервола без какого-либо уведомления или согласования с администратором. Для этого он используте к примеру цепочку с именем DOCKER и не только.

Читайте также:  Не работает измеритель артериального давления and

Chain FORWARD ( policy DROP )
target prot opt source destination
DOCKER all — 0.0.0.0 / 0 0.0.0.0 / 0
.

Chain DOCKER ( 1 references )
target prot opt source destination

Более того, когда вы указываете docker открывать порт контейнера, он открывает его всему миру, нарушая ваши возможные правила iptables. Итак … если вы запускаете docker на хосте, на котором уже установлен брандмауэр на основе iptables, вам, вероятно, следует установить –iptables = false. Давайте возьмем пример. Вы хотите запустить nginx и связать containerPort 80 с hostPort 9090:

За сценой он добавляет правило iptables в цепочку фильтров DOCKER:

Chain FORWARD ( policy DROP )
target prot opt source destination
DOCKER all — 0.0.0.0 / 0 0.0.0.0 / 0
.

Chain DOCKER ( 1 references )
target prot opt source destination
ACCEPT tcp — 0.0.0.0 / 0 172.17.0.2 tcp dpt: 9090 — это было добавлено при запуске контейнера

Теперь порт 9090 доступен со всего мира. Потому что мы слушаем 9090 на любых IP-адресах (‘0.0.0.0)’из-за правил пересылки, которые динамически добавляются в цепочку фильтров DOCKER. Обратите внимание, что правила пересылки docker разрешают все внешние IP-адреса по умолчанию. Вы, вероятно, не хотите этого. Возможно, вы захотите публиковать порты только локально, а не в ‘0.0.0.0’, для внутреннего использования. Давайте прочитаем документацию по docker-run:

Как видите, вы можете привязать hostPort к IP.

Докер, хватит возиться с моими правилами iptables!

Допустим, вы используете докер на сервере, доступном в Интернете. У вас уже настроен межсетевой экран на основе iptables. Чтобы запретить docker вносить изменения в правила iptables вашей системы, вы должны установить –iptables=false при запуске демона. Для систем на основе sysvinit и upstart вы можете отредактировать /etc/default/docker. Для systemd вы можете сделать это – ‘systemd edit docker.service’ и добавить следующий код и перегрузить docker:

Теперь перезагрузите брандмауэр и перезапустите демон Docker. Вы можете видеть, что цепочка с именем DOCKER и ссылки на нее в цепочке FORWARD исчезли.

Настройте iptables для работы с докером

Если вы все еще используете мост Ethernet, созданный docker и названный docker0, вы можете установить следующие правила для пересылки:

Теперь, если вы хотите открыть TCP-порт 10000 работающего контейнера для всего мира, этот контейнер должен предоставить порт любому IP-адресу (0.0.0.0) на стороне хоста:

docker run —name some-nginx -d -p 10000 : 80 nginx

netstat -an | grep 10000
tcp6 0 0 . 10000 . * LISTEN

Затем вы можете добавить это правило брандмауэра, чтобы разрешить миру доступ к вашему контейнеру через правила пересылки:

Источник

Настройка iptables при работе с Docker Engine

Общая информация

Публикация сетевых портов из docker-контейнеров в хост-систему по умолчанию работает через DNAT трафика на сетевой интерфейс контейнера с приложением. В связи с этим привычная многим фильтрация трафика в цепочке INPUT для docker-контейнеров не применяется, что может привести к несанкционированному доступу к приложениям извне.

Чтобы полностью контролировать доступ к серверу с приложениями в docker’е, необходимо фильтровать трафик также в цепочке FORWARD , а точнее в ее дочерней цепочке DOCKER-USER .

Пример

Применение приведённых в примере правил без адаптации к конкретному серверу может привести к недоступности сервисов

В данном примере:

  1. Доступ к docker-контейнерам фильтруется в цепочке DOCKER-USER , а доступ к приложениям хост-системы — традиционно в цепочке INPUT .
  2. Для разрешающих правил цепочки DOCKER-USER применяется действие RETURN , потому что трафик дальше продолжает обрабатываться служебными правилами Docker Engine.
  3. Порты назначения в DOCKER-USER определяются с помощью модуля conntrack , поскольку на данном этапе пакеты уже прошли через DNAT и порт назначения изменился на порт внутри контейнера.

Рекомендации

Список правил iptables стоит вести в отдельном файле (например, в /etc/network/iptables.up.rules ) и загружать в систему до запуска Docker Engine.

Изменение правил необходимо выполнять в следующем порядке:

  1. Изменить файл с правилами iptables;
  2. Остановить Docker Engine ( это приведёт к остановке всех docker-приложений, работающих на сервере );
  3. Применить правила iptables;
  4. Запустить Docker Engine;
  5. Проверить работу и доступность docker-приложений (за основу можно взять карту проверок работы биллинга после обновлений).

Остановка Docker Engine для применения правил требуется для переинициализации правил iptables по контейнерам. К сожалению, переинициализировать их без остановки всего Docker Engine невозможно (см. https://github.com/moby/moby/issues/12294).

Применять правила iptables в Debian Linux рекомендуется с использованием утилиты iptables-apply (в случае если эта утилита не получит подтверждения доступа к серверу, изменения в правилах будут отменены). При возникновении ошибок некорректные правила необходимо удалить из файла с правилами iptables, чтобы они не применялись при перезагрузке сервера.

Источник

Пользовательские правила iptables для docker на примере zabbix

Задача: Закрыть все входящие соединение, кроме определенных ip адресов.

Имеется тестовая среда, состоящий из linux и трех windows c статическими ip адресами. На linux установлен docker образами zabbix, redmine. А на двух windows машинах установлены и настроены агенты от zabbix, на третьем нужно организовать возможность просмотра zabbix. Нужно ограничить других пользователей от zabbix сервера, но не ограничивая от redmine.

Все команды выполняются от имени root.

В официальной документации говорится о правиле iptables DOCKER-USER. Следует только это правило менять. Сперва смотрим какие правила есть, акцентируем внимание только на некоторых правилах.

Видно, что в правиле FORWARD первым стоит правило с target DOCKER-USER. Поэтому следует только его изменить.

Из таблицы правил DOCKER можно увидеть какие порты и открыты и внутренние ip адреса контейнеров.

В правиле DOCKER-USER нет особенных правил, все соединение пропускает через себя.

Первую очередь разберемся с сетью zabbix, а именно установим постоянную имя сети. Чтоб при пересоздании docker-compose имя сети не сменился. Из нынешнего состояния сети zabbix имеет сеть под именем br-c56432fe07cc, что не очень хорошо. В файле *.yaml добавим одну строку отвечающее за имя сети zbx_net_frontend: «com.docker.network.bridge.name: «docker_zabbix»».

Читайте также:  Чего не работает канал тнт

После пересоздаем сеть. Следует заменить на вашу *.yaml.

Cмотрим правило DOCKER.

Осталось добавить правило в таблицу DOCKER-USER. Первом делом ведем правило DROP для всех подключений в сеть docker_zabbix из внешнего интерфейса (у меня eth0).

Сейчас все соединение запрещены в сеть docker_zabbix. Разрешим соединение для одного ip адреса, точнее сказать пакет может продолжить путь дальше по FORWARD.

Здесь явным образом не указали сеть docker_zabbix. Проверяем доступность zabbix от хоста 192.168.43.55 с помощью powershell.

8081 порт открыт для zabbix docker. Чтоб удостовериться в том, что zabbix принадлежит 8081 порт.

Но следует учесть, что в правилах надо указывать порт 80, а не 8081. Если указать порт 8081, то не откроется доступ к zabbix. Для второго хоста команда.

Для третьего хоста откроем только порт 10051, на этом хосте используется активный агент.

Еще одна проблема, не можем из контейнеров выйти в внешний мир. Не работают скрипты оповещение и не может проверить доступность сайтов. Осталось еще одна команда для разрешение уже имеющих соединений.

Не забываем, что после перезагрузки сервера созданные правило стираются.

Источник

Сети Docker изнутри: как Docker использует iptables и интерфейсы Linux

Я познакомился с Docker довольно давно и, как и большинство его пользователей, был мгновенно очарован его мощью и простотой использования. Простота является основным столпом, на котором основывается Docker, чья сила кроется в легких CLI-командах. Когда я изучал Docker, я захотел выяснить, что происходит у него в бэкграунде, как вообще все происходит, особенно что касается работы с сетью (для меня это одна из самых интересных областей).

Я нашел много разной документации о том, как создавать контейнерные сети и управлять ими, но в отношении того, как именно они работают, материалов намного меньше. Docker широко использует Linux iptables и bridge-интерфейсы для создания контейнерных сетей, и в этой статье я хочу подробно рассмотреть именно этот аспект. Информацию я почерпнул, в основном, из комментариев на github-е, разных презентаций, ну и из моего собственного опыта. В конце статьи можно найти список полезных ресурсов.

Я использовал Docker версии 1.12.3 для примеров в этой статье. Я не ставил своей целью дать исчерпывающее описание Docker-сетей или написать полное введение в эту тему. Я надеюсь, что этот материал будет полезен для пользователей, и я буду рад, если вы в комментариях оставите обратную связь, укажете на ошибки или скажете, чего недостает.

Оглавление

Обзор сетей Docker

Сеть Docker построена на Container Network Model (CNM), которая позволяет кому угодно создать свой собственный сетевой драйвер. Таким образом, у контейнеров есть доступ к разным типам сетей и они могут подключаться к нескольким сетям одновременно. Помимо различных сторонних сетевых драйверов, у самого Docker-а есть 4 встроенных:

  • Bridge: в этой сети контейнеры запускаются по умолчанию. Связь устанавливается через bridge-интерфейс на хосте. У контейнеров, которые используют одинаковую сеть, есть своя собственная подсеть, и они могут передавать данные друг другу по умолчанию.
  • Host: этот драйвер дает контейнеру доступ к собственному пространству хоста (контейнер будет видеть и использовать тот же интерфейс, что и хост).
  • Macvlan: этот драйвер дает контейнерам прямой доступ к интерфейсу и суб-интерфейсу (vlan) хоста. Также он разрешает транкинг.
  • Overlay: этот драйвер позволяет строить сети на нескольких хостах с Docker (обычно на Docker Swarm кластере). У контейнеров также есть свои адреса сети и подсети, и они могут напрямую обмениваться данными, даже если они располагаются физически на разных хостах.

Сетевые драйвера Bridge и Overlay, возможно, используются чаще всего, поэтому в этой статье я буду больше уделять им внимание.

Сети типа мост (bridge)

По умолчанию для контейнеров используется bridge. При первом запуске контейнера Docker создает дефолтную bridge-сеть с одноименным названием. Эту сеть можно увидеть в общем списке по команде docker network ls :

Чтобы проинспектировать ее свойства, запустим команду docker network inspect bridge :

Вы также можете создать свои собственные bridge-сети при помощи команды docker network create , указав опцию —driver bridge .

Например, команда docker network create —driver bridge —subnet 192.168.100.0/24 —ip-range 192.168.100.0/24 my-bridge-network создает еще одну bridge-сеть с именем “my-bridge-network” и подсетью 192.168.100.0/24.

Bridge-интерфейсы в Linux

Каждая bridge-сеть имеет свое представление в виде интерфейса на хосте. С сетью “bridge”, которая стоит по умолчанию, обычно ассоциируется интерфейс docker0, и с каждой новой сетью, которая создается при помощи команды docker network create , будет ассоциироваться свой собственный новый интерфейс.

Чтобы найти интерфейс, который ассоциируется с сетью, которую вы создали, введите команду ifconfig , чтобы вывести все интерфейсы, а затем найти тот интерфейс, который относится к созданной вами подсети. Например, если нам надо найти интерфейс для сети my-bridge-network, которую мы только что создали, то можно запустить такую команду:

Bridge-интерфейсы Linux похожи на свичи тем, что они присоединяют несколько интерфесов к одной подсети и перенаправляют трафик на основе MAC-адресов. Как будет видно ниже, у каждого контейнера, привязанного к bridge-сети, будет свой собственный виртуальный интерфейс на хосте, и все контейнеры в одной сети будут привязаны к одному интерфейсу, что позволит им передавать друг другу данные. Можно получить больше данных о статусе моста при помощи утилиты brctl :

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

Читайте также:  Бэтмен аркхем сити как настроить графику

Виртуальные интерфейсы Linux

Container Networking Model дает каждому контейнеру свое собственное сетевое пространство. Если запустить команду ifconfig внутри контейнера, то можно увидеть его интерфейсы такими, какими их видит сам контейнер:

Впрочем, eth0, который представлен в этом примере, можно увидеть только изнутри контейнера, а снаружи, на хосте, Docker создает соответствующую копию виртуального интерфейса, которая служит связью с внешним миром. Затем эти виртуальные интерфейсы соединяются с bridge-интерфейсами, о которых мы говорили выше, чтобы легче установить связь между разными контейнерами в одной подсети.

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

До запуска каких-либо контейнеров у bridge-интерфейса docker0 нет никаких других присоединенных интерфейсов:

Затем я запустил два контейнера на образе ubuntu:14.04:

Сразу стало видно, что два интерфейса присоединены к bridge-интерфейсу docker0 (по одному на каждый контейнер):

Если начать пинговать Google с одного из контейнеров, то захват трафика с хоста на виртуальном интерфейсе контейнера покажет нам трафик контейнеров:

Аналогично можно выполнить пинг от одного контейнера к другому.

Во-первых, надо получить IP-адрес контейнера. Это можно сделать либо при помощи команды ifconfig , либо при помощи docker inspect , что позволяет проинспектировать контейнер:

Затем начинаем пинг от одного контейнера к другому:

Чтобы увидеть трафик с хоста, мы можем сделать захват на любом из виртуальных интерфейсов, которые соотносятся с контейнерами, либо на bridge-интерфейсе (в данном случае docker0), что покажет нам все коммуникации внутри контейнеров данной подсети:

Находим Veth-интерфейс в контейнере

Если вы хотите узнать, какой veth-интерфейс хоста привязан к интерфейсу внутри контейнера, то простого способа вы не найдете. Однако, есть несколько методов, которые можно найти на разных форумах и в обсуждениях на github. Самый простой, на мой взгляд, способ я почерпнул из этого обсуждения на github, немного его изменив. Он зависит от того, присутствует ли ethtool в контейнере.

Например, у меня в системе запущены 3 контейнера:

Для начала, я выполняю следующую команду в контейнере и получаю номер peer_ifindex:

Затем на хосте я использую peer_ifindex, чтобы узнать имя интерфейса:

В данном случае интерфейс называется veth7bd3604.

iptables

Docker использует linux iptables, чтобы контролировать коммуникации между интерфейсами и сетями, которые он создает. Linux iptables состоят из разных таблиц, но нам в первую очередь интересны только две из них: filter и nat. Таблица filter содержит правила безопасности, которые решают, допускать ли трафик к IP-адресам или портам. С помощью таблицы nat Docker дает контейнерам в bridge-сетях связываться с адресатами, которые находятся снаружи хоста (иначе пришлось бы добавлять маршруты к контейнерным сетям в сети хоста).

iptables:filter

Таблицы в iptables состоят из различных цепочек, которые соответствуют разным состояниям или стадиям обработки пакета на хосте. По умолчанию, у таблицы filter есть 3 цепочки:
Input для обработки входящих пакетов, предназначенных для того же хоста, на который они приходят;
Output для пакетов, возникающих на хосте, предназначенных для внешнего адресата;
Forward для обработки входящих пакетов, предназначенных для внешнего адресата.

Каждая цепочка включает в себя правила, которые определяют, какие действия и при каких условиях надо применить к пакету (например, отклонить или принять его). Правила обрабатываются последовательно, пока не будет найдено соответствие, иначе применяются дефолтные правила цепочки. Также в таблице можно задать кастомные цепочки.

Чтобы увидеть текущие правила цепочки и дефолтные установки в таблице filter, запустите команду iptables -t filter -L или iptables -L , если таблица filter используется по умолчанию и не указана никакая другая таблица:

Жирным выделены разные цепочки и дефолтные установки для каждой из них (у кастомных цепочек дефолтных установок нет). Также видно, что Docker добавил две кастомные цепочки: Docker и Docker-Isolation, также добавил правила в цепочку Forward, целью которых являются эти две новые цепочки.

Цепочка Docker-isolation

Docker-isolation содержит правила, которые ограничивают доступ между разными сетями. Чтобы узнать подробности, добавляйте -v , когда запускаете iptables:

Можно увидеть несколько правил DROP, которые блокируют трафик между всеми bridge-интерфейсами, которые создал Docker, и таким образом не дают сетям обмениваться данными.

icc=false

Одна из опций, которую можно передать команде docker network create , — это опция, которая отвечает за передачу данных внутри контейнера: com.docker.network.bridge.enable_icc . Если задать ей значение false, то передача данных между контейнерами внутри одной сети будет заблокирована. Для этого нужно добавить DROP-правило в цепочку forward, которое соответствует пакетам, приходящим от bridge-интерфейса, связанного с сетью для данного интерфейса.

Например, если создать новую сеть при помощи команды docker network create —driver bridge —subnet 192.168.200.0/24 —ip-range 192.168.200.0/24 -o «com.docker.network.bridge.enable_icc»=»false» no-icc-network , то мы получим следующее:

iptables:nat

С помощью nat можно поменять IP-адрес или порт пакета. В данном случае он используется, чтобы за IP-адресом хоста спрятать адреса источников пакетов, которые приходят от bridge-сетей (например, хосты в подсети 172.18.0.0/24) и направлены во внешний мир. Эта фича контролируется опцией com.docker.network.bridge.enable_ip_masquerade , которую можно передать docker network create (если не задать ничего специфического, то по умолчанию будет значение true).

Результат этой команды можно увидеть в таблице nat:

В этой цепочке postrouting можно увидеть все сети, которые созданы под действием masquerade, которое применяется, когда они передают данные любому хосту вне своей собственной сети.

Источник

Оцените статью