Назад | Перейти на главную страницу

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

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

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

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

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

Спасибо!

При работе с правилами брандмауэра Docker следует учитывать две вещи:

  1. Чтобы избежать нарушения ваших правил докером, используйте 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 ACCEPT
iptables -A DOCKER-USER -i eth0 -s 4.4.4.4 -p tcp -m conntrack --ctorigdstport 3306 --ctdir ORIGINAL -j ACCEPT
iptables -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/

В отличие от цепного ДОКЕРА, он не сбрасывается при постройке / запуске контейнеров. Таким образом, вы можете добавить эти строки в конфигурацию / скрипт iptables для подготовки сервера еще до установки докера и запуска контейнеров:

-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), даже если докер открывает порт для всего мира. (Эти правила предполагают, что ваш внешний интерфейс - eth0.)

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

ОБНОВИТЬ: Хотя этот ответ все еще действителен, ответ @SystemParadox с использованием DOCKER-USER в комбинации с --ctorigdstport лучше.

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

iptables -t mangle -N DOCKER-mysql
iptables -t mangle -A DOCKER-mysql -s 22.33.44.144/32 -j RETURN
iptables -t mangle -A DOCKER-mysql -s 22.33.44.233/32 -j RETURN
iptables -t mangle -A DOCKER-mysql -j DROP
iptables -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 ACCEPT
iptables -I DOCKER -i eth0 -s 4.4.4.4 -p tcp --dport 3306 -j ACCEPT
iptables -I DOCKER 3 -i eth0 -p tcp --dport 3306 -j DROP

Я не трогал --iptables или --icc параметры.