Firewall с Docker на сервере
В этом небольшом гайдике расскажу, как я защитил свои машины поверх Firewall на сети, с какими трудностями я столкнулся.
Реализация
Идею взял отсюда: https://github.com/chaifeng/ufw-docker
Я решил пойти по пути наимельшего сопротивления: ufw
1
2
3
apt update && apt install ufw -y
ufw allow ssh # Желательно ограничить ssh до вашего vpn туннеля
ufw enable
К сожалению, docker самостоятельно переписывает (ip/nf)tables правила, поэтому нам нужно изменить конфигузацию ufw.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
cp /etc/ufw/after.rules /etc/ufw/after.rules.bak # backup старых правил
cat > /etc/ufw/after.rules<<EOF
#
# rules.input-after
#
# Rules that should be run after the ufw command line added rules. Custom
# rules should be added to one of these chains:
# ufw-after-input
# ufw-after-output
# ufw-after-forward
#
# Don't delete these required lines, otherwise there will be errors
*filter
:ufw-after-input - [0:0]
:ufw-after-output - [0:0]
:ufw-after-forward - [0:0]
:DOCKER-USER - [0:0]
:ufw-user-forward - [0:0]
# End required lines
# don't log noisy services by default
-A ufw-after-input -p udp --dport 137 -j ufw-skip-to-policy-input
-A ufw-after-input -p udp --dport 138 -j ufw-skip-to-policy-input
-A ufw-after-input -p tcp --dport 139 -j ufw-skip-to-policy-input
-A ufw-after-input -p tcp --dport 445 -j ufw-skip-to-policy-input
-A ufw-after-input -p udp --dport 67 -j ufw-skip-to-policy-input
-A ufw-after-input -p udp --dport 68 -j ufw-skip-to-policy-input
# don't log noisy broadcast
-A ufw-after-input -m addrtype --dst-type BROADCAST -j ufw-skip-to-policy-input
-A DOCKER-USER -j ufw-user-forward
-A DOCKER-USER -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
-A DOCKER-USER -m conntrack --ctstate INVALID -j DROP
-A DOCKER-USER -i eth0 -j DROP
# don't delete the 'COMMIT' line or these rules won't be processed
COMMIT
EOF
Теперь чтобы разрешить доступ к нашему контейнеру просто просываем, например
Обратите внимание, что порт указывается внутренний контейнера, изменить его у меня не получалось
1
2
3
ufw route allow from 192.168.x.x to any port 2283 proto tcp
ufw route allow from 192.168.x.x to any port 443
ufw route allow 80/tcp
Применяем изменения
1
ufw reload
На этом гайд заканчивается, дальше расскажу что я пытался делать
Боль, с которой я столкнулся
Всё, что тут находится не рекоммендуется к использованию
Проблемы с ufw
Изначально я решил выбрать ufw, из-за его простого синтаксиса, но сразу после написания всех правил, оказалось, что docker’у вообще по барабану наши правила, он слушал на всем интерфейсе. Даже тогда, когда я указал его подсеть в docker-compose.yaml секции ports, ничего не менялось. А самое печальное, что я это заметил только спустя несколько месяцев после установки, когда мне рассказал мой хороший товарищ о своей реализации firewall на голом nftables. (( Рома, привет! )) Ведь часть сервисов реально блокировалось: samba, ssh, apt-cacher-ng, т.к. они были запущены просто на lxc без docker.
Костыль в виде firewalld
Затем я увидел на
Отключение изменение iptables docker’ом
Это реально помогло на многих моих машинах, но вот несколько контейнеров отказались работать в таком режиме, из-за чего мне пришлось искать замену этому способу.
Возвращение к ufw и проблемы с iptables
Я пришел к этой конфигурации
1
2
3
sudo iptables -I DOCKER-USER 1 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
sudo iptables -I DOCKER-USER 2 -p tcp --dport 2283 -s 192.168.x.x -j ACCEPT
sudo iptables -A DOCKER-USER -i eth0 -j DROP
С последней строчкой у меня было много казусов: в iptables важен порядок правил, но я почему-то решил разместить ее первой – сломал весь docker. При этом chatGPT постоянно предлагал этот вариант, но без -i eth0, что ломало сервисы, состоящих из нескольких контейнеров. Дальше я обнаружил на забытом https://stackoverflow.com ответ от 2018 года, а затем и нашел описанный в моем гайде способ, который я модифицировал под свои нужды
Небольшой комментарий
iptables под своим капотом на современном ядре Linux уже имеет nftables, поэтому правила писал под них