8(800) 222 32 56
Панель управления
Сетевые протоколы

PROXY protocol v2 для LLM API: как сохранить реальный IP клиента

PROXY protocol v2 для LLM API: как сохранить реальный IP клиента
Подберите идеальное решение для ваших задач:
в России, США и Нидерландах обеспечат максимальную скорость. Воспользуйтесь всеми преимуществами надежного оборудования. Базовая помощь и техническое обслуживание входят в пакет услуг.

Rate limit внезапно блокирует всех пользователей сразу, а в audit log у каждого запроса один и тот же адрес load balancer. Для LLM API это не мелкая неточность: вы теряете границу tenant, разрешаете обход дорогих квот или останавливаете очередь из-за одного клиента. PROXY protocol v2 и X-Forwarded-For решают задачу только при правильно заданном доверии. Ниже — production-runbook: как выбрать механизм, настроить NGINX, Envoy и Kubernetes, доказать защиту от spoofing и провести rollout с отрицательным контролем.

Готовы перейти на современную серверную инфраструктуру?

В King Servers мы предлагаем серверы как на AMD EPYC, так и на Intel Xeon, с гибкими конфигурациями под любые задачи — от виртуализации и веб-хостинга до S3-хранилищ и кластеров хранения данных.

  • S3-совместимое хранилище для резервных копий
  • Панель управления, API, масштабируемость
  • Поддержку 24/7 и помощь в выборе конфигурации

Создайте аккаунт

Быстрая регистрация для доступа к инфраструктуре

Почему все запросы внезапно приходят с одного IP

Инцидент начинается не с сети, а с бизнес-симптома. Лимит срабатывает сразу для всех, аудит показывает адрес балансировщика, а расследование злоупотребления упирается в одну строку лога. Сам LLM отвечает, GPU загружен нормально, ошибки 5xx не растут — но контроль доступа уже работает не по тем субъектам.

Причина проста: TCP-соединение до приложения устанавливает последний proxy hop. Для ядра именно он является peer, поэтому приложение честно видит адрес NGINX, Envoy или load balancer. Реальный клиентский адрес существует раньше по цепочке и должен быть передан отдельным механизмом.

Для LLM API ошибка дороже обычной неточности. Запросы длинные, квоты считают токены или параллельные генерации, а один пользователь способен занять очередь. Если limiter ключуется по адресу общего proxy, шумный клиент блокирует всех; если приложение верит произвольному header, атакующий меняет IP и обходит лимит.

Сопоставьте три значения на canary-запросе: TCP peer на gateway, asserted address из metadata и effective IP, который попал в limiter и audit. Если поля смешаны, сначала чините trust boundary, а не увеличивайте лимиты.

Есть важный disqualifier: когда effective IP уже совпадает с клиентом, проблема может жить в API key, tenant mapping, NAT большого корпоративного пользователя или retry storm. Не переписывайте сеть без этого контрфакта.

Потеря реального IP клиента за балансировщиком LLM API

Сначала нарисуйте trust boundary, потом выбирайте заголовок

Client IP — не факт из запроса, а утверждение конкретного узла. Оно заслуживает доверия, только когда получатель знает отправителя и исключил прямой обход. Выпишите каждый hop: интернет-клиент, внешний L4 LB, TLS termination, L7 proxy, ingress и приложение.

Для каждого ребра задайте три вопроса. Кто устанавливает TCP-соединение? Кто имеет право сообщить исходный адрес? Может ли клиент подключиться к получателю напрямую? Если да, X-Forwarded-For или PROXY header на этом listener становится способом spoofing.

Спецификация HAProxy требует принимать PROXY protocol только от доверенных прокси. Header идёт до HTTP и меняет представление о peer для всего соединения, поэтому ошибка влияет и на TLS audit, и на HTTP controls.

Практический default: доверяйте точным CIDR или security groups балансировщиков, закройте backend firewall-ом и логируйте физический peer вместе с восстановленным адресом. Не используйте всю приватную сеть как удобный allowlist.

Owner у каждого утверждения должен быть один. Если CDN добавляет XFF, WAF переписывает его, а ingress снова добавляет адрес, документируйте порядок и версию trust list. Иначе следующая миграция создаст тихую дыру.

Какой слой переносит client IP?

Схема границ доверия для PROXY protocol и X-Forwarded-For

PROXY v2, X-Forwarded-For или source IP: быстрый выбор

PROXY protocol работает на L4. Отправитель добавляет служебный header в начало нового соединения, а получатель читает source и destination до TLS или HTTP. Версия 2 бинарная, поддерживает IPv4, IPv6 и TLV. Это выбор для TCP load balancer или когда адрес нужен на TLS termination.

X-Forwarded-For и стандартный Forwarded принадлежат L7. Их проще читать, зато proxy должен понимать HTTP и очищать цепочку. Первый элемент не становится достоверным автоматически: алгоритм отбрасывает trusted hops и выбирает последний недоверенный адрес.

Source IP без metadata возможен, если маршрут не делает SNAT. В Kubernetes externalTrafficPolicy: Local сохраняет адрес, но обслуживает только node-local endpoints. Это обмен fidelity на свободу распределения, а не бесплатный флаг.

Не смешивайте механизмы на одном порту без ясного контракта. Listener, ожидающий PROXY header, не является обычным TLS listener: неверный клиент получит handshake failure. Раздельные адреса проще защищать и откатывать.

Выбор определяет owner: L4 metadata контролирует сетевой балансировщик, L7 header — HTTP edge, packet source — routing plane. Выбирайте механизм, чей owner действительно находится в вашей зоне изменений.

Выбор способа сохранения IP: PROXY v2, X-Forwarded-For или externalTrafficPolicy Local

NGINX: принимаем PROXY protocol только от доверенного LB

В NGINX два шага независимы. Параметр proxy_protocol у listen заставляет сокет ожидать header. Модуль realip затем решает, можно ли заменить $remote_addr значением из него. Без allowlist адрес клиента превращается в пользовательский ввод.

ngx_http_realip_module сохраняет исходный peer в $realip_remote_addr, а $remote_addr после обработки содержит effective IP. Логируйте оба: одинаковые значения у трафика через LB укажут на неприменённый realip.

CIDR в примере нельзя копировать буквально. Он должен соответствовать вашим LB, а не всей RFC1918-сети. Перед reload проверьте, собран ли HTTP realip module, затем отправьте canary через LB и прямой запрос к backend — второй обязан быть заблокирован.

После восстановления адреса не добавляйте старую пользовательскую XFF-цепочку автоматически. Если NGINX становится authoritative edge, безопаснее сформировать header из проверенного $remote_addr по явному контракту.

Отдельно наблюдайте соединения без header и malformed header. Резкий рост после rollout часто означает, что health checks или один из upstream LB ходит на новый порт по старому протоколу.

Что именно проверять в NGINX

Physical peer должен совпадать с адресом доверенного load balancer.
Восстановленный адрес совпадает с canary-клиентом и становится ключом limiter.
Прямое подключение не принимает пользовательский PROXY header.
nginxnginx.conf
http {
  set_real_ip_from 10.20.0.0/24;
  real_ip_header proxy_protocol;
  log_format identity '$request_id peer=$realip_remote_addr proxy=$proxy_protocol_addr effective=$remote_addr';
  server {
    listen 443 ssl proxy_protocol;
    access_log /var/log/nginx/llm_identity.log identity;
    location /v1/ {
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $remote_addr;
      proxy_pass http://llm_upstream;
    }
  }
}
PROXY protocol от доверенного L4 LB
NGINX принимает данные PROXY protocol от доверенного балансировщика

X-Forwarded-For: очищайте цепочку, а не выбирайте первый IP

Клиент может сам прислать X-Forwarded-For. Внешний proxy должен удалить header и создать его заново либо добавить адрес так, чтобы следующий hop мог отбросить доверенную часть. Правило «брать первый IP» ломается, как только атакующий подставляет значение слева.

В NGINX сочетание real_ip_header X-Forwarded-For, точного set_real_ip_from и real_ip_recursive on ищет последний недоверенный адрес. Но результат верен только при полном списке proxies.

Для цепочки CDN → WAF → ingress → API составьте контракт: какой hop удаляет пользовательский header, какой добавляет адрес и какой вычисляет effective IP. Сохраняйте версию trust list рядом с request ID.

Если пропустить ingress, приложение увидит его адрес. Если доверить лишний CIDR, пользователь сможет влиять на identity. Эти два failure mode выглядят одинаково в одном поле client_ip, поэтому physical peer обязателен.

Rate limits и квоты становятся полезными после этого шага: дорогой LLM-запрос нельзя честно ограничивать по IP, пока происхождение IP не доказано.

nginxrealip-xff.conf
set_real_ip_from 10.30.0.0/24;
set_real_ip_from 10.31.0.0/24;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
log_format xff '$request_id peer=$realip_remote_addr xff="$http_x_forwarded_for" effective=$remote_addr';
XFF на доверенной L7-границе

Envoy: listener filter раньше HTTP-фильтров

В Envoy PROXY protocol разбирается listener filter-ом до HTTP filter chain. После успешного разбора downstream remote address используется access log, RBAC и rate-limit integration. Обычное соединение без обязательного header отклоняется.

Документация Envoy описывает v1/v2 и counters для found, malformed, disallowed и missing. Опция allow_requests_without_proxy_protocol ослабляет контракт и годится только для полностью доверенного источника.

Proxy Protocol filter не равен Original Source filter. Первый извлекает координаты клиента. Второй использует downstream address как source upstream-соединения и требует capabilities и policy routing. Для IP-aware limiter чаще достаточно первого.

Canary доказывает три слоя: filter принял header; effective address попал в access log; приложение и limiter приняли то же значение. Счётчик found без application outcome ещё не успех.

Добавьте отрицательный контроль: соединение без header и соединение с запрещённой версией должны вести себя предсказуемо. Иначе permissive listener переживёт миграцию и станет постоянной дырой.

Готов ли Envoy listener к canary?

yamlenvoy-listener.yaml
listener_filters:
- name: envoy.filters.listener.proxy_protocol
  typed_config:
    "@type": type.googleapis.com/envoy.extensions.filters.listener.proxy_protocol.v3.ProxyProtocol
    disallowed_versions:
    - V1
    stat_prefix: llm_edge
Строгий Proxy Protocol listener filter
Envoy проверяет метаданные соединения перед маршрутизацией к LLM inference

Kubernetes: source IP без SNAT имеет цену

У Service с externalTrafficPolicy: Cluster пакет может попасть на node без нужного Pod и быть переслан с SNAT. Приложение увидит node address. Local ограничивает маршрутизацию локальными endpoints и сохраняет source IP, но node без endpoint отбрасывает трафик.

Официальный tutorial Kubernetes показывает компромисс. Для LoadBalancer Kubernetes выделяет healthCheckNodePort, чтобы внешний LB исключал nodes без локальных endpoints.

Представьте два gateway Pod на десяти nodes. Local сохранит IP, но только два узла примут запрос. Если LB шлёт на все десять, восемь путей становятся чёрной дырой. Проверяйте health-check membership и topology spread вместе.

Если LB уже умеет PROXY v2, иногда лучше передать metadata и оставить Cluster routing. Local оправдан, когда packet-level source IP нужен network policy или L4 audit, но тогда availability зависит от распределения Pod.

Архитектура private AI API помогает выбрать границу. Новое железо здесь не исправит неверный health check: сначала доказательство маршрута, затем capacity decision.

yamlservice.yaml
apiVersion: v1
kind: Service
metadata:
  name: llm-gateway
spec:
  type: LoadBalancer
  externalTrafficPolicy: Local
  selector:
    app: llm-gateway
  ports:
  - name: https
    port: 443
    targetPort: 8443
Source IP с node-local routing

Негативный контроль: докажите, что IP нельзя подделать

Положительный тест показывает, что механизм работает. Негативный — что им не может воспользоваться клиент. Отправьте через публичный endpoint поддельный XFF и убедитесь, что edge заменил его. Затем попробуйте backend напрямую: соединение блокируется до приложения.

Для PROXY protocol используйте canary из доверенной сети и источник вне allowlist на staging listener. Ожидаемый результат: trusted LB меняет effective IP, недоверенный peer не получает такой возможности.

Третий тест — рассинхронизация. Подайте разные адреса в PROXY metadata и XFF. Заранее выберите authoritative слой и создайте событие при конфликте. Молчаливый выбор превращает смену topology в уязвимость.

WAF, limiter и audit обязаны использовать одну identity. Атакующий найдёт самый слабый consumer. Материал про firewall, WAF и DDoS полезен как карта разных controls, но не заменяет trust boundary.

Повторяйте negative control после каждого изменения CIDR, LB pool или ingress. Это короткий synthetic test, который часто ценнее ещё одного dashboard: он проверяет именно невозможность обхода.

Какой тест поймает ошибку доверия?

Проверка реального IP от TCP peer до rate limit и результата LLM

Наблюдаемость: храните доказательство, а не только итоговый IP

Один столбец client_ip удобен, но плох для расследования. Минимум — connection peer, asserted address, effective address, mechanism, trust-list version и request ID. Для HTTP сохраните исходную XFF-цепочку в защищённом логе, но не используйте её напрямую как ключ.

Не превращайте каждый IP в label Prometheus: кардинальность раздует series. Метрики считают accepted, missing, malformed, spoof attempt и mismatch, а конкретные адреса остаются в logs и traces с ограниченным retention.

Свяжите signal с outcome LLM API: 401/403/429, active streams, TTFT и завершённые ответы. После исправления identity 429 может вырасти правильно, потому что обход квот прекратился. Сравнивайте tenant behavior.

Различайте быстрый отказ до upstream и обрыв начатого stream. Первый защищает GPU, второй уже потратил compute. Runbook про Envoy overload раскрывает эту границу.

Для privacy сократите retention адресов и ограничьте доступ к raw chain. Доказательство доверия не означает бессрочное хранение персональных сетевых данных.

Rollout и rollback без потери контроля доступа

Начинайте с отдельного canary listener. Baseline использует старый путь, а canary пишет расширенный identity log и shadow-решение limiter. Не применяйте блокировки сразу: сначала сравните решения и причины расхождений.

Порядок rollout следует зависимости. Сначала sender формирует PROXY header или очищает XFF, затем receiver включает parsing на отдельном порту, после этого приложение меняет limiter key. Обратный порядок даёт handshake errors либо общий адрес proxy.

Stop conditions: рост malformed, missing identity на доверенном пути, mismatch gateway/app, потеря health-check nodes или рост незавершённых streams. У каждого условия должны быть owner и команда возврата.

Rollback симметричен: вернуть трафик на baseline, восстановить прежний ключ, проверить тот же canary и только затем отключать parser. Не оставляйте публичный permissive listener «на всякий случай».

Dedicated edge имеет смысл после доказанной причины: он даёт контроль firewall, версий и change window. Но новый сервер не исправляет spoofable header, неполный allowlist или небезопасную retry policy.

Проверка перед переключением трафика

Canary и baseline для безопасного внедрения доверенного client IP

Итог: реальный IP начинается с доверенного пути

Надёжный client IP не появляется от одной директивы. Это цепочка: известный TCP peer, защищённый канал от trusted proxy, однозначный механизм, effective address в gateway и тот же ключ в приложении, аудите и limiter.

Default прост: L4 LB — PROXY v2 на закрытом listener; L7 — очищенный XFF с точным allowlist; Kubernetes Local — только когда вы готовы ограничить topology. Во всех вариантах bypass невозможен.

Не покупайте edge-сервер как лекарство от неверного trust list. Выделенный VPS или dedicated gateway уместен, когда нужны собственные firewall rules, контролируемые версии NGINX/Envoy и воспроизводимый canary.

Следующий шаг — протянуть один запрос через все hops. Зафиксируйте peer, asserted и effective IP, повторите с подделанным header и через rollback. Только после обеих проверок включайте реальные квоты.

Зафиксируйте эту проверку как регулярный regression test: после смены балансировщика, CIDR, ingress-контроллера или сетевой политики прогоняйте тот же positive/negative canary. Такой контроль быстро замечает drift до того, как он превратится в ложные блокировки или обход лимитов.

HTTP/2 GOAWAY и gRPC keepalive для LLM API: как найти обрывы и настроить graceful drain
Сетевые протоколы

HTTP/2 GOAWAY и gRPC keepalive для LLM API: как найти обрывы и настроить graceful drain

Практический runbook для LLM API: отличаем штатный HTTP/2 GOAWAY от аварии, находим владельца соединения, согласуем gRPC keepalive и проверяем retry, drain и SLO.

Какой VPN-протокол выбрать?
Сетевые протоколы

Какой VPN-протокол выбрать?

VPN-протоколы являются ключевым элементом сетевой безопасности, но какой выбрать? В этом обзоре мы сравниваем OpenVPN, WireGuard и IPsec, оценивая их скорость, уровень защиты, простоту настройки и совместимость. Узнайте, какой протокол подойдёт именно вам 🚀

Сетевые протоколы передачи данных
Сетевые протоколы

Сетевые протоколы передачи данных

Главная функция протоколов – обеспечение стабильного обмена информацией между устройствами под управлением различных УС, утилит и программ.