Docker и файрвол
Порты из docker run -p и compose ports: открыты из интернета даже при ufw deny. Как закрыть: 127.0.0.1, DOCKER-USER, whitelist.
Коротко: порт, опубликованный Docker (-p 5432:5432, ports: ["5432:5432"]), открыт всему интернету, даже если ufw status показывает, что он закрыт.
Проверить свой сервер — анализатор правил (вставьте iptables-save) или снаружи — проверка порта.
Почему так
Пакет к контейнеру идёт не в цепочку INPUT, где живут правила ufw, а через NAT в FORWARD:
интернет → PREROUTING (nat: DOCKER, DNAT 203.0.113.5:5432 → 172.17.0.2:5432)
→ FORWARD → DOCKER-USER → DOCKER-FORWARD / DOCKER → контейнер
(INPUT и ufw этот пакет не видят)
Docker сам добавляет разрешающие правила в FORWARD для каждого опубликованного порта. ufw ничего про них не знает.
Как закрыть — от простого к гибкому
1. Не публиковать наружу. Если к сервису ходит только nginx или другое приложение на этом же сервере:
services:
db:
ports:
- "127.0.0.1:5432:5432" # только с этого сервера
А лучше совсем без ports: — контейнеры в одной сети compose видят друг друга по имени сервиса.
2. Пускать только свои адреса — цепочка DOCKER-USER. Docker её не трогает, и она проверяется раньше его правил:
# пустить 203.0.113.10 к порту 5432 контейнеров, остальным — нет
iptables -I DOCKER-USER -p tcp -m conntrack --ctorigdstport 5432 --ctdir ORIGINAL ! -s 203.0.113.10 -j DROP
--ctorigdstport — порт, на который пришёл клиент (до DNAT). Сохранить: netfilter-persistent save. Правила в DOCKER-USER переживают перезапуск Docker.
3. Закрыть всё опубликованное, кроме нужного:
iptables -I DOCKER-USER -i eth0 -m conntrack --ctstate ESTABLISHED,RELATED -j RETURN
iptables -I DOCKER-USER 2 -i eth0 -p tcp -m conntrack --ctorigdstport 443 --ctdir ORIGINAL -j RETURN
iptables -A DOCKER-USER -i eth0 -j DROP
eth0 — внешний интерфейс (ip route get 1.1.1.1 покажет его имя).
4. Ограничить на уровне приложения. Для веб-сервисов — allow/deny в nginx перед контейнером, для сервисов RunStack — rs <сервис> access "203.0.113.10".
Чего не делать
"iptables": falseв daemon.json — Docker перестанет управлять правилами, и у контейнеров сломается сеть и выход в интернет.- Править цепочки DOCKER и DOCKER-FORWARD руками — Docker перезапишет их при перезапуске.
- Полагаться на
ufw deny 5432— см. выше.
IPv6
Если у сервера есть IPv6 и в Docker включён IPv6, то же самое нужно сделать в ip6tables (DOCKER-USER там своя).
