
Не удивительно, но Docker не работает из коробки с “Universal Firewall” Linux, или UFW. И для того чтобы UFW корректно управлял доступом к портам контейнеров, необходимо отключить прямое управление iptables в конфигурации самого Docker, а затем разрешить необходимые порты в конфигурации UFW.
Почему Docker не работает с UFW напрямую?
UFW задуман как очень простой брандмауэр.
Конфликт в том, что UFW и Docker работают по своим сценариям и пытаются изменить одни и те же базовые правила брандмауэра, и этот конфликт требует дополнительной перенастройки, если вы хотите использовать UFW и Docker эффективно в связке друг с другом.
Если вы настроите базовый брандмауэр UFW на запрет по умолчанию и разрешить HTTP и SSH соединения несомненно это безопасно, но если не будет блокировать запуск контейнеров Docker, привязанных к другим портам.
Этот косяк сложно отследить и вовремя сообразить за ранее, поскольку UFW и Docker – это отдельные системы.
UFW работает по своему сценарию и не оповещает вас, не показывает явно открытые порты контейнеров Docker.
Это может стать серьезной проблемой в безопасности, если вы сами за ранее не готовы к такому повороту событий.
Например вы хотите запустить дашборд администратора на порту 8000 и внести его в белый список для вашего собственного IP-адреса.
Мы понимаем что это не самый безопасный сценарий и обычно все в порядке, особенно если даш имеет дополнительную аутентификацию.
Тем не менее, UFW покажет правило брандмауэра как правильно внесенное в белый список, и оно, конечно работает для вас так как ip внесен в белый список.
Но если оно запущено через Docker, то по умолчанию оно будет видно на порту 8000 с любого места.
Исправление конфигурации Docker
Рассмотрим сценарий для безопасного решения, которое предлагает Docker: отредактируйте /etc/default/docker или /etc/docker/daemon.json и просто отключите функциональность iptables в Docker:
DOCKER_OPTS="--iptables=false"
Да, не сомневайтесь это будет работать, но не так эффективно и гибко как хотелось бы.
Это лишает Docker возможности управлять собственными сетями и может привести к тому, что контейнеры вообще не смогут получить доступ в интернет из коробки.
Работать конечно будет, но вам придется вручную поддерживать правила iptables для контейнеров Docker и локальной сети, и начнет раздражать.
Реальное решение сложное, но, к счастью, достаточно распространенное, поэтому на Github есть полезная публикация с подробным описанием проблемы и шагов по ее устранению.
По сути все что вам нужно это изменить конфигурацию UFW в /etc/ufw/after.rules и добавить следующий блок правил в конце:
# BEGIN UFW AND DOCKER *filter :ufw-user-forward - [0:0] :ufw-docker-logging-deny - [0:0] :DOCKER-USER - [0:0] -A DOCKER-USER -j ufw-user-forward -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 -p udp -m udp --sport 53 --dport 1024:65535 -j RETURN -A DOCKER-USER -j ufw-docker-logging-deny -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 192.168.0.0/16 -A DOCKER-USER -j ufw-docker-logging-deny -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 10.0.0.0/8 -A DOCKER-USER -j ufw-docker-logging-deny -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 172.16.0.0/12 -A DOCKER-USER -j ufw-docker-logging-deny -p udp -m udp --dport 0:32767 -d 192.168.0.0/16 -A DOCKER-USER -j ufw-docker-logging-deny -p udp -m udp --dport 0:32767 -d 10.0.0.0/8 -A DOCKER-USER -j ufw-docker-logging-deny -p udp -m udp --dport 0:32767 -d 172.16.0.0/12 -A DOCKER-USER -j RETURN -A ufw-docker-logging-deny -m limit --limit 3/min --limit-burst 10 -j LOG --log-prefix "[UFW DOCKER BLOCK] " -A ufw-docker-logging-deny -j DROP COMMIT # END UFW AND 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.
ufw-docker install sudo systemctl restart ufw
После перезапуска изменения должны применяться автоматически, но если они не применяются, вам может потребоваться перезапустить Docker или вашу машину в целом.
После включения все порты должны быть правильно заблокированы.
Белые списки портов контейнеров Docker с помощью UFW
Это решение потребует от вас немного другой конфигурации портов.
В утилите ufw-docker есть команда, которая выборочно вносит порты в белый список для определенных контейнеров Docker.
ufw-docker allow httpd 80
ufw route allow proto tcp from 1.2.3.4 to any port 9443