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

У меня возникли проблемы с доступом к частному интерфейсу хоста (ip) из контейнера docker. Я совершенно уверен, что это связано с моими правилами Iptables (или, возможно, маршрутизацией). Когда я добавляю --net=host флаг, чтобы docker run, все работает, как и ожидалось. Аналогично, когда я указываю, что политика ВВОДА следует либеральной -P INPUT ACCEPT, все также работает так, как я и ожидал. Однако это нежелательные и небезопасные варианты, которых я хотел бы избежать.

Поскольку это не относится конкретно к моим службам (DNS), я исключил это из проблемы, поскольку поиск этого в сочетании с docker приводит к другой (популярной) проблемной области, добавляя шума в результаты поиска.

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

У меня есть следующие правила Iptables. Полагаю, это комбинация CoreOS, Digital Ocean и Docker.

-P INPUT DROP-P FORWARD ACCEPT-P OUTPUT ACCEPT-N DOCKER-A INPUT -i lo -j ACCEPT-A INPUT -i eth1 -j ACCEPT-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT-A INPUT -p icmp -m icmp --icmp-type 0 -j ACCEPT-A INPUT -p icmp -m icmp --icmp-type 3 -j ACCEPT-A INPUT -p icmp -m icmp --icmp-type 11 -j ACCEPT-A FORWARD -o docker0 -j DOCKER-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT-A FORWARD -i docker0 ! -o docker0 -j ACCEPT-A FORWARD -i docker0 -o docker0 -j ACCEPT

Мои (соответствующие) интерфейсы хоста:

3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000    inet 10.129.112.210/16 brd 10.129.255.255 scope global eth1       valid_lft forever preferred_lft forever4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default    inet 172.17.42.1/16 scope global docker0       valid_lft forever preferred_lft forever

И я запускаю контейнер docker:

$ docker run --rm -it --dns=10.129.112.210 debian:jessie # Specifying the DNS is so that the public DNS servers aren't used.

На данный момент я хочу иметь возможность использовать локальную службу, привязанную к 10.129.112.210:53. Так что следующее должно дать ответ:

$ ping google.com^C$ ping user.skydns.local^C

Когда я запускаю ту же команду с моего хоста:

$ ping photo.skydns.localPING photo.skydns.local (10.129.112.206) 56(84) bytes of data.64 bytes from 10.129.112.206: icmp_seq=1 ttl=64 time=0.790 ms^C

Мой resolv.conf

$ cat /etc/resolv.confnameserver 10.129.112.210nameserver 127.0.0.1nameserver 8.8.8.8nameserver 8.8.4.4

Суть здесь не в том, чтобы получить доступ к общедоступным хостам, а скорее к внутренним, используя локальную службу DNS, доступную на хосте (через другой экземпляр docker).

Чтобы проиллюстрировать это еще больше (мои навыки художественного дизайна ascii превосходят мои навыки работы с iptables, так что на данный момент этого должно быть достаточно):

 ______________________________________________|  __________________________           Host   || |   Docker DNS container   |                 ||  ``````````````````````|```                  ||                        |                     ||     ,----------,---( private n. interface )  ||     |          |                             ||     |          |   ( public  n. interface )---|     |          |                             ||     |          |   ( loopbck n. interface )  ||     |          |                             ||     |          |                             ||     |        __|_______________________      ||     |       | Docker service container |     ||     |        ``````````````````````````      ||     |                                        ||     |                                        || [ Local host service using DNS. ]            ||                                              ||______________________________________________|  private (host) network interface: eth1 (10.129.0.0/16)  Docker network interface: docker0 (172.17.0.0/16)

Я искал, читал и применял различные примеры конфигураций Iptables, но я слишком мало знаю о более "продвинутых" правилах Iptables, чтобы понять, что происходит, и, таким образом, получить желаемый результат.

Выход из iptables -t nat -nL:

Chain PREROUTING (policy ACCEPT)target     prot opt source               destinationDOCKER     all  --  0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCALChain INPUT (policy ACCEPT)target     prot opt source               destinationChain OUTPUT (policy ACCEPT)target     prot opt source               destinationDOCKER     all  --  0.0.0.0/0           !127.0.0.0/8          ADDRTYPE match dst-type LOCALChain POSTROUTING (policy ACCEPT)target     prot opt source               destinationMASQUERADE  all  --  172.17.0.0/16        0.0.0.0/0Chain DOCKER (2 references)target     prot opt source               destination

Выход из cat /proc/sys/net/ipv4/ip_forward:

1

Контейнер взаимодействует с хостом с помощью docker0 интерфейс.Чтобы разрешить трафик из контейнера, добавьте:

-A INPUT -i docker0 -j ACCEPT

Я сталкивался с очень похожей ситуацией, но добавляя -A INPUT -i docker0 -j ACCEPT откроет все доступы через мой интерфейс eth0 хоста docker к контейнерам, что абсолютно не то, что я предполагал.

И поскольку я заметил, что мой контейнер просто имел ограниченный доступ (скажем, только порт 22) к интерфейсу хоста вместо полного отключения от сети хоста, я просмотрел свои правила iptables и нашел правило в цепочке IN_public_allow, которое должно отвечать за это. Правило таково -A IN_public_allow -p tcp -m tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT. Поэтому я добавил аналогичные правила, чтобы разрешить моему контейнеру доступ к другим нужным портам хоста, что, я думаю, может быть немного более точным способом открыть доступ к сети хоста к контейнерам.

Я думаю, что пакеты из контейнера поступают из интерфейса docker0, а не eth1. попробуйте `-A INPUT -i docker0 -j ACCEPT’

Конечно, спасибо за помощь до сих пор: Chain PREROUTING (policy ACCEPT)target prot opt source desti - Pastebin.com (Не соответствует комментарию…) --[редактировать] → Обновлена ссылка на вставку, срок действия которой не истекает.

Возможно, я не правильно понял вашу проблему, но я не вижу никакого правила, разрешающего DNS-запросы на хосте. Кроме того, включен ли ip_forward?

Привет, @LaurentiuRoescu. $ cat /proc/sys/net/ipv4/ip_forward -> 1 и -A INPUT -i eth1 -j ACCEPT принимают все соединения на интерфейсе private. Каких правил вам не хватает?

Я думаю, ты справился с этим, @LaurentiuRoescu. Когда я добавляю вашу строку, кажется, это работает. Я никогда не думал, что это что-то настолько тривиальное… Не могли бы вы, пожалуйста, добавить это в качестве ответа на мой вопрос? Я хотел бы вознаградить вас за ответ.

Можете ли вы опубликовать выходные данные iptables -t nat -nL? Выполняли ли вы какой-либо анализ пакетов, скажем, выполняли пинг из исходного контейнера и использовали tcpdump для захвата пакетов на хосте.