Моя цель - ограничить доступ к контейнерам 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:
- Чтобы избежать того, чтобы ваши правила были заблокированы docker, используйте
DOCKER-USER
цепь
- 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
опции.