Моя цель - ограничить доступ к контейнерам докеров всего несколькими общедоступными IP-адресами. Есть ли простой, повторяемый процесс для достижения моей цели? Понимая только основы iptables при использовании параметров Docker по умолчанию, мне это очень сложно.
Я хотел бы запустить контейнер, сделать его видимым для общедоступного Интернета, но разрешить соединения только с выбранных хостов. Я бы ожидал установить политику INPUT по умолчанию REJECT, а затем разрешать соединения только с моих хостов. Но правила и цепочки Docker NAT мешают, а мои правила INPUT игнорируются.
Может ли кто-нибудь привести пример того, как достичь моей цели при следующих предположениях?
docker run -d -p 3306:3306 mysql
Я счастлив привязать контейнер только к локальному IP-адресу, но мне потребуются инструкции о том, как правильно настроить правила пересылки iptables, которые выдерживают перезапуск процесса докера и хоста.
Спасибо!
При работе с правилами брандмауэра Docker следует учитывать две вещи:
DOCKER-USER
цепь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 (или и то, и другое):
ОБНОВИТЬ: Хотя это решение действовало в 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
параметры.