Описание проблемы
При настройке 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.
Последнее изменение: 20.09.2024 15:57