Шаг 2. Настройка ADC: плагины

Из прошлой статьи вы уже знаете, как работает ADC. Теперь начинаем обучение настройке. Оно разбито на две части: плагины (текущая статья) и объекты конфигурации (следующая статья).

Скажем заранее: ADC настраивается через объекты конфигурации. Плагины — второстепенная сущность; вы будете их подключать к нужным объектам.

Но поверьте, обучение настройке лучше начать с плагинов. Так будет проще сложить в голове общую картину.

Что такое плагин

Плагин — модуль, который выполняет конкретное действие над запросом/соединением, которое принял ADC.

Пример: плагин key-auth проверяет API-ключ клиента. Если ключ невалидный, ADC отдаст клиенту ошибку и не пропустит запрос к бэкенду.

Какие бывают плагины

В целом, все плагины можно разбить на такие группы:

Группа Что делают Примеры

Аутентификация и авторизация

Проверяют, кто отправил запрос и разрешён ли ему доступ

key-auth — проверяет API-ключ; jwt-auth — JWT; openid-connect — OIDC; opa — авторизация через Open Policy Agent

Ограничение и управление трафиком

Ограничивают нагрузку, распределяют трафик и меняют правила его прохождения

limit-req — ограничивает частоту запросов; limit-conn — число одновременных запросов/соединений; traffic-split — распределяет трафик между группами бэкенд-нод; api-breaker — circuit breaker

Проверка и защита трафика

Проверяют входящий трафик и блокируют нежелательный или некорректный

ip-restriction — ограничения по IP; uri-blocker — блокировка URI; oas-validator — проверка по OpenAPI; chaitin-waf — проверка через WAF

Изменение запросов и ответов

Переписывают URI, заголовки, тело и другие части HTTP-запроса или ответа

proxy-rewrite — изменяет запрос перед проксированием; response-rewrite — ответ; body-transformer — преобразует тело

Преобразование протоколов и интерфейсов

Позволяют клиенту и бэкенду использовать разные протоколы или API

grpc-transcode — HTTP ↔ gRPC; grpc-web — gRPC-Web → gRPC; degraphql — GraphQL → REST; http-dubbo — HTTP → Dubbo

Дополнительная обработка и доставка трафика

Делают с трафиком действия помимо обычной передачи на бэкенд

proxy-mirror — отправляет копию запроса другому сервису; proxy-cache — кэширует ответы; mocking — самостоятельно формирует mock-ответ; redirect — возвращает перенаправление

Логи, метрики и трассировка

Собирают данные о работе ADC и передают их в системы наблюдаемости

http-logger / kafka-logger — отправляют логи; prometheus — метрики; opentelemetry / zipkin — трассировка

Выполнение пользовательской и serverless-логики

Позволяют запускать собственную логику или обращаться к serverless-функциям во время обработки трафика

serverless-pre-function / serverless-post-function — Lua-функции; aws-lambda — AWS Lambda; azure-functions — Azure Functions

Работа со специальными протоколами

Добавляют механику, специфичную для протоколов помимо обычного HTTP

mqtt-proxy — MQTT в Stream; kafka-proxy — параметры проксирования Kafka; dubbo-proxy — Dubbo

AI/LLM

Управляют трафиком к LLM: проксируют его, ограничивают токены, проверяют и преобразуют промпты

ai-proxy — прокси к LLM-провайдерам; ai-rate-limiting — лимиты по токенам; ai-prompt-guard — проверка промптов; ai-rag — RAG

Что ADC умеет без плагинов

Без плагинов ADC может выполнять только базовую обработку трафика:

  1. Принять входящий запрос/соединение от клиента.

  2. Выбрать бэкенд-ноду с учётом алгоритма балансировки и результатов health check.

  3. Передать трафик выбранной ноде.

  4. Передать клиенту трафик от бэкенда.

Какой функционал добавляют плагины

Плагины добавляют дополнительные действия. То есть вы подключаете плагин, и ADC начинает делать что-то сверх списка выше. Например:

  1. Принять HTTP-запрос.

  2. Проверить учётные данные клиента.

  3. Проверить лимит запросов, настроенный для этого клиента.

  4. Отправить копию запроса во внешний сервис.

  5. Изменить заголовки запроса.

  6. Выбрать бэкенд-ноду с учётом алгоритма балансировки и результатов health check.

  7. Передать запрос выбранной ноде.

  8. Получить ответ от бэкенда.

  9. Добавить в ответ служебные заголовки.

  10. Закешировать ответ.

  11. Передать ответ клиенту.

  12. Записать информацию об обработке в логи, метрики или систему трассировки.

