Есть в линуксе такой очень тёплый и очень ламповый файервол — iptables.
Присутствует он там уже 20 с лишним лет, и чаще всего используется либо в настройках по умолчанию, либо для классической раздачи инета через шлюзовой сервер посредством NAT/MASQUERADE. Иногда про него вспоминают, если поднятый сервис после старта оказался не доступен из инета =)
Однако есть у него и ряд совершенно чумовых возможностей. В одной заметке нереально уместить всё обилие фич и сценариев использования, появившихся за двадцатилетнюю историю, я же опишу лишь две из них.
IPSET.
Офигенная штука, когда надо работать с крупными списками адресов или список адресов должен быть использован более одного раза.
Пример — есть у нас список IP адресов (ркн, телеметрия майкрософт, копирасты, спамеры и прочие злыдни), с которыми соединяться не нужно даже случайно ни на вход, ни на выход. Список при этом может часто меняться. Размещать всю эту муру в основном конфиге файервола — сложно, неудобно и чревато поломкой сети в случае ошибки.
Что мы делаем ? Ставим пакет ipset, и пишем простейший скрипт типа такого:
#!/bin/sh
ipset -N banlist iphash
ipset -F banlist
# Spam bots
ipset -A banlist 92.127.233.224
ipset -A banlist 208.103.122.165
...
ipset -A banlist 95.101.95.129/25
А в начало конфига файервола пишем вот такое:
-A INPUT -m set --set banlist src -j DROP
-A OUTPUT -m set --set banlist dst -j DROP
Всё, любой входящий траффик с этих адресов и исходящий на них же будет дропаться с регистрацией в соответствующих счётчиках (iptables —list -vn). Важных замечаний ровно два. Первое — ипсеты использует такая лютая надстройка, как firewalld. Мне не очень нравится его развесистая лапша из таблиц, пытающаяся описать все распространённые случаи. Надо внимательно смотреть, что ипсеты правильно применились. Зато он полностью сам рулит ипсетами, правилами, последовательностью запуска и прочим. Но конфиг на выходе — в три экрана. Впрочем, ничто не мешает снести надстройку и написать свой конфиг файервола со скриптами, сетами и логгерами.
Второе — сеты должны быть созданы ДО запуска файервола. Как именно вы это сделаете — через юниты systemd, скриптами из rc.local или ещё как — не суть. Главное — конфиг с -m set сработает только тогда, когда используемый ipset будет создан (вполне может быть и пустым).
Очень полезная особенность — правка ipset-ов не рестартит файервол, не сбрасывает его счётчики, не трогает никакие другие правила, к ipset-у не относящиеся. В простых конфигах ipset может показаться лишней сущностью. Но для систем типа fail2ban или случая развесистых списков адресов для правил — вещь незаменимая.
-m owner
Ещё одна редко используемая, но тоже в ряде случаев полезная опция.
Идея в том, что ядро системы знает, какой исходящий траффик процессом какого пользователя порожден, и может на основании этого применить специфичную обработку траффика.
Вспомнил я про это, когда один из моих знакомых спросил, можно ли запустить некое виндовс-приложение в WINE так, чтобы он не могло вылезти в сеть.
В этом случае самое очевидное, и при этом весьма надёжное — отдельная виртуальная машина. Но это а) куда менее удобно б) требует ещё один инстанс ОС.
Однако есть и готовое решение, изумительно простое в своей изящности. Оно не столь надёжно, как изолированная ВМ без сетевой карты, но поставленную задачу тоже решает.
Идея в том, что iptables для исходящего траффика может различать траффик не только по пользователю, но и по его группе и даже по SELinux-контексту. Возня с отдельными пользователями под каждую софтину — неудобна и проблемна из-за прав доступа и вопросов доступа к X-серверу, SELinux сам по себе та ещё черная магия, а вот доступ на основе группы — это то, что доктор прописал.
Базовый ман для убунты на английскои тут: https://askubuntu.com/questions/249826/how-to-disable-internet-connection-for-a-single-process/393013#393013
Для редхатных чуть иначе.
Сперва создаем группу, которую будем назначать тем, кому надо ограничить сетевые аппетиты:
groupadd no-internet
Дальше делаем нашего пользователя членом этой группы:
usermod -G no-internet UserVasya
ВАЖНО !! Опция -G — заглавной буквой ! То есть мы добавляем пользователя UserVasya в группу no-internet, но ОСНОВНУЮ группу пользователя не меняем ! Если перепутать — пользователь останется с отломанным инетом.
В файлах это будет выглядеть вот так:
# cat /etc/group | grep UserVasya
UserVasya:x:1000:
no-internet:x:1011:UserVasya
# cat /etc/passwd | grep UserVasya
UserVasya:x:1000:1000:UserVasya:/home/UserVasya:/bin/bash
Тут у нас есть пользователь UserVasya c UID = 1000, его основная группа — тоже UserVasya, с GID = 1000. Но он также входит в группу no-internet c GID = 1011. Именно это членство позволит пользователю менять группу без ухищрений с судо и запросов паролей.
Теперь напишем сетевое правило для этой группы где-нибудь в начале фильтров для OUTPUT:
-A OUTPUT -m owner --gid-owner no-internet -j DROP
Тут мы говорим файерволу, что траффик, порожденный процессами c группой no-internet, надо тихо дропнуть.
А дальше мы просто воспользуемся утилитой sg (substitute group).
Примеры волшебных команд:
sg no-internet quake2
sg no-internet konsole
sg no-internet ~/.wine_radmin/radmin.sh
env WINEPREFIX=/home/user/.wine_ut2004 sg no-internet 'wine "C:\UT2004\System\UT2004.exe"'
При их выполнении приложения запустятся, но попытка зайти на игровые сервера, соединиться с серверами radmin или пропинговать что-то в запущенной таким способом консоли — завершится неудачей.
Однако это не является 100% способом !
Например, запущенный таким образом firefox группу не меняет, и остается с сетевым доступом !
Так что реально критичным сервисам — своя ВМ, со своим файерволом.
В следующий раз попрактикуемся в ч0рной магии.