Заблокированные запросы: ответ, аудит и метрики
Каждая блокировка видна в трёх местах одновременно: клиент получает HTTP-ответ с кодом отказа, оператор — событие в потоке аудита, мониторинг — приращение счётчика блокировок в метриках.
Коды ответа: 403 и 405
Код отказа зависит от того, на каком измерении политики запрос не прошёл.
| Код | Когда возвращается | Что это значит для оператора |
|---|---|---|
405 Method Not Allowed | Путь совпал хотя бы с одним правилом, но ни одно из совпавших правил не разрешает этот метод. | Ресурс политикой предусмотрен, запрошенная операция над ним — нет. |
403 Forbidden | Путь не совпал ни с одним правилом. | Ресурс политикой не предусмотрен вообще; метод в этом случае не проверяется. |
Разделение кодов сделано для диагностики: 405 обычно означает, что политика описана правильно, но клиент использует незаявленную операцию, а 403 — что путь не попал в политику (опечатка в шаблоне, новая точка API, сканирование чужих путей).
Заблокированный запрос получает ответ с пустым телом:
HTTP/1.1 403 Forbidden
Content-Length: 0
Connection: close
Тело, детали правила и причина блокировки клиенту не раскрываются: внешняя сторона не должна по ответам восстанавливать структуру политики и внутреннего API. Соединение после ответа закрывается.
Что происходит с запросом внутри контура
| Компонент | Момент проверки | Последствия блокировки |
|---|---|---|
netgap-gateway | Сразу после разбора строки запроса и заголовков, до постановки в очередь. | Запрос не попадает в очередь запросов, клиентское соединение не паркуется в пуле, исполнитель о запросе не узнаёт. Клиент получает 403/405 немедленно. |
netgap-executor | В обработке полученного запроса, до вызова целевого сервиса. | Целевой сервис не вызывается; шлюзу через мост ответов возвращается ответ 403/405 с пустым телом и нулевым временем вызова целевого сервиса, шлюз отдаёт его ожидающему клиенту. |
Блокировка на исполнителе при разрешающей политике шлюза — штатный признак рассинхронизации конфигураций: политика уже ужесточена в доверенном сегменте и ещё не обновлена на границе (или наоборот). Разбирается по компоненту, чья метрика блокировок растёт; оба случая по шагам разобраны ниже, в разделе Сценарии блокировки.
Как блокировка отражается на остальных показателях:
netgap_gateway_requestsиnetgap_executor_requestsувеличиваются и для заблокированного запроса — счётчик принятых запросов растёт до проверки политики;- гистограммы задержек шлюза (
netgap_gateway_total_latency_seconds,netgap_gateway_processing_time_seconds) заблокированными запросами не наполняются: ответ отдаётся до постановки в очередь; netgap_executor_target_call_time_secondsдля заблокированного запроса не пишется — вызова целевого сервиса не было;netgap_gateway_errorsиnetgap_executor_errorsне увеличиваются: блокировка — это штатное решение политики, а не ошибка обработки.
Сценарии блокировки
Запрос заблокирован шлюзом
Обычный случай при одинаковой политике у обоих компонентов: решение принимается на границе контура, дальше запрос не идёт.
Для незнакомого пути (GET /internal/debug) картина та же, меняются только решение и коды: BlockedPath, reason=path, ответ 403 Forbidden.
Запрос заблокирован исполнителем
Случай расхождения политик: шлюз работает в mode: AllowAll (например, ограничение ещё не раскатано на границу), а у исполнителя уже настроен AllowList. Запрос доходит до доверенного сегмента, но целевого сервиса не достигает.
Отличия от блокировки на шлюзе, важные при разборе инцидента:
- запрос занимает место в очереди шлюза и удерживает клиентское соединение в пуле до прихода ответа — блокировка на исполнителе не экономит ресурсы границы;
- в аудите шлюза есть штатные
http requestиreceived response, а событиеrequest blocked by http filterприходит только от исполнителя; - растёт
netgap_executor_blocked_requests, тогда какnetgap_gateway_blocked_requestsостаётся нулевым — это и есть характерный признак расхождения политик; - гистограмма
netgap_executor_target_call_time_secondsне пополняется, аtarget_processing_timeв ответе равен нулю, поэтому вnetgap_gateway_target_call_time_secondsтакой запрос попадает нулевым значением; гистограммы задержек шлюза при этом заполняются как у обычного запроса.
Обратный перекос — правила на шлюзе и AllowAll у исполнителя — снаружи выглядит как первый сценарий: клиент получает отказ от шлюза, исполнитель о запросе не узнаёт. Скрытый риск здесь в том, что исполнитель перестаёт быть последним рубежом перед целевым сервисом, поэтому секцию http_filter держат одинаковой в обеих конфигурациях. Если такая асимметрия выбрана осознанно, см. разбор остающихся рисков в статье Схемы размещения фильтра.
Событие аудита
Каждая блокировка фиксируется как событие уровня warn в потоке аудита (target_id: Audit) и дублируется в технологический лог. Событие формируется обоими компонентами независимо, поэтому запрос, заблокированный шлюзом, даёт одну запись, а редкий случай блокировки на исполнителе — запись со стороны исполнителя.
| Компонент | Событие | Когда формируется |
|---|---|---|
netgap-gateway | request blocked by http filter | Запрос не прошёл фильтр на границе контура и не был поставлен в очередь. |
netgap-executor | request blocked by http filter | Запрос не прошёл фильтр перед вызовом целевого сервиса. |
Поля события:
| Поле | Назначение |
|---|---|
method | HTTP-метод запроса, как его прислал клиент. |
path | Путь запроса из строки запроса, вместе с query-строкой, если она была. |
reason | Причина блокировки: path — путь не совпал ни с одним правилом, method — метод не разрешён для совпавшего пути. |
status_code | Код ответа: 403 для reason=path, 405 для reason=method. |
Заголовки и тело запроса в событие не попадают: аудит фиксирует факт и причину отказа, а не содержимое трафика. Для промышленной эксплуатации события удобно писать в отдельный файл в format: Json и/или отправлять в SIEM — настройка описана в статьях События и Аудит.
observability:
service_name: netgap-gateway
event_targets:
- level: info
target_id: Audit
target_destination: File
target_args: /var/log/netgap/audit.log
format: Json
siem:
endpoint: 192.0.2.10:514
log_types: [Audit]
level: info
Событие имеет уровень warn, поэтому оно проходит в цели с порогом info и warn, но отбрасывается целью с уровнем error. Если в SIEM нужны только блокировки и ошибки без штатных событий прохождения запросов, достаточно поднять порог до level: warn.
Метрики блокировок
Каждый компонент публикует собственный счётчик заблокированных запросов через функцию Метрики.
| Метрика | Тип | Что показывает |
|---|---|---|
netgap_gateway_blocked_requests | counter | Запросы, заблокированные фильтром на стороне шлюза. |
netgap_executor_blocked_requests | counter | Запросы, заблокированные фильтром на стороне исполнителя. |
Метки серий:
| Метка | Значения | Назначение |
|---|---|---|
method | HTTP-метод запроса | Показывает, какая операция запрашивалась. |
path | Путь запроса | Показывает, какой ресурс запрашивался. |
reason | path, method | Причина блокировки: неизвестный путь или неразрешённый метод. |
Важно: метка
pathсодержит путь запроса так, как его прислал клиент, включая query-строку. На потоке произвольных или сканирующих запросов это даёт высокую кардинальность серий. Если Netgap открыт в недоверенную сеть, ограничьте кардинальность на стороне сбора метрик — например,metric_relabel_configsв Prometheus, который отбрасывает или обобщает меткуpath, оставляя разбивку поmethodиreason.
Примеры PromQL:
rate(netgap_gateway_blocked_requests[5m])
Блокировки по причинам за 5 минут:
sum by (reason) (rate(netgap_gateway_blocked_requests[5m]))
Топ-10 путей, которые чаще всего блокируются:
topk(10, sum by (path) (rate(netgap_gateway_blocked_requests[5m])))
Доля заблокированных запросов в общем входящем потоке шлюза:
sum(rate(netgap_gateway_blocked_requests[5m])) / sum(rate(netgap_gateway_requests[5m]))
Блокировки на исполнителе — признак расхождения политик компонентов (кандидат в правило алертинга):
sum(rate(netgap_executor_blocked_requests[5m])) > 0
Диагностика
| Симптом | Вероятная причина | Что сделать |
|---|---|---|
Весь трафик получает 403, метрика блокировок растёт с reason=path | Политика не покрывает фактические пути целевого сервиса (опечатка, лишний или недостающий префикс, регистр) | Сверить пути в событиях аудита с правилами; см. Правила фильтра |
| Часть операций получает 405 после включения фильтра | Метод не перечислен для совпавшего пути (частый случай — HEAD и OPTIONS) | Добавить недостающие методы в правило |
Растёт netgap_executor_blocked_requests, а netgap_gateway_blocked_requests — нет | Политики шлюза и исполнителя различаются | Привести секции http_filter к одинаковому виду и перезапустить оба компонента |
| Блокировок нет вообще, хотя ожидались | Компонент запущен с mode: AllowAll | Проверить фактическую конфигурацию запуска: режим задан в ней явно, а политика читается один раз при старте |
Метрики блокировок отсутствуют в /metrics | Ни одной блокировки ещё не было либо не включена секция observability.metrics | Проверить настройку метрик; серии появляются после первой блокировки |
Резкий рост уникальных значений метки path | Сканирование внешним источником | Ограничить кардинальность на стороне Prometheus и разобрать источник по событиям аудита |
Ссылки
- Конфигурирование фильтра HTTP-запросов — секция
http_filter, режимы и проверка конфигурации. - Правила фильтра: пути и методы — синтаксис правил и семантика сопоставления.
- Схемы размещения фильтра: шлюз, исполнитель или оба — когда блокировки на исполнителе штатны, а когда — признак рассинхронизации.
- Аудит — полный состав audit-событий и варианты доставки.
- Описание метрик — полный перечень метрик компонентов.