Описание проблемы

При настройке ufw в Unix системах может возникнуть ситуация, при которой Docker контейнеры не соблюдают правила файрволла.

Так, например, при разрешенных портах файрволла ufw 80, 443 и 22

# 80, 443
sudo ufw allow 'Nginx Full'
# 22
sudo ufw allow OpenSSH
 
sudo ufw enable

контейнер с проброшенными портами 8000:80 (8000 - хост, 80 - контейнер) может быть доступен из вне с порта 8000 хоста, игнорируя правила файрволла.

Решение

Для решения данной проблемы необходимо изменить файл конфигурации UFW etc/ufw/after.rules, добавив следующий листинг в конец файла.

#BEGIN UFW AND DOCKER
*filter
:ufw-user-forward - [0:0]
:DOCKER-USER - [0:0]
-A DOCKER-USER -j RETURN -s 10.0.0.0/8
-A DOCKER-USER -j RETURN -s 172.16.0.0/12
-A DOCKER-USER -j RETURN -s 192.168.0.0/16
 
-A DOCKER-USER -j ufw-user-forward
 
-A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 192.168.0.0/16
-A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 10.0.0.0/8
-A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 172.16.0.0/12
-A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 192.168.0.0/16
-A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 10.0.0.0/8
-A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 172.16.0.0/12
 
-A DOCKER-USER -j RETURN
COMMIT
# END UFW AND DOCKER

Далее, используя команду

sudo systemctl restart ufw

перезапустить UFW. Теперь нельзя будет обратиться к открытым портам Docker контейнера из вне, при этом контейнеры могут “общаться” между собой и также имеют доступ ко внешней сети.

Дополнительные настройки

Если необходимо разрешить публичным сетям доступ к контейнеру Docker, например, через его порт 80, выполните следующую команду, чтобы разрешить публичным сетям доступ к этому контейнеру:

fw route allow proto tcp from any to any port 80

Эта команда позволяет публичным сетям получить доступ ко всем контейнером с портом 80.

Примечание: Следует использовать именно порт контейнера 80, а не порт хоста 8000, если порты проброшены следующим образом:

ports:
	- "HOST_PORT:CONTAINER_PORT:
	- "8000: 80"

Если необходимо запущено несколько Docker контейнеров с портом 80, но доступ из вне необходимо дать только одному определенному, выполните следующую команду:

ufw route allow proto tcp from any to 172.17.0.2 port 80

172.17.0.2 - внутренний IP адрес контейнера.

Также, если прокол сети - UDP, например, DNS сервис, можно использовать аналогичные команды:

ufw route allow proto udp from any to any port 53

И для определенного контейнера с внутренним IP адресом 172.17.0.2 :

ufw route allow proto udp from any to 172.17.0.2 port 53

Как это работает

Следующие правила позволяют частным сетям обращаться друг к другу.

-A DOCKER-USER -j RETURN -s 10.0.0.0/8
-A DOCKER-USER -j RETURN -s 172.16.0.0/12
-A DOCKER-USER -j RETURN -s 192.168.0.0/16

Следующие правила позволяют UFW управлять тем, разрешено ли публичным сетям обращаться к контейнерам Docker.

-A DOCKER-USER -j ufw-user-forwar

Следующие правила блокируют запросы на подключение, инициированные всеми публичными сетями, но позволяют внутренним сетям получать доступ к внешним сетям.

-A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 192.168.0.0/16
-A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 10.0.0.0/8
-A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 172.16.0.0/12
-A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 192.168.0.0/16
-A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 10.0.0.0/8
-A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 172.16.0.0/12
 
-A DOCKER-USER -j RETURN

Для протокола TCP запрещается активное установление TCP-соединения из публичных сетей.

Для протокола UDP блокируются все обращения к портам с номером меньше 32767.

Почему выбирается именно этот порт? Поскольку протокол UDP не имеет состояния, невозможно заблокировать handshake, инициирующий запрос соединения, как это делает TCP. Для GNU/Linux мы можем найти локальный диапазон портов в файле /proc/sys/net/ipv4/ip_local_port_range. По умолчанию диапазон составляет 32768: 60999. При обращении к протоколу UDP из запущенного контейнера локальный порт будет выбран случайным образом из указанного выше диапазона портов, и сервер вернет данные на этот случайный порт. Таким образом, можно предположить, что порты, которые “слушают” протокол UDP внутри всех контейнеров меньше 32768. Именно по этой причине блокируются обращения публичных сетей к UDP-портам, которые меньше 32768.

Источник


📂 Yandex Cloud

Последнее изменение: 20.09.2024 15:57