Недавно я настраивала сервер, на котором запускается Elasticsearch в докере.
Обращения к контейнеру предусмотрены только в пределах сервера по 9200 порту. Доступ к этому порту извне нужно было закрыть. И эта несложная, вроде бы, операция, сделала мой день. Вроде как закрытый через iptables порт оставался открытым во что бы то ни стало. В результате довольно продолжительного гугления я нашла статью другого человека, столкнувшегося с точно такой же проблемой.
https://www.jeffgeerling.com/blog/2020/be-careful-docker-might-be-exposing-ports-world
Перевод этой статьи и предлагаю вашему вниманию.
На днях я заметил странные записи в логах одного из моих веб сервисов, как будто кто-то пытается обратиться к эндпоинту моего приложения. Я удивился, так как все эндпоинты, открытые во внешний интернет, закрыты либо паролем, либо по IP. Так я думал.
За последний год я переписал этот сервис под docker. Вместо стандартного одного сервера на процесс, теперь я запускаю группу процессов на одном сервере, каждый процесс в своем docker-контейнере, и распределяю трафик между процессами по именам поддоменов. В качестве прокси-сервера — nginx.
На сервере я сделал фаерволл на основе iptables. Запуск происходит через Docker Compose, все процессы запускаются в контейнерах, каждый на отдельном порту, типа 1234, 1235, и т.д.
Объявление порта для сервиса выглядит так:
version'3.7'
services
process_1234
ports
"127.0.0.1:1234:1234"
Nginx проксирует трафик с поддомена типа service-1234.example.com (на 443 порту) на приложение в докере, которе висит на 1234 порту, service-1235.example.com — на 1235 порт, и т.д.
Я думал, что объявление порта «127.0.0.1:1234:1234» будет открывать порт только на локальный хост, в соотвествии с документацией.
В большинстве случаев, схема работает, как ожидалось.
Вот скрипт для проверки:
https://gist.github.com/geerlingguy/3dabf0ec3befb8c49bbed0ec7cd3d44c
Но в моем случае, похоже, некоторые правила iptables конфиликруют с правилами докера, и правила iptables докера открывают порты во внешнюю сеть.
Я стал думать (и гуглить), как же так получилось, что, несмотря на то, что порт вроде бы закрыт, внешние запросы к server-ip:1234 проходят, и нашел другие свидетельства той же проблемы.
В моем случае, помогло добавить новое правило к цепочке DOCKER-USER:
iptables -I DOCKER-USER -i eth0 ! -s 127.0.0.1 -j DROP
Это правило, в соответствии с документацией, ограничивает весь трафик с интерфейса eth0, кроме исходящего от localhost. Это сработало для меня, но мне не нужно расшаривать контейнеры докера в сеть. Если вам нужно получить микс контейнеров, открытых в сеть, и других сервисов, установленных прямо на сервере, этот фикс не сработает.
После внесения изменений, можно проверить, что они применились:
$ sudo iptables -L
…
Chain DOCKER-USER (1 references)
target prot opt source destination
DROP all -- !localhost anywhere
RETURN all -- anywhere anywhere
Для стопроцентной уверенности, что фаерволл сработал, можно поискать открытые порты (-p- значит «сканировать все порты, 1-65535»), используя nmap:
$ sudo nmap -p- [server-ip-address]
Вот так! Мне, кстати, тоже помогло это решение. Будьте внимательны и осторожны с докером!