Набір правил Iptables, щоб контейнер докера міг отримувати доступ до послуги на хості IP


18

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

Оскільки це не характерно для моїх служб (DNS), я виключив це з проблеми, оскільки пошук цього в поєднанні з докером дає результати в іншій (популярній) проблемній області, додаючи шум результатам пошуку.

Також зв'язування контейнерів Docker не є життєздатним варіантом, тому що певні контейнери потрібно запускати з опцією --net = хост, запобігаючи посиланням, і я хочу створити послідовну ситуацію, де це можливо.

У мене є такі правила 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 forever
4: 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 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

Моя резолюція.conf

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

Сенс у цьому полягає не в доступі до публічних хостів, а до внутрішніх, використовуючи локальну службу DNS, доступну на хості (через інший екземпляр докера).

Щоб проілюструвати це ще більше (Мої навички дизайну мистецтва ascii перевершують мою iptables fu, так що цього могло б сказати досить):

 ______________________________________________
|  __________________________           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               destination
DOCKER     all  --  0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL

Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
DOCKER     all  --  0.0.0.0/0           !127.0.0.0/8          ADDRTYPE match dst-type LOCAL

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination
MASQUERADE  all  --  172.17.0.0/16        0.0.0.0/0

Chain DOCKER (2 references)
target     prot opt source               destination

Вихід cat /proc/sys/net/ipv4/ip_forward:

1

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

Звичайно, дякую за допомогу до цього часу: pastebin.com/TAaT73nk (коментар не підходив ..) - редагувати -> Оновлено посилання на пастину, яка не закінчується.
Діном

Можливо, я неправильно зрозумів вашу проблему, але я не бачу жодного правила дозволу DNS-запитів на хості. Також, чи включений ip_forward?
Laurentiu Roescu

Привіт @LaurentiuRoescu. $ cat /proc/sys/net/ipv4/ip_forward -> 1і -A INPUT -i eth1 -j ACCEPTприймає всі з'єднання в приватному інтерфейсі. Які правила вам не вистачає?
Діном

2
Я думаю, що пакети з контейнера надходять через інтерфейс docker0, а не eth1. спробуйте-A INPUT -i docker0 -j ACCEPT
Laurentiu Roescu

Відповіді:


14

Контейнер спілкується з хостом за допомогою docker0інтерфейсу. Щоб дозволити трафік з контейнера, додайте:

-A INPUT -i docker0 -j ACCEPT

2
Dynom, урок, який ви можете захопити, це те, що реєструвати всі ваші відмови корисно, наприклад, наприклад iptables -A INPUT -j LOG. Штамп IN=docker0був би дуже корисним при розробці того, яке налаштування правила потрібно. Не відривати від роботи Лаурентью, яка була чудовою - +1 від мене!
MadHatter підтримує Моніку

5
Для людей, які використовують UFW, ось що я зробив, щоб дозволити приймати всі комунікації з контейнерів Docker: ufw дозволити на docker0
Ali Ok

0

Я зіткнувся з дуже подібною ситуацією, але додавання -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. Тому я додав подібні правила, щоб дозволити моєму контейнеру отримати доступ до інших бажаних портів хосту, що, на мою думку, може бути трохи більш точним способом відкрити доступ хост-мережі до контейнерів.


-i docker0слід переконатися, що це не вплине на трафік, який не надходить через мережу docker0. Однак ваша граматика незрозуміла. Можливо, ви казали, що вихідний доступ з хостів докера через eth0 увімкнено, що може бути правдою. Я погоджуюся, що більш цільові правила можливі, відкриваючи лише стільки, скільки потрібно.
mc0e
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.