SkyDNS on-prem решение
1. Общее описание продукта
SkyDNS on-prem решение для контентной фильтрации DNS-трафика представляет собой DNS Proxy, который получая DNS-запрос идентифицирует пользователя, сравнивает целевой домен с политикой фильтрации для этого клиента и принимает решение о блокировке (или не блокировке) трафика.
Блокировка, с технической точки зрения, осуществляется путем подмены IP целевого ресурса на IP страницы блокировки. Это может быть как собственная корпоративная страница, расположенная за пределами нашего решения, так и встроенная в наше решение типовая страница блокировки (при этом её можно кастомизировать).
Важным ограничением является необходимость добавление в список доверенных нашего корневого сертификата на каждое конечное устройство пользователя для отображения страницы блокировки по протоколу https. Для отображения страницы блокировки по протоколу http это не требуется. Без установленного сертификата на конечном устройстве при блокировании домена по https, пользователь не увидит страницу блокировки, но доступ к ресурсу всё равно будет заблокирован.
В случае, если блокировка не требуется, работая как DNS Proxy, запрос на резолв целевого домена перенаправляется на следующий в цепочке кэширующий DNS-сервер. Это может быть как локальный корпоративный DNS-сервер или DNS провайдера, так и любой публичный DNS.
Кроме этого, пропуская через себя весь DNS-трафик это решение позволяет анализировать весь трафик в разрезе пользователей. Аккумулируются логи всех запросов и предоставляется доступ к статистике.
2. Варианты схемы размещения продукта в контуре компании
В зависимости от топологии сети клиента, схем размещения может быть множество. Ниже представлены примеры типовых решений.
Для провайдеров
Такая схема размещения используется в крупных сетях, где конечные пользователи расположены за NAT относительно основного оборудования клиента и нет возможности идентифицировать их по индивидуальному IP.
Для корпоративных клиентов
или
Эта схема используется в сетях, где в точке расположения нашего решения возможна идентификация конечного пользователя по IP. Здесь в зависимости от наличия в компании собственного кэширующего DNS сервера - запросы проксируются либо на него, либо на внешнюю инфраструктуру (DNS провайдера или любой публичный DNS, типа 1.1.1.1 или 8.8.8.8).
Для корпоративного клиента с AD (или другим локальным DNS)
В этом случае запросы получает сначала сервер AD, обслуживает локальные адреса, затем, в качестве внешнего источника домен передается в наш сервис, где происходит фильтрация определенных доменов и только в случае необходимости обеспечить доступ к целевому ресурсу - запрос передается на внешний рекурсивный DNS. В такой схеме - невозможно идентифицировать конечного пользователя, т.к. источником всех запросов будет служить домен-контроллер или ддругой локальный DNS-сервер.
Однако, прямо сейчас SkyDNS разрабатывает решение, которое позволит устранить эту проблему и возможно будет сохранить связь конечных пользователей с домен-контроллером, при этом идентифицировать их на нашем оборудовании. Кроме того, станет возможным управлять фильтрацией через групповые политики AD. Это решение должно выйти до конца 2024 года.
3. Идентификация пользователей
Для возможности применения различных политик фильтрации, а также для разделения статистики по запросам необходимо идентифицировать конечного пользователя. Для идентификации в on-prem решении используется один из следующих вариантов:
- IP
- IP/подсеть
- IP:порт
- IP:[порт]-[порт]
В случае наличия у каждого пользователя своего IP (с которого будут поступать DNS-запросы) мы клиента идентифицируем по этому IP. Либо, если нет необходимости детального разделения - сразу по подсети.
Если же пользователь находится за NAT (CGNAT, NAT44 и др.) и запросы от разных конечных пользователей будут приходить с одного и того же IP, то в этом случае мы можем идентифицировать конечного пользователя по связке IP + порт, либо по диапазону портов.
4. Из чего состоит
Внутри наше решение состоит из:
- Модуля DNS Proxy, который получат DNS-запрос и возвращает на него ответ в виде IP
- Внутренней БД, содержащей информацию о всех пользователях и политиках фильтрации
- RestAPI для обновления данных в БД:
- Создание/изменение профилей фильтрации (какие категории должны быть заблокированы)
- Создание/изменение страницы блокировки
- Создание/обновление пользователя или группы пользователей с указанием:
- идентификатора (подсеть/IP/порт)
- профиля фильтрации
- страницы блокировки
- Страницы блокировки
- Модуля парсинга бинарных логов DNS Proxy (StatsLoader)
- Модуля экспорта статистики в СУБД Clickhouse
Расшифровка других элементов схемы:
Клиент
Представляет конечного пользователя, который будет использовать сервис DNS-фильтрации. Клиент отправляет DNS-запросы в SkyDNS on prem.
DB Files
Это база данных, которая хранит информацию о клиентах и правила фильтрации. RestAPI извлекает информацию из этой базы данных.
DNSPROXY
Этот компонент является центральным элементом процесса DNS-фильтрации. Он получает DNS-запросы от клиента, применяет правила фильтрации на основе данных, полученных из DB Files, а затем перенаправляет запросы на кэширующий DNS.
Кэширующий DNS сервер
Это кэш-сервер, развернутый на стороне клиента. Он выполняет фактическое разрешение DNS-запросов после их фильтрации через DNSPROXY.
HostPATH
После обработки DNS-запросов DNSPROXY создает binlog-файлы (журнальные файлы, содержащие информацию о DNS-запросах). HostPATH отвечает за хранение этих binlog-файлов.
StatsLoader
После сохранения binlog-файлов StatsLoader получает и анализирует двоичные данные от HostPATH, затем обрабатывает статистику и отправляет их в кластер ClickHouse для хранения и анализа.
Балансировщик нагрузки (LB)
StatsLoader отправляет обработанную статистику на балансировщик нагрузки, который распределяет её по узлам ClickHouse.
Кластер ClickHouse
Это распределенная база данных, используемая для хранения и анализа статистики DNS-запросов. Кластер разделен на шарды, и каждый шард содержит несколько узлов ClickHouse для отказоустойчивости (mirroring). Шард 1 и Шард 2 предназначены для высокой производительности, т.к. чтение и запись производится параллельно.
Zookeeper
Эти экземпляры управляют конфигурацией и координацией кластера ClickHouse, обеспечивая консистентность данных и надежность распределенной системы.
5. Настройка и взаимодействие с продуктом
Вся настройка, обслуживание и поддержка осуществляется исключительно специалистами SkyDNS, что позволяет однозначно определить зоны ответственности между SkyDNS и клиентом. Клиент предоставляет оборудование (сервер на архитектуре x64) согласно требованиям и удаленный доступ к этому серверу, после чего мы настраиваем всё "под ключ".
Нашими специалистами, совместно с заказчиком производится первичная настройка правил фильтрации и производится обучение специалистов клиента для дальнейшей настройки.
При необходимости - выделяется отдельная линия поддержки для клиентов с On-Prem решениями.
6. Работа со статистикой
На самом сервере SkyDNS Security хранятся бинарные логи. В составе нашего решения присутстувет модуль, который парсит эти логи и выгружают во внешнюю СУБД для последующего анализа и формирования отчётов. В данный момент существует коннектор для выгрузки логов в СУБД ClickHouse, которая показывает наилучшую производительность при работе с таким типом данных, но при необходимости, логи можно выгружать и в другие СУБД. Модуль статистики не является обязательным для обеспечения основного функционала SkyDNS Security, однако, без неё невозможно оценить эффективность работы и проводить расследование инцидентов.
7. Системные требования к продукту
Минимальные системные требования для сервера под модуль SkyDNS Security составляют:
- CPU 4 ядра (архитектура x64)
- RAB 8 Gb
- 200 Gb NVMe
- ОС Debian 11
Таких характеристик достаточно для функционирования всех модулей системы и обработки до 1000 запросов в секунду.
На характеристиках 64 ядра CPU и 128 Gb RAM система способна обрабатывать до 2 млн. запросов в секунду при достаточной пропускной способности сетевых интерфейсов.
Для кластера СУБД Clickhouse минимальные системные требования на один сервер:
- CPU 8 ядер (архитектура x64)
- RAB 16 Gb
- 500 Gb NVMe (до 2 Tb в зависимости от объёма трафика клиента)
При этом мы рекомендуем минимальный кластер из 4 серверов с разбивкой 2x2. Т.е. два шарда для параллельной записи/чтения и 2 сервера в каждом шарде для резервирования.
Опционально, при небольшом объёме трафика можно назвернуть Stand-Alone сервер Clickhouse и отказаться от модуля Zookeeper.
8. Rest API
Всё взаимодействие со SkyDNS Security производится с помощью Rest API. Для это существуют следующие вызовы:
- Инициализация базы юзердаты (создание пачки данных):
-
тип: POST
-
URL: <domain>/init/
-
данные:
{ 'profiles': [ { 'cat_ids': [<cat_id>,], 'profile': { 'page_id': <page_id>, 'id': <id> } }, ... ], 'nets': [{'ip': <ipv4>, 'profile_id': <profile_id>, 'prefix_len': <prefix_len4>}, ...], 'nets6': [{'ip': <ipv6>, 'profile_id': <profile_id>, 'prefix_len': <prefix_len6>}, ...], 'blockpages': [{'id': <page_id>, 'type': <blockpage_type>}, ...], 'napts': [ { 'ip': <ipv4>, "profile_id": <profile_id>, "lower_port_bound": <lower_port_bound>, "upper_port_bound": <upper_port_bound> }, ] } -
результат: 204, без тела
-
валидация:
- cat_ids в списке видимых категорий для ская в skydns-categories (код 400, ошбика: Invalid cat_ids: {cat_ids})
- id профилей не повторяются (код 400, ошбика: Profile IDs are repeated)
- page_id id страницы блокировки из blockpages
- profile_id у сетей есть в списке profiles (код 400, ошибка: Unknown profile_id {profile_id})
- ipv4 не повторяются (код 400, ошбика: IPv4 are repeated)
- ipv6 не повторяются (код 400, ошбика: IPv6 are repeated)
- адреса ipv4 валидного формата ipv4 (rfc 791) (код 400, ошибка: Invalid IPv4 format {ipv4})
- адреса ipv4 не приватные (код 400, ошибка: IPv4 address {ipv4} is private)
- адреса ipv6 валидного формата ipv6 (rfc 2460) (код 400, ошибка: Invalid IPv6 format {ipv6})
- адреса ipv6 не приватные (код 400, ошибка: IPv6 address {ipv6} is private)
- prefix_len4 маска подсети 16-32
- prefix_len6 маска подсети 64-128
- lower/upper_port_bound - границы диапазона портов для napt
-
логирование: Init database: {input_data}
-
- Получение всех профилей:
- тип: GET
- урл (предварительно): <domain>/profiles/
- результат: 200, список словарей с данными id, cats_ids
- Добавление профиля:
-
тип: POST
-
URL: <domain>/profiles/
-
данные:
{ "profile": { "id": int, "page_id": int }, "cat_ids": [int, ] } -
результат: 201, словарь с данными профиля
-
действия при добавлении:
- добавляется строка в таблицу profile (все значения используются по умолчанию)
- добавляется строк в таблицу profile2cat с созданным profilе_id и cat_ids
-
валидация:
- cat_ids в списке видимых категорий для ская в skydns-categories (код 400, ошбика: Invalid cat_ids)
-
логирование: Add profile: profile_id={profile_id}, cat_ids={cat_ids}
-
- Получение профиля:
- тип: GET
- URL: <domain>/profiles/<id>/
- результат: 200, словарь с данными id, cats_ids
- Добавление айпи адреса ipv4:
- тип: POST
- URL: <domain>/net/
- данные: ipv4, profile_id
- результат: 201, словарь с данными ipv4, profile_id
- действия при добавлении:
- добавляется строка в таблицу net (
skydns.userdata.models.ip2int(ipv4),profile_id)
- добавляется строка в таблицу net (
- валидация:
- адрес валидного формата ipv4 (rfc 791) (код 400, ошибка: Invalid ipv4 format)
- не приватный (код 400, ошибка: IP address is private)
- еще нет в базе (код 400, ошибка: IP address already exists)
- логирование: Add net: ipv4={ipv4}, profile_id={profile_id}
- Получение ipv4 адреса:
- тип: GET
- URL: <domain>/net/<int_ip>/
- результат: 200, словарь с данными ipv4, profile_id
- валидация:
- существование адреса int_ip из урла (код 404, ошибка: IP address not exists)
- Обновление ipv4 адреса:
- тип: PATCH
- URL: <domain>/net/<int_ip>/
- данные (необязательные): ipv4, profile_id
- результат: 200, словарь с данными ipv4, profile_id
- валидация:
- существование адреса int_ip из урла (код 404, ошибка: IP address not exists)
- адрес валидного формата ipv4 (rfc 791) (код 400, ошибка: Invalid ipv4 format)
- не приватный (код 400, ошибка: IP address is private)
- еще нет в базе (код 400, ошибка: IP address already exists)
- логирование: Update net {old_ipv4}: ipv4={new_ipv4}, profile_id={new_profile_id}
- Удаление ipv4 адреса:
- тип: DELETE
- URL: <domain>/net/<int_ip>/
- результат: 204 код, без тела
- валидация:
- существование адреса int_ip из урла (код 404, ошибка: IP address not exists)
- логирование: Delete net {ipv4}
- Добавление айпи адреса ipv6:
- тип: POST
- URL: <domain>/net6/
- данные: ipv6, profile_id
- результат: словарь с данными ipv6, profile_id
- действия при добавлении:
- добавляется строка в таблицу net6 (
ip_address(address).packed,prefix_len=128,profile_id)
- добавляется строка в таблицу net6 (
- валидация:
- адрес валидного формата ipv6 (rfc 2460) (код 400, ошибка: Invalid ipv6 format)
- не приватный (код 400, ошибка: IP address is private)
- еще нет в базе (код 400, ошибка: IP address already exists)
- логирование: Add net6: ipv6={ipv6}, prefix_len=128, profile_id={profile_id}
- Получение ipv6 адреса:
- тип: GET
- урл (предварительно): <domain>/net6/<int_ip>/
- результат: словарь с данными ipv6, profile_id
- Обновление ipv6 адреса:
- тип: PATCH
- URL: <domain>/net6/<int_ip>/
- данные (необязательные): ipv6, profile_id
- результат: 200, словарь с данными ipv6, profile_id
- валидация:
- существование адреса int_ip из урла (код 404, ошибка: IP address not exists)
- адрес валидного формата ipv6 (rfc 2460) (код 400, ошибка: Invalid ipv4 format)
- не приватный (код 400, ошибка: IP address is private)
- еще нет в базе (код 400, ошибка: IP address already exists)
- логирование: Update net6 {old_ipv6}: ipv6={new_ipv6}, prefix_len=128, profile_id={new_profile_id}
- Удаление ipv6 адреса:
- тип: DELETE
- URL: <domain>/net6/<int_ip>/
- результат: 204 код, без тела
- валидация:
- существование адреса int_ip из урла (код 404, ошибка: IP address not exists)
- логирование: Delete net6 {ipv6}




