Шаги по ограничению внешних подключений к контейнеру docker с помощью iptables?

Моя цель - ограничить доступ к контейнерам docker всего несколькими общедоступными IP-адресами. Существует ли простой, повторяемый процесс для достижения моей цели? Понимая только основы iptables при использовании параметров Docker по умолчанию, я нахожу это очень сложным.

Я хотел бы запустить контейнер, сделать его видимым для общедоступного Интернета, но разрешить подключения только с выбранных хостов. Я ожидал бы установить политику ВВОДА по умолчанию для ОТКЛОНЕНИЯ, а затем разрешить подключения только с моих хостов. Но правила и цепочки NAT Docker мешают, и мои правила ввода игнорируются.

Может кто-нибудь привести пример того, как достичь моей цели, учитывая следующие предположения?

  • Общедоступный IP-адрес хоста 80.80.80.80 на eth0
  • Частный IP-адрес хоста 192.168.1.10 на eth1
  • docker run -d -p 3306:3306 mysql
  • Заблокируйте все соединения с хостом/контейнером 3306, кроме соединений с хостами 4.4.4.4 и 8.8.8.8

Я рад привязать контейнер только к локальному ip-адресу, но мне понадобятся инструкции о том, как правильно настроить правила пересылки iptables, которые выдерживают процесс docker и перезапуск хоста.

Спасибо!

Две вещи, которые следует иметь в виду при работе с правилами брандмауэра docker:

  1. Чтобы избежать того, чтобы ваши правила были заблокированы docker, используйте DOCKER-USER цепь
  2. Docker выполняет сопоставление портов в PREROUTING цепочка из nat стол. Это происходит до того, как filter правила, так что --dest и --dport будет отображаться внутренний IP-адрес и порт контейнера. Чтобы получить доступ к исходному пункту назначения, вы можете использовать -m conntrack --ctorigdstport.

Например:

iptables -A DOCKER-USER -i eth0 -s 8.8.8.8 -p tcp -m conntrack --ctorigdstport 3306 --ctdir ORIGINAL -j ACCEPTiptables -A DOCKER-USER -i eth0 -s 4.4.4.4 -p tcp -m conntrack --ctorigdstport 3306 --ctdir ORIGINAL -j ACCEPTiptables -A DOCKER-USER -i eth0 -p tcp -m conntrack --ctorigdstport 3306 --ctdir ORIGINAL -j DROP

ПРИМЕЧАНИЕ: Без --ctdir ORIGINAL, это также соответствовало бы ответным пакетам, возвращающимся для подключения из контейнера к порту 3306 на каком-либо другом сервере, что почти наверняка не то, что вы хотите! Вам это строго не нужно, если, как и я, ваше первое правило таково -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT, так как это будет иметь дело со всеми ответными пакетами, но было бы безопаснее по-прежнему использовать --ctdir ORIGINAL в любом случае.

С Docker v.17.06 появилась новая цепочка iptables под названием DOCKER-USER. Это для ваших пользовательских правил: https://docs.docker.com/network/iptables/

В отличие от chain DOCKER, он не сбрасывается при сборке / запуске контейнеров. Таким образом, вы могли бы добавить эти строки в свой iptables config / script для подготовки сервера еще до установки docker и запуска контейнеров:

-N DOCKER-N DOCKER-ISOLATION-N DOCKER-USER-A DOCKER-ISOLATION -j RETURN-A DOCKER-USER -i eth0 -p tcp -m tcp --dport 3306 -j DROP-A DOCKER-USER -j RETURN

Теперь порт для MySQL заблокирован от внешнего доступа (eth0), даже если docker открывает порт для всего мира. (Эти правила предполагают, что ваш внешний интерфейс - eth0.)

В конце концов, вам придется сначала очистить iptables и перезапустить службу docker, если вы слишком сильно испортили ее, пытаясь заблокировать порт, как это сделал я.

ОБНОВЛЕНИЕ: Хотя этот ответ все еще действителен, ответ @SystemParadox, использующий DOCKER-USER в сочетании с --ctorigdstport это лучше.

Вот решение, которое хорошо сохраняется между перезапусками и позволяет вам влиять на подвергнутый порт, а не внутренний порт.

iptables -t mangle -N DOCKER-mysqliptables -t mangle -A DOCKER-mysql -s 22.33.44.144/32 -j RETURNiptables -t mangle -A DOCKER-mysql -s 22.33.44.233/32 -j RETURNiptables -t mangle -A DOCKER-mysql -j DROPiptables -t mangle -A PREROUTING -i eth0 -p tcp -m tcp --dport 3306 -j DOCKER-mysql

Я создал образ Docker, который использует этот метод для автоматического управления iptables для вас, используя либо переменные среды, либо динамически с помощью etcd (или и то, и другое).:

https://hub.docker.com/r/colinmollenhour/confd-firewall/

ОБНОВЛЕНИЕ: Хотя это решение действительно в 2015 году, оно больше не является правильным способом сделать это.

Ответ, похоже, содержится в документации Docker по адресу https://docs.docker.com/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

То, что я в итоге сделал, было:

iptables -I DOCKER -i eth0 -s 8.8.8.8 -p tcp --dport 3306 -j ACCEPTiptables -I DOCKER -i eth0 -s 4.4.4.4 -p tcp --dport 3306 -j ACCEPTiptables -I DOCKER 3 -i eth0 -p tcp --dport 3306 -j DROP

Я не прикасался к --iptables или --icc опции.