August 7, 2022

Решение вопроса с обходом запрещающих правил фаервола в Docker

Проблема:

При включенном фаерволе (iptables), настроенном на полный запрет входящего трафика, любой docker контейнер с опубликованными портами становится открытым для доступа из интернета, это обусловлено правилами iptables которые добавляет сам docker автоматически при установке.

Решение проблемы:

Установить скрипт, который добавляет необходимые правила в iptables которые по умолчанию запрещают доступ ко всем контейнерам со стороны интернета (доступ из диапазонов локальных сетей сохраняется). В дальнейшем если для какого-то docker контейнера нужно разрешить входящий трафик из интернета необходимо вместо стандартного iptables менеджера ufw использовать скрипт ufw-docker.

Установка ufw-docker:

Скачиваем файл скрипта и сохраняем его в /usr/local/bin/ufw-docker

sudo wget -O /usr/local/bin/ufw-docker https://github.com/chaifeng/ufw-docker/raw/master/ufw-docker

Меняем файлу скрипта разрешение на запуск

sudo chmod +x /usr/local/bin/ufw-docker

Выполняем установку необходимых для ufw-docker правил (добавляет пачку правил в /etc/ufw/after.rules)

sudo ufw-docker install

Перезагрузить фаервол чтобы изменения вступили в силу

systemctl restart ufw

Работа с ufw-docker:

Общий синтаксис ufw-docker:

ufw-docker <list|allow> [docker-instance-id-or-name [port[/tcp|/udp]] [network]]
ufw-docker delete allow [docker-instance-id-or-name [port[/tcp|/udp]] [network]]

Примеры:

Чтобы разрешить доступ из интернета к TCP порту 8080 контейнера с названием test_container (вместо имени можно указывать ID контейнера):

ufw-docker allow test_container 8080/tcp

Чтобы удалить правило:

ufw-docker delete allow test_container 8080/tcp

Чтобы разрешить доступ из интернета ко всем опубликованным портам контейнера c названием test_container:

ufw-docker allow test_container

Просмотр всех правил для контейнера test_container:

ufw-docker list test_container

Чтобы удалить все правила для контейнера test_container:

ufw-docker delete allow test_container

Просмотр всех правил созданных с помощью ufw-docker:

ufw-docker status

Важное примечание:

Номера портов, используемые с ufw-docker необходимо указывать именно те, которые внутри контейнера, а не те которые им сопоставлены в хостовой системе.

Eсли запустить контейнер с указанием публикации портов (параметр -p) таки образом:

docker run -p 88:8080

Сервис, работающий внутри контейнера на порту 8080 будет доступен в хостовой системе на порту 88. Чтобы разрешить доступ к такому сервису из интернета с помощью ufw-docker необходимо указывать порт 8080, т.е. именно тот, на котором работает сервис внутри контейнера.

ufw-docker allow test_container 8080

Важное примечание 2:

ufw-docker это просто удобное дополнение которое позволяет добавлять правила на основании имени контейнера в стандартный ufw. При этом если посмотреть ufw status, можно увидеть что эти правила создаются для внутренних ip адресов контейнеров, соответственно если удалить контейнер и создать его снова, есть вероятность что его ip адрес поменяется, соответственно старое разрешающее правило уже не будет работать. Рекомендую после пересоздания контейнера еще раз разрешать необходимые порты с помощью ufw-docker, при этом он автоматически удалит старые неактуальные.

Альтернативный способ запрета доступа из интернета

В случае если вам нужно закрыть доступ к контейнеру из интернета полностью, можно не публиковать порты вовсе, например если доступ из интернета организован с помощью reverse proxy работающем в другом контейнере.

Также можно публиковать порты с привязкой к localhost интерфейсу, в таком случае доступ из интернета будет закрыт, но будет доступен локально, например с RPC или API сервисами ноды можно будет взаимодействовать локально с помощью curl.

Так выглядит параметр -p при стандартной публикации порта с привязкой ко всем интерфейсам в системе:

-p 1317:1317

А так доступ будет только локально:

-p 127.0.0.1:1317:1317

Проверка доступности портов https://portchecker.co/

Полная инструкция по ufw-docker:

https://github.com/chaifeng/ufw-docker