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

Внутренний запрос остаётся отдельным пакетом со своим источником, назначением и службой, и ядро знает, из какой ассоциации безопасности он вышел. Именно эти знания и может сопоставить правило межсетевого экрана.

Два пакета, один интерфейс

Представьте входящее направление. Приходит пакет, инкапсулированный в ESP или UDP, ядро находит подходящую политику, расшифровывает его и передаёт открытый пакет на путь пересылки. Правило, которое смотрит только на имя интерфейса, не может отличить этот пакет от любого другого трафика, приходящего по тому же проводу.

Отличает его контекст входящего пути безопасности, привязанный к пакету. nftables показывает его как meta ipsec exists, что верно, когда пакет пришёл через путь безопасности IPsec. Соедините его с пулом клиентов, назначением и службой, и правило станет достаточно конкретным, чтобы быть безопасным.

Опустить контекст — обычная ошибка, и это ошибка безопасности, а не косметическая. Правило, которое принимает всё из пула клиентов, так же охотно примет поддельный пакет из локальной сети, потому что адрес источника сам по себе ничего не доказывает. Контекст пути безопасности — самый дешёвый способ сделать источник осмысленным. Пишите правило с ним с самого начала, а не добавляйте его после аудита.

Напишите правило пересылки

Предположим, есть аутентифицированная служба удалённого доступа IPv4 с клиентами в 10.90.0.0/24 и одно одобренное назначение на 203.0.113.40. Фрагмент правила для этого потока выглядит так.

meta ipsec exists ip saddr 10.90.0.0/24 \
  ip daddr 203.0.113.40 tcp dport 443 \
  oifname "eth0" counter accept

Адреса и интерфейс — примеры для замены. Поместите проверенный эквивалент в политику пересылки перед правилом, которое иначе отклонило бы поток, и не очищайте существующий набор правил, чтобы его установить; шлюз — не эксперимент в чистой комнате.

Термин oifname стоит сохранить. Он документирует решение о выходе и не позволяет правилу совпасть в направлении, которое вы не имели в виду, а это важно на шлюзе с несколькими путями в интернет. На тестовой машине с одним вышестоящим каналом термин кажется излишним, и именно поэтому его убирают раньше, чем машина получит второй канал.

Разрешения для внешнего обмена отдельные. Входному пути шлюза нужны порты IKE и ESP или инкапсуляции UDP, которые он действительно использует, и эти разрешения ничего не разрешают в отношении расшифрованного пакета внутри. Смешивать одно с другим — это путь, которым работающий туннель оказывается с межсетевым экраном, пересылающим всё.

Входящий контекст — не исходящий контекст

То же семейство выражений покрывает другое направление через rt ipsec, который описывает исходящую ассоциацию безопасности, которую будет использовать пакет. Он отвечает на другой вопрос: не откуда пришёл этот пакет, а будет ли он защищён на следующем участке.

Это различие важно на шлюзе, который одновременно завершает один туннель и пересылает в другой. Пакет может прийти расшифрованным и всё же должен уйти зашифрованным, а разрешение, написанное только для входящего контекста, ничего не говорит о требовании к исходящему. Если политика требует такой защиты, набор правил должен её выразить, а не предполагать, что маршрутизация разберётся.

Держите два вопроса в отдельных правилах, чтобы читатель видел, какое из них применяется. Одно хитрое правило, проверяющее оба, труднее проверять и гораздо труднее отлаживать, когда одна его половина перестаёт совпадать. Два правила со счётчиками также сообщают, какое требование не выполняется, чего объединённое правило никогда не сделает.

NAT — это не решение межсетевого экрана

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

Разрешение внутри цепочки NAT тоже не общее позволение. У NAT и фильтрации разные задачи, и цепочка NAT не проверяет каждый последующий пакет установленного потока, и именно поэтому расчёт на неё в вопросах безопасности даёт правила, которые выглядят работающими в тесте и отказывают под нагрузкой.

Обратное тоже верно и застаёт людей врасплох: разрешение где-то в одной базовой цепочке фильтрации ничего не весит против последующего отклонения в другой применимой цепочке. Результат решают порядок и охват цепочки, а не наличие разрешения в файле.

Проверьте точную внутреннюю службу

Проверьте конкретное назначение и порт, которые вы разрешили, с настоящего клиента и убедитесь, что ответ возвращается. Затем проверьте что-то, что вы не разрешали, и убедитесь, что это не проходит, потому что слишком широкое правило проходит первую проверку так же хорошо, как правильное. Запрос, который вообще не покидает клиента, тоже не результат межсетевого экрана, поэтому читайте счётчики, чтобы понять, оценивался ли пакет вообще. Две проверки и одно чтение счётчика расскажут больше, чем целый день чтения набора правил.

Справочник nftables описывает meta ipsec, rt ipsec и выражения, зависящие от направления, и именно там проверяют синтаксис относительно установленной версии. И держите охват явным: это пример IPv4, он ничего не говорит об IPv6 и не превращает произвольную пересылку публичных портов в часть службы VPN.

Похожие статьи