Docker
Iptables with Docker
Поиск…
Вступление
В этом разделе рассказывается о том, как ограничить доступ к контейнерам докеров из внешнего мира с помощью iptables.
Для нетерпеливых людей вы можете проверить примеры. Для остальных, пожалуйста, прочитайте раздел примечаний, чтобы понять, как создавать новые правила.
Синтаксис
- iptables -I DOCKER [RULE ...] [ACCEPT | DROP] // Чтобы добавить правило в верхнюю часть таблицы DOCKER
- iptables -D DOCKER [RULE ...] [ACCEPT | DROP] // Чтобы удалить правило из таблицы DOCKER
- ipset restore </etc/ipfriends.conf // Чтобы перенастроить ваш ipps- адрес ipset
параметры
параметры | подробности |
---|---|
ext_if | Ваш внешний интерфейс на хосте Docker. |
XXX.XXX.XXX.XXX | Необходимо указать конкретный IP-адрес, на который должен быть предоставлен доступ к контейнерам Docker. |
YYY.YYY.YYY.YYY | Еще один IP-адрес, на который должен быть предоставлен доступ к контейнерам Docker. |
ipfriends | Имя ipset, определяющее IP-адреса, позволило получить доступ к вашим контейнерам Docker. |
замечания
Эта проблема
Настройка правил iptables для контейнеров Docker немного сложна. Сначала вы думаете, что «классические» правила брандмауэра должны делать трюк.
Например, предположим, что вы сконфигурировали контейнер nginx-proxy + несколько контейнеров-служб для предоставления через HTTPS некоторых персональных веб-сервисов. Затем такое правило должно предоставлять доступ к вашим веб-службам только для IP XXX.XXX.XXX.XXX.
$ iptables -A INPUT -i eth0 -p tcp -s XXX.XXX.XXX.XXX -j ACCEPT
$ iptables -P INPUT DROP
Это не сработает, ваши контейнеры все еще доступны для всех.
Действительно, контейнеры Docker не являются хост-услугами. Они полагаются на виртуальную сеть вашего хоста, а хост выступает в качестве шлюза для этой сети. Что касается шлюзов, маршрутизируемый трафик не обрабатывается таблицей INPUT, а таблицей FORWARD, что делает правило выше, чем неэффективным.
Но это еще не все. Фактически, демон Docker создает множество правил iptables, когда он начинает делать свою магию в отношении подключения к сети контейнеров. В частности, создается таблица DOCKER для обработки правил, касающихся контейнеров, путем пересылки трафика из таблицы FORWARD в эту новую таблицу.
$ iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain FORWARD (policy DROP)
target prot opt source destination
DOCKER-ISOLATION all -- anywhere anywhere
DOCKER all -- anywhere anywhere
ACCEPT all -- anywhere anywhere ctstate RELATED,ESTABLISHED
ACCEPT all -- anywhere anywhere
ACCEPT all -- anywhere anywhere
DOCKER all -- anywhere anywhere
ACCEPT all -- anywhere anywhere ctstate RELATED,ESTABLISHED
ACCEPT all -- anywhere anywhere
ACCEPT all -- anywhere anywhere
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
Chain DOCKER (2 references)
target prot opt source destination
ACCEPT tcp -- anywhere 172.18.0.4 tcp dpt:https
ACCEPT tcp -- anywhere 172.18.0.4 tcp dpt:http
Chain DOCKER-ISOLATION (1 references)
target prot opt source destination
DROP all -- anywhere anywhere
DROP all -- anywhere anywhere
RETURN all -- anywhere anywhere
Решение
Если вы проверяете официальную документацию ( https://docs.docker.com/v1.5/articles/networking/) , то предоставляется первое решение ограничить доступ контейнера Docker к одному конкретному IP- адресу .
$ iptables -I DOCKER -i ext_if ! -s 8.8.8.8 -j DROP
Действительно, добавление правила в верхней части таблицы DOCKER - хорошая идея. Это не мешает правилам, автоматически настроенным Docker, и это просто. Но два основных недостатка:
- Во-первых, что, если вам нужно получить доступ с двух IP вместо одного? Здесь может быть принят только один IP-адрес src, другие будут исключены, чтобы предотвратить это.
- Во-вторых, что делать, если вашему докере нужен доступ в Интернет? При этом ни один запрос не будет выполнен, так как только сервер 8.8.8.8 может ответить на них.
- Наконец, что делать, если вы хотите добавить другие логики? Например, предоставить доступ любому пользователю к вашему веб-серверу, работающему по протоколу HTTP, но ограничивать все остальное конкретным IP-адресом.
Для первого наблюдения мы можем использовать ipset . Вместо того, чтобы разрешать один IP в приведенном выше правиле, мы разрешаем всем IP-адресам из предопределенного ipset. В качестве бонуса ipset можно обновить без необходимости переопределять правило iptable.
$ iptables -I DOCKER -i ext_if -m set ! --match-set my-ipset src -j DROP
Для второго наблюдения это каноническая проблема для брандмауэров: если вам разрешено связаться с сервером через брандмауэр, тогда брандмауэр должен разрешить серверу отвечать на ваш запрос. Это можно сделать, разрешив пакеты, связанные с установленным соединением. Для докерной логики он дает:
$ iptables -I DOCKER -i ext_if -m state --state ESTABLISHED,RELATED -j ACCEPT
Последнее наблюдение фокусируется на одной точке: правила iptables необходимы. В самом деле, дополнительная логика для ПРИНИМАНИЯ некоторых подключений (в том числе связанных с ESTABLISHED соединениями) должна быть помещена в верхнюю часть таблицы DOCKER до правила DROP, которое отрицает все остальные соединения, не соответствующие ipset.
Поскольку мы используем опцию -I iptable, которая вводит правила в верхней части таблицы, предыдущие правила iptables должны быть вставлены в обратном порядке:
// Drop rule for non matching IPs
$ iptables -I DOCKER -i ext_if -m set ! --match-set my-ipset src -j DROP
// Then Accept rules for established connections
$ iptables -I DOCKER -i ext_if -m state --state ESTABLISHED,RELATED -j ACCEPT
$ iptables -I DOCKER -i ext_if ... ACCEPT // Then 3rd custom accept rule
$ iptables -I DOCKER -i ext_if ... ACCEPT // Then 2nd custom accept rule
$ iptables -I DOCKER -i ext_if ... ACCEPT // Then 1st custom accept rule
Учитывая все это, вы можете теперь проверить примеры, иллюстрирующие эту конфигурацию.
Ограничить доступ к контейнерам Docker к набору IP-адресов
Во-первых, при необходимости установите ipset . Пожалуйста, обратитесь к вашему дистрибутиву, чтобы узнать, как это сделать. Например, вот команда для Debian-подобных дистрибутивов.
$ apt-get update
$ apt-get install ipset
Затем создайте файл конфигурации, чтобы определить ipset, содержащий IP-адреса, для которых вы хотите открыть доступ к своим контейнерам Docker.
$ vi /etc/ipfriends.conf
# Recreate the ipset if needed, and flush all entries
create -exist ipfriends hash:ip family inet hashsize 1024 maxelem 65536
flush
# Give access to specific ips
add ipfriends XXX.XXX.XXX.XXX
add ipfriends YYY.YYY.YYY.YYY
Загрузите этот ipset.
$ ipset restore < /etc/ipfriends.conf
Убедитесь, что ваш демон Docker запущен: при вводе следующей команды не следует выводить никаких ошибок.
$ docker ps
Вы готовы вставить свои правила iptables. Вы должны уважать заказ.
// All requests of src ips not matching the ones from ipset ipfriends will be dropped.
$ iptables -I DOCKER -i ext_if -m set ! --match-set ipfriends src -j DROP
// Except for requests coming from a connection already established.
$ iptables -I DOCKER -i ext_if -m state --state ESTABLISHED,RELATED -j ACCEPT
Если вы хотите создать новые правила, вам нужно будет удалить все пользовательские правила, которые вы добавили, прежде чем вставлять новые.
$ iptables -D DOCKER -i ext_if -m set ! --match-set ipfriends src -j DROP
$ iptables -D DOCKER -i ext_if -m state --state ESTABLISHED,RELATED -j ACCEPT
Настройка доступа к ограничениям при запуске Docker-демона
Работа в процессе
Некоторые пользовательские правила iptables
Работа в процессе