Все выделенные жирным действия реализуются с помощью плагинов.

Как подключаются и настраиваются плагины

  1. Создаёте объект конфигурации, который который отвечает за обработку конкретного типа трафика.

    Об объектах подробнее расскажем на шаге обучения 3. Сейчас в это можно не углубляться.

  2. Подключаете к этому объекту нужный плагин.

    tutorial plugins 1
  3. Задаёте атрибуты плагина.

    tutorial plugins 2
  4. Сохраняете объект конфигурации.

Готово. Плагин применяется к трафику, который относится к этому объекту конфигурации.

Порядок выполнения плагинов

Скорее всего, вы подключите много плагинов. Обратите внимание: они выполняются не в том порядке, в котором стоят в интерфейсе.

Очерёдность плагинов привязана к этапам обработки трафика:

  • Сначала выполняются плагины первого этапа (для HTTP-запросов это rewrite, для TCP-UDP-трафика — preread), затем второго (access / before_proxy) и так далее.

  • У каждого плагина есть приоритет. Чем он выше, тем раньше плагин будет выполнен внутри своего этапа обработки трафика.

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

Подробнее о стандартных приоритетах

Стандартные значения настроены так, чтобы закрывать самые часто встречающиеся сценарии. Пример:

  • ip-restriction — приоритет 3000. Этот плагин проверяет, разрешён ли запрос с IP клиента.

  • limit-count — приоритет 1002. Этот плагин проверяет, не исчерпан ли лимит запросов.

У ip-restriction приоритет выше, он сработает раньше. Это соответствует здравому смыслу: если IP запрещён, незачем проверять настроенные для него лимиты — ADC просто сразу отклонит запрос.

Один плагин может выполнять действия на нескольких этапах. Например, cors на этапе rewrite обрабатывает входящий запрос, а на header_filter добавляет CORS-заголовки в ответ. При этом значение приоритета у плагина всё равно одно: на каждом этапе ADC использует его, чтобы определить порядок плагина относительно других плагинов этого этапа.

Чтобы узнать приоритеты всех плагинов, которые вы подключили в рамках объектов конфигурации, отправьте запрос к Control API ADC:

GET /v1/schema

Этапы обработки HTTP-трафика плагинами

  1. rewrite — подготовка запроса к дальнейшей обработке.

    К этому моменту ADC получил HTTP-запрос. Здесь плагины могут:

    • распознать клиента и проверить его учётные данные;

    • изменить URI, заголовки и другие параметры запроса;

    • извлечь из запроса данные, которые понадобятся на следующих этапах;

    • сформировать контекст для дальнейшей обработки запроса.

  2. access — проверка, можно ли продолжить обработку запроса.

    К этому моменту запрос уже подготовлен, а клиент при необходимости распознан. Здесь плагины применяют правила, которые определяют, следует ли пропускать запрос дальше. Например:

    • проверяют права доступа;

    • применяют ограничения по IP и другим условиям;

    • проверяют лимиты запросов или одновременных соединений;

    • отклоняют запрос, если нарушено заданное правило.

    Аутентификация клиента при этом может происходить раньше, на этапе rewrite: сначала ADC определяет, кто отправил запрос, а затем на этапе access может решить, что этому клиенту разрешено делать.

  3. before_proxy — последние действия перед передачей запроса на бэкенд.

    К этому моменту основные проверки уже пройдены и определено, куда будет передан запрос. Здесь плагины выполняют действия, которым нужна информация о выбранном бэкенде или параметрах соединения с ним. Например, они могут:

    • изменить запрос с учётом выбранной бэкенд-ноды;

    • добавить в запрос данные, связанные с выбранным бэкендом;

    • выполнить другую финальную подготовку непосредственно перед проксированием.

  4. header_filter — обработка заголовков ответа.

    К этому моменту HTTP-ответ уже сформирован. Здесь плагины могут изменить заголовки ответа перед передачей клиенту, например:

    • добавить CORS-заголовки;

    • изменить значение существующего заголовка;

    • удалить служебный заголовок, который не должен попасть клиенту.

  5. body_filter — обработка тела ответа.

    К этому моменту HTTP-ответ уже сформирован и при необходимости в нём изменены заголовки. Здесь плагины могут изменить тело ответа перед его передачей клиенту, например:

    • заменить тело ответа целиком;

    • заменить отдельный фрагмент тела ответа;

    • преобразовать содержимое ответа перед отправкой клиенту.

  6. log — фиксация результата обработки запроса.

    К этому моменту основная обработка запроса и ответа уже завершена и этот ответ передан клиенту. Здесь плагины используют сведения о завершённой обработке. Например, они могут:

    • записать или отправить логи;

    • обновить метрики и счётчики;

    • отправить данные трассировки или аудита во внешнюю систему.

То есть упрощённо HTTP-цепочку можно представить так:

rewrite — подготовить запрос и определить клиента
↓
access — решить, можно ли пропустить запрос
↓
before_proxy — выполнить последние действия перед бэкендом
↓
header_filter / body_filter — обработать ответ
↓
log — зафиксировать результат

Например, key-auth и proxy-rewrite выполняются на этапе rewrite, а limit-count — на следующем этапе access. Поэтому сначала выполнятся key-auth и proxy-rewrite, а затем limit-count.

Этапы обработки TCP/UDP-трафика плагинами

Для TCP и UDP используется режим работы ADC stream, в котором последовательность короче:

  1. preread — основная обработка входящего TCP-соединения или UDP-сессии до проксирования.

    К этому моменту ADC уже получил TCP-соединение или UDP-сессию от клиента. Здесь плагины могут:

    • проверить IP-адрес клиента и другие параметры TCP-соединения или UDP-сессии;

    • применить ограничения;

    • проанализировать доступные данные прикладного протокола;

    • определить или скорректировать, куда направить трафик;

    • сформировать контекст, который понадобится на следующих этапах.

  2. before_proxy — последние действия перед началом передачи трафика на бэкенд.

    К этому моменту основные проверки уже пройдены и определено, куда будет направлен трафик. Здесь плагины выполняют действия, которым нужна информация о выбранной бэкенд-ноде или параметрах проксирования. Например, они могут:

    • скорректировать параметры проксирования с учётом выбранной бэкенд-ноды;

    • подготовить данные или контекст, которые нужны непосредственно перед передачей трафика на бэкенд.

  3. log — обработка данных о завершённом TCP-соединении или UDP-сессии.

    К этому моменту передача трафика уже завершена. Здесь плагины используют итоговые сведения о TCP-соединении или UDP-сессии. Например, они могут:

    • записать или отправить лог;

    • обновить метрики и счётчики;

    • сохранить сведения о длительности TCP-соединения или UDP-сессии, объёме переданных данных или результате обработки.

То есть упрощённо stream-цепочку можно представить так:

preread — проверить сессию и принять основные решения
↓
before_proxy — выполнить последние действия перед бэкендом
↓
log — зафиксировать результат

Пример плагина и его настройки

Разберём всё на примере плагина limit-count.

Назначение плагина

limit-count ограничивает количество запросов за заданный период. Примеры лимитов:

  • 100 запросов в минуту;

  • 10 000 запросов в день;

  • 1 000 000 запросов в месяц.

Принцип работы

Система считает запросы, которые попадают в один счётчик лимита. Счётчик может быть привязан к конкретному клиенту, IP, маршруту или другому признаку.

Когда число запросов достигает лимита, новые запросы отклоняются до конца текущего периода.

Применение

limit-count подходит для квот: тарифных планов, SLA, дневных, минутных или месячных лимитов.

Например, его можно использовать, когда клиенту разрешено не больше 10 000 запросов в день. Плагин будет блокировать запросы, начиная с 10 001-го. А на следующий день обнулит счётчик и снова пропустит 10 000 запросов.

Особенности

limit-count может добавлять в ответы заголовки с состоянием лимита:

Заголовок

Что значит

X-RateLimit-Limit

Общий лимит запросов

X-RateLimit-Remaining

Сколько запросов осталось до достижения лимита

X-RateLimit-Reset

Через сколько секунд сбросится счётчик

Эти заголовки помогают API-клиенту отслеживать оставшуюся квоту и заранее замедлять отправку запросов. Добавление заголовков (как и любые другие настройки плагина) делается через атрибуты.

Атрибуты

Атрибут Тип Обяз. По умолч. Допустимые значения Описание

count

integer

Нет

> 0

Максимальное число запросов за заданный интервал. Обязателен, если не настроен rules.

time_window

integer

Нет

> 0

Интервал времени в секундах, которому соответствует count. Обязателен, если не настроен rules.

rules

array
[object]

Нет

Список правил rate limiting. Каждое правило содержит count, time_window и key.

rules.count

integer

Да

> 0

Максимальное число запросов за заданный интервал.

rules.time_window

integer

Да

> 0

Интервал времени в секундах, которому соответствует count.

rules.key

string

Да

Ключ для подсчёта запросов. Если ключ не существует, правило не выполняется. Интерпретируется как комбинация переменных, например $http_custom_a $http_custom_b.

rules.header_prefix

string

Нет

Префикс для rate limit headers: X-{header_prefix}-RateLimit-Limit, X-{header_prefix}-RateLimit-Remaining, X-{header_prefix}-RateLimit-Reset. Если не задан, используется индекс правила.

key_type

string

Нет

var

var / var_
combination / constant

Тип key. var — переменная; var_combination — комбинация переменных; constant — постоянное значение.

key

string

Нет

remote_addr

Признак, по которому считаются запросы. Для var указывается имя переменной без $. Для var_combination все переменные указываются с $. Для constant key считается постоянным значением.

rejected_code

integer

Нет

503

200…​599

HTTP-код, который возвращается при отклонении запроса из-за превышения лимита.

rejected_msg

string

Нет

non-empty

Тело ответа, которое возвращается при отклонении запроса из-за превышения лимита.

allow_degradation

boolean

Нет

false

Если true, система продолжит обрабатывать запросы без плагина, когда плагин или его зависимости недоступны.

policy

string

Нет

local

local / redis / redis-cluster

Политика хранения счётчика. local — в памяти узла; redis — в Redis; redis-cluster — в Redis Cluster.

show_limit_quota_
header

boolean

Нет

true

Если true, в ответ добавляются X-RateLimit-Limit и X-RateLimit-Remaining.

group

string

Нет

non-empty

ID группы плагина. Routes с одной group могут использовать общий счётчик запросов.

redis_host

string

Нет

Адрес узла Redis. Обязателен при policy = redis.

redis_port

integer

Нет

6379

>= 1

Порт Redis при policy = redis.

redis_username

string

Нет

Имя пользователя Redis при использовании Redis ACL. Для legacy requirepass задавайте только redis_password.

redis_password

string

Нет

Пароль Redis при policy = redis или redis-cluster.

redis_ssl

boolean

Нет

false

Если true, используется SSL-подключение к Redis при policy = redis.

redis_ssl_verify

boolean

Нет

false

Если true, проверяется SSL-сертификат сервера Redis при policy = redis.

redis_database

integer

Нет

0

>= 0

Номер базы данных Redis при policy = redis.

redis_timeout

integer

Нет

1000

>= 1

Таймаут Redis в миллисекундах при policy = redis или redis-cluster.

redis_keepalive_
timeout

integer

Нет

10000

>= 1000

Keepalive timeout для Redis в миллисекундах при policy = redis или redis-cluster.

redis_keepalive_
pool

integer

Нет

100

>= 1

Размер keepalive pool для Redis при policy = redis или redis-cluster.

redis_cluster_
nodes

array
[string]

Нет

Список узлов Redis Cluster. Требуется минимум два адреса. Обязателен при policy = redis-cluster.

redis_cluster_
name

string

Нет

Имя Redis Cluster. Обязательно при policy = redis-cluster.

redis_cluster_
ssl

boolean

Нет

false

Если true, используется SSL-подключение к Redis Cluster при policy = redis-cluster.

redis_cluster_
ssl_verify

boolean

Нет

false

Если true, проверяется SSL-сертификат сервера Redis Cluster при policy = redis-cluster.

Пример конфигурации

С такой конфигурацией limit-count будет разрешать 1 запрос за 30 секунд для каждого IP-адреса клиента:

"limit-count": {
  "count": 1,
  "time_window": 30,
  "rejected_code": 429,
  "key_type": "var",
  "key": "remote_addr"
}