Короткий ответ
Egress filtering — контроль исходящих new-сессий с серверов (и по возможности с пользователей), а не только inbound на WAN 203.0.113.10. Цель: сервер в 10.0.10.0/24 или DMZ 10.0.30.0/24 не открывает произвольный tcp к интернету. Разрешите DNS, NTP, HTTP/HTTPS к репозиториям, SMTP с почтового, VPN куда надо. Запретите исходящие 445, 3389, SMB, случайные высокие порты для C2. Соберите потоки, затем drop. Не policy accept, не отключение фильтра «чтобы apt заработал».
Пользовательский VLAN часто шире (HTTPS anywhere). Серверный VLAN — узкий allow-list. Если серверы в том же VLAN, что ПК — сначала сегментация.
Симптомы и как отличить
С app01 (10.0.10.20) curl https://93.184.216.34:4444 или nc на произвольный порт проходит. В filter нет drop для oif WAN с src серверов. Conntrack полон сессий на странные dst-port.
| Источник | Норма исходящего | Тревога |
|---|---|---|
ПК 10.0.10.50 | 80/443, DNS | 445 на интернет |
| App-сервер | 443 к vendor update, DNS, NTP | any tcp |
| DMZ web | 443 к API, DNS | DMZ→LAN any, 25 на всех |
| DC | почти ничего в интернет | Windows Update через WSUS |
Это не «нет NAT»: NAT есть, фильтра нет. Не путать с inbound any-any — см. any-any.
Возможные причины
- Forward policy accept «как домашний роутер».
- Allow LAN→WAN без dst-port.
- Облако: NSG inbound закрыт, outbound 0.0.0.0/0 открыт.
- Dual-homed сервер мимо шлюза (свой белый).
- IPv6 egress не фильтруется.
- Прокси есть, но хосты ходят bypass.
Диагностика
1. Есть ли вообще исходящий контроль
sudo nft list ruleset | grep -n -A2 'hook forward'/ip firewall filter print where chain=forward and out-interface-list=WANЕсли единственное — masquerade в nat и accept forward — egress нет.
2. Что серверы уже открывают
На шлюзе, час-два рабочего времени:
sudo conntrack -L | awk '/10.0.10.20/ {print}' | headRouterOS: /ip firewall connection print where src-address~"10.0.10.2"
Снимите топ dst-port. Это черновик allow-list.
Временный log исходящих new с серверного диапазона (не с всего LAN, если там пользователи):
sudo nft add rule inet filter forward ip saddr 10.0.10.20 oifname "ens18" ct state new \
counter log prefix "EGRESS-APP01 " limit rate 5/second3. Обход шлюза
ip route
# на сервере: default через 10.0.10.1?Второй NIC с белым — пакеты не попадут в ваш forward. Фильтр на хосте + уберите белый.
4. Концепция pf
LAN/SERVERS interface: out to WAN default deny + pass на 53, 443, 80, 123. Не pass any out.
Сверьте матрицу исходящих — отдельная колонка в документе портов.
Решение
Целевой allow-list для app-сервера (пример, не догма):
- UDP/TCP 53 к внутреннему резолверу
10.0.10.10, не к 8.8.8.8 с каждого хоста (или к выбранному DNS). - UDP 123 к NTP.
- TCP 443 (и при необходимости 80) к списку update (или через HTTP proxy).
- TCP 25 только с MX в DMZ наружу.
- Остальное drop + log sample.
Сценарий A. nftables forward
Политика forward drop. Established в начале. Затем узкие allow. Затем:
sudo cp /etc/nftables.conf /root/nftables.conf.bak.egressИдея правил (NIC WAN ens18, сервер 10.0.10.20):
ip saddr 10.0.10.20 ip daddr 10.0.10.10 udp dport 53 accept(и tcp 53)ip saddr 10.0.10.20 udp dport 123 acceptк NTP или внутреннемуip saddr 10.0.10.20 oifname ens18 tcp dport { 80, 443 } accept— временный широкий HTTPS, потом сузить по dstip saddr 10.0.10.20 oifname ens18 tcp dport { 445, 3389, 135, 139, 25 } dropip saddr 10.0.10.20 oifname ens18 counter log prefix "EGRESS-DENY " drop
sudo nft -c -f /etc/nftables.conf
sudo systemctl reload nftablesСначала поставьте drop только известных опасных портов, понаблюдайте log, затем default deny outbound для серверного VLAN.
Сценарий B. RouterOS 7
/ip firewall address-list add list=servers address=10.0.10.20 comment=app01
/ip firewall filter add chain=forward action=accept connection-state=established,related place-before=0
/ip firewall filter add chain=forward src-address-list=servers dst-address=10.0.10.10 protocol=udp dst-port=53 action=accept
/ip firewall filter add chain=forward src-address-list=servers out-interface-list=WAN protocol=tcp dst-port=80,443 action=accept comment="updates HTTPS"
/ip firewall filter add chain=forward src-address-list=servers out-interface-list=WAN protocol=tcp dst-port=445,3389,25 action=drop comment="no smb/rdp/smtp out"
/ip firewall filter add chain=forward src-address-list=servers out-interface-list=WAN connection-state=new action=drop comment="egress default deny servers"Пользователей 10.0.10.0/24 минус servers пока не трогайте тем же drop, иначе «интернет офиса лёг». Лучше вынести серверы в отдельную сеть.
Сценарий C. Обновления сломались
Не возвращайте any. Смотрите log EGRESS-DENY: dst и порт. Добавьте dst в address-list updates (репозитории Ubuntu, WSUS, vendor CDN). Для apt:
# на app01 после фильтра: что не прошло
sudo apt-get updateЕсли timeout — на шлюзе prefix deny. Разрешите этот dst:443. Не 0.0.0.0/0.
Сценарий D. Хостовый nft как второй слой
На самом сервере Ubuntu default deny outgoing кроме нужного — defense in depth. Не заменяет периметр.
Откат: файл bak, RouterOS enable старого accept. Firewall не stop.
Связка с DMZ: исходящие из DMZ ещё строже (обычно только 80/443/25/53).
Как проверить, что проблема устранена
С app01:
curl -I --connect-timeout 5 https://archive.ubuntu.com
nc -zv -w 3 203.0.113.10 445 || true
# 445 наружу должен fail; не сканируйте чужие сети — проверяйте drop локально:
# попытка к документированному внешнему IP организации или к TEST-NET, который не маршрутизируетсяПрактический негативный тест без скана чужих: на шлюзе счётчик drop 445/3389 растёт при nc на ваш unused белый или на адрес из RFC 5737, если маршрут туда идёт в WAN (иначе будет network unreachable — тоже ок vs accept).
Позитив: DNS резолвится, NTP, HTTPS к update. Пользовательский ПК без серверного list — браузер жив.
Если не помогло
- Мониторинг (ICMP/443 к 8.8.8.8) — внесите или смените на внутренние probe.
- SMTP с app-сервера — пусть идёт через внутренний MX, не напрямую.
- Docker
0.0.0.0и SNAT минуя правила — правьте docker/forward. - NTP на 123 блокируется как «редко» — верните 123, не any.
- IPv6 AAAA обход — table inet/ip6.
Профилактика
- Серверный VLAN + default deny egress.
- HTTP proxy для обновлений — один исходящий 443 с proxy, не с каждого host any.
- Алерт на new с серверов на порты вне матрицы.
- Запрет dual-homed app-серверов.
- Ревизия address-list servers при вводе VM.
FAQ
Пользователям тоже deny egress?
Поэтапно: сначала серверы. Пользователям минимум запретите 25/445/137-139 исходящие на WAN (spam/worm). Полный allow-list браузера — тяжелее.
Разрешить 443 anywhere с серверов достаточно?
Лучше, чем any tcp, хуже allow-list dst. C2 часто 443. Следующий шаг — proxy + SNI/dst list.
Куда деть GitHub/Docker Hub?
Address-list или proxy. Не any. Списки меняются — владелец сервиса обновляет list.
ICMP исходящий
Echo к мониторингу можно точечно. Не any proto.
Это сломает Let's Encrypt с web в DMZ?
ACME — исходящий 443 к CA плюс входящий 80/443 по матрице. Внесите CA в egress DMZ, не открывайте any.