↓ Перейти к основному содержимому
  1. Posts/
  2. OPNsense/

Как у меня устроен firewall в OPNsense

·1865 слов·9 минут· loading · loading · ·
Stilicho2011
Автор
Stilicho2011
Пишу о homelab, self-hosting, автоматизации и open-source решениях
Оглавление
Работа с Opnsense - This article is part of a series.
Part : This Article

Ранее я уже разбирал одну конкретную часть своего firewall подробно - вынос Traefik в отдельный VLAN, в статье «Traefik в отдельном VLAN: настройка firewall в OPNsense». Но там речь шла только про один сегмент (под условным названием opt6) и про переезд конкретного сервиса. В этой статье я постараюсь рассказать, как у меня устроена сегментация сети целиком: сколько у меня VLAN, зачем каждый из них существует, и какой шаблон правил повторяется в каждом сегменте практически без изменений.

Сколько VLAN и зачем
#

flowchart LR
  WAN["WAN
интернет"] LAN["LAN
основной сегмент"] OPT1["opt1
WIFI"] OPT2["opt2
хосты для
личного использования"] OPT3["opt3
DMZ для
съемок на ютубе"] OPT6["opt6
Traefik + CrowdSec"] WAN -->|"block GEOIP, block Firehol, block CrowdSec"| LAN LAN --- OPT1 LAN --- OPT2 LAN --- OPT3 LAN --- OPT6

Шесть сегментов на сегодняшний день.

Общий принцип правил у всех сегментов следующий, включая opt6 - базовый шаблон (разберу ниже) у всех одинаковый. У каждого сегмента внутри себя и в сторону интернета доступ практически без ограничений (это же все-таки домашняя сеть, а не корпоративный периметр), а вот между сегментами доступ по умолчанию закрыт - перед любым allow-правилом в каждом сегменте стоит блокировка доступа к другим приватным сетям (более подробно ниже), и любое межсегментное взаимодействие описывается отдельным точечным правилом. В opt6 эта логика точечных межсегментных правил просто разрастается сильнее, чем везде - потому что там крутится обратный прокси Traefik и security-стек (ну наверно не стэк, а Crowdsec, но может будет и стэк), а не рабочие станции, и у каждого проксируемого сервиса своя отдельная точка выхода.

Поэтому колонка «Финальное правило» в таблице ниже - это не «что у меня разрешено по умолчанию», а название последнего catch-all правила в цепочке каждого сегмента. То есть то, что остается разрешенным уже после того, как более ранние блокирующие правила отфильтровали межсегментный трафик. Сама по себе фраза «allow to any» в названии правила может сбить с толку - на уровне всей сети эффект противоположный. По умолчанию все закрыто, а открыто - только явно описанное. И я просто не придумал, как это более наглядно отобразить, чтобы не тащить все правила в таблицу.

СегментНазначениеФинальное правило
WANВнешний интерфейсБлокировки GeoIP, FireHOL и CrowdSec, после них проброс 80 и 443 на Traefik - все остальное входящее закрыто
LANОсновной сегмент: рабочие станции, NAS, админский доступDefault allow LAN to any (после блокировки других сегментов)
opt1WIFIDefault allow WIFI to any (после блокировки других сегментов)
opt2Хосты для личного использованияDefault allow to any (после блокировки других сегментов)
opt3DMZDefault allow DMZ to any (после блокировки других сегментов)
opt6Traefik + CrowdSec, отдельный периметр (разбирал здесь)Default allow opt6 to any (после блокировки + 50+ точечных разрешений к проксируемым сервисам)

WAN - что открыто и что отсекается на входе
#

С внешним интерфейсом все устроено заметно проще, чем с внутренними сегментами, но именно здесь стоит первая линия фильтрации, поэтому про него отдельно.

Снаружи у меня открыто ровно два порта - 80 и 443. Оба проброшены через Destination NAT в один-единственный LXC-контейнер с Traefik в сегменте opt6, и больше никуда. Никаких пробросов «на всякий случай» к отдельным сервисам у меня нет. Все, что должно быть доступно из интернета, доступно только через Traefik, а дальше работает уже та схема точечных правил из opt6, которую я разбираю ниже.

Но до этих двух портов трафик еще должен дойти. Выше разрешающих правил на WAN стоят блокирующие, и они отбрасывают заметную часть мусора раньше, чем он вообще увидит Traefik.

flowchart LR
  I["Интернет"] --> B["WAN
block GeoIP
block FireHOL
block CrowdSec"] B -->|"80, 443"| T["Traefik
LXC в opt6"] B -.->|"все остальное"| X["отброшено"]

Блокировок три вида:

  • Блокировка по странам (GeoIP) - алиас типа GeoIP на базе MaxMind. Входящие соединения из стран, откуда я гостей не жду, отбрасываются сразу, до любых других проверок.
  • Блоклисты FireHOL - четыре списка сразу, firehol_level1, firehol_level2, firehol_level3 и firehol_abusers_1d. Это адреса ботнетов, сканеров, серверов управления и прочих узлов, уже замеченных во вредоносной активности. Списки подтягиваются по URL и обновляются по cron раз в сутки.
  • CrowdSec прямо в OPNsense - плагин os-crowdsec. Его Remediation Component сам блокирует на firewall входящие соединения с адресов, по которым у CrowdSec есть решение о бане. В отличие от первых двух пунктов, это не статичный список, который я подключил руками, а постоянно меняющийся набор адресов.

Все три механизма настроены ровно по той схеме, которую я пошагово расписал в статье «OPNsense 26.1: установка и настройка с нуля» - алиасы, исключение локальных сетей из списков FireHOL, блокирующие правила на WAN с направлением in, задание cron на обновление и установка плагина CrowdSec. Там же я советовал большинству начинать с одного firehol_level1, а у себя держу все четыре уровня, включая более агрессивные.

Эти фильтры друг друга не дублируют. GeoIP - грубый инструмент, который режет целые страны независимо от репутации адреса. FireHOL работает точечно и ловит уже засветившиеся адреса, в том числе из тех стран, которые у меня не заблокированы. CrowdSec добавляет к этому адреса, забаненные за конкретное поведение - перебор паролей, сканирование и тому подобное.

Все, что прошло эти фильтры и попало на 80 или 443, дальше встречает Traefik, рядом с которым в opt6 работает еще один CrowdSec (про него есть отдельные статьи - в Docker и в LXC). Он смотрит уже на HTTP-запросы к конкретным сервисам, то есть на то, чего firewall на своем уровне не видит.

И еще одна деталь, которую легко упустить. Правила GeoIP и FireHOL стоят на WAN с направлением in, то есть касаются только входящих соединений. На то, куда мои собственные устройства ходят наружу, они не влияют.

Базовый шаблон, который повторяется в каждом сегменте
#

Практически один в один в lan, opt1, opt2, opt3 и opt6 повторяется одна и та же последовательность правил:

  1. Allow internal DNS - разрешить сегменту достучаться до собственного gateway-IP на порт 53. Без этого правила резолвинг доменов внутри сегмента просто не работает, а все остальное построено на резолвинге доменных имен внутренних сервисов.
  2. VPN-сплит-туннелинг (см. отдельный раздел ниже) - точечная переадресация определенных категорий трафика через VPN gateway.
  3. Block access to all other private networks - блокирует доступ из этого сегмента во все остальные приватные диапазоны (алиас Private_Networks). Это и есть та самая «закрытая по умолчанию» граница между сегментами.
  4. Default allow <сегмент> to any (и его IPv6-версия) - все, что не запрещено явно выше и не идет в другой приватный сегмент, разрешено. У меня домашняя сеть просто так устроена - не нулевое доверие внутри сегмента, а полный контроль на границе между сегментами. Мне кажется, это здоровый баланс для дома.

На lan дополнительно есть:

  • Allow ICMP echo request messages - чтобы обычный ping работал внутри сети, это не включенное по умолчанию, а специально созданное правило;
  • Allow admin devices access to anywhere without any restrictions (алиас admins) - у части устройств (мои личные рабочие машины/устройства) явный полный доступ без ограничений, чтобы не бороться с собственным firewall при диагностике;
  • такое же админское правило продублировано и в opt1.

VPN-сплит-туннелинг PROXYTUN
#

Во всех сегментах (кроме DMZ) есть пара правил policy-based routing с одинаковой структурой: трафик к определенному списку сервисов (алиас вида не скажу, сам догадывайся) заворачивается через отдельный gateway - PROXYTUN - вместо обычного маршрута в интернет.

Смысл всей связки в том, что часть сервисов (условно, зарубежные софтверные ресурсы, базы знаний и видеохостинг) недоступна потому что … потому что (например, геоблок с той стороны, законы РФ мы не нарушаем), и трафик нужно направить через VPN, а весь остальной трафик - идет обычным маршрутом через провайдера. Списки сервисов собраны в алиасы, поэтому добавить или убрать сервис - это правка одного алиаса, а не поиск правила по всем шести сегментам.

Точечные межсегментные разрешения
#

Помимо базового шаблона, в каждом сегменте есть свой набор точечных правил под конкретные сервисы - но их количество и состав могут сильно отличаться:

  • opt1 (WIFI) - буквально несколько точечных разрешений для отдельных устройств к отдельным сервисам (медиасерверу, Traefik и т.п.), не больше.
  • opt2 (хосты для личного использования) - самый насыщенный по количеству точечных правил из «обычных» сегментов: доступ к базе данных (у меня внешняя бд Postgres) с нескольких источников, доступ к паре внутренних сервисов и к NAS по файловым протоколам (то есть по конкретным портам). Именно здесь оседает основная часть исключений, потому что в этом сегменте больше всего разнородных сервисов.
  • opt3 (DMZ) - минимальный набор, по сути только базовый шаблон без единого точечного разрешения. Логично для DMZ. Там у меня крутится все то, что я тебе показываю в видео, поэтому доступ туда из внешнего мира получить невозможно в принципе. А даже если и получишь, то и сиди в этом VLAN в одиночестве.
  • opt6 (Traefik/CrowdSec) - устроен принципиально иначе, чем остальные сегменты, поэтому разберу его отдельно ниже.
  • lan - тоже не ограничивается только базовым шаблоном. Несколько точечных правил вида «хост → Traefik:443» для отдельных сервисов основного сегмента, которым нужен доступ к проксируемым ресурсам. Логика та же, что и для направления «из остальных сегментов к Traefik», разобранного ниже - просто на уровне конкретных хостов, а не всего сегмента целиком.

opt6 - точечный доступ в дополнение к общему шаблону
#

Базовый шаблон (включая финальный default allow) здесь на месте, как и везде, но сверху - вместо одного общего разрешения «Traefik видит весь Homelab» - 50+ отдельных точечных правил, по одному на каждый проксируемый сервис:

flowchart LR
  T["Traefik
opt6"] -->|":порт сервиса A"| A["Сервис A"] T -->|":порт сервиса B"| B["Сервис B"] T -->|":порт сервиса C"| C["Сервис C"] T -.->|"остальные ~50 сервисов"| D["..."]

Раньше, когда Traefik физически был дружелюбным соседом контейнером-соседом на том же хосте в той же докер машине, что и большинство сервисов, такая детализация была не нужна - трафик же даже не покидал docker-bridge. Как только Traefik переехал на отдельный VLAN, каждое взаимодействие стало пересекать границу сегментов, и firewall увидел (и смог ограничить) то, что раньше было для него полностью невидимым.

Отдельно и обязательно - доступ в обратную сторону, из остальных сегментов к Traefik:443:

flowchart LR
  subgraph Others["LAN / opt1 / opt2"]
    S["Сервисы и агенты"]
  end
  S -->|"обычный reverse-proxy трафик"| T["Traefik:443
opt6"] S -->|"ForwardAuth / OIDC"| T S -->|"WSS-агенты (например Periphery)"| T

Технически это не одно правило на весь сегмент, а набор точечных правил вида «конкретный хост → Traefik:443»: доступ к Traefik открыт только тем, кому он действительно нужен. DMZ в этот список сознательно не входит - оттуда к Traefik не ходит никто.

Без этих правил разом отваливаются внешняя маршрутизация, аутентификация через ForwardAuth/OIDC и WSS-соединения служебных агентов - потому что все три сценария технически используют один и тот же путь трафика на 443, а не три разных. Это не заплатка для решения проблемы, а прямое следствие того, что Traefik - единая точка входа для всего: людей, сервисов и агентов одновременно. Поэтому при проектировании любого нового сегмента я этот путь должен прописывать сразу, в противном случае ничего не заработает. Я, конечно, об этом периодически забываю, но потом неработающий сервис мне напоминает, что что-то пошло не так.

Подробный разбор переезда в этот сегмент (что было, что стало, косяки при аудите, вот это все) - в отдельной статье.

Что дальше
#

  • Более детальный разбор opt1 (WIFI) и opt3 (DMZ) будет отдельными статьями, если наберу достаточно интересного материала. Пока там просто не о чем рассказывать, чтобы заслуживало внимания с моей точки зрения.
  • Если понадобится развернуть еще один сегмент под что-то новое - ориентируюсь я на тот же шаблон, который описан выше: DNS, VPN-сплит при необходимости, блокировка приватных сетей, дефолтный allow, и точечные правила посередине.

Ссылки
#

Работа с Opnsense - This article is part of a series.
Part : This Article

Related

Настройка Kea DHCP сервера в OPNsense - современная альтернатива ISC DHCP

·1140 слов·6 минут· loading · loading
Подробная инструкция по установке и настройке Kea DHCP в OPNsense. Рассмотрены шаги по конфигурации серверов DHCP, управлению диапазонами IP-адресов, настройке статических назначений и проверке работы сети для надежного и гибкого распределения адресов.

История OPNsense - от m0n0wall до современного файрволла

··1068 слов·6 минут· loading · loading
История создания и развития OPNsense - ответвления от проекта pfSense, которое стало самостоятельным и активно развивающимся решением с открытым исходным кодом. Рассматриваем причины форка, философию проекта, ключевые этапы развития и отличия OPNsense от других open-source маршрутизаторов.