Гайд · TNWS AI
Почему --api-key в vLLM не защищает весь сервер и как проверить схему доступа
Разбираем границы защиты ключом, локальную привязку и необходимость ограничить все маршруты на уровне сети.
Задача и применимость
Вопрос читателя: «почему api key vLLM не защищает все endpoints invocations». Для vLLM OpenAI-compatible server на 20 сентября 2026 года. Руководство рассматривает безопасное развёртывание собственного сервера, а не получение доступа к чужому. Все проверки проводятся только на подконтрольном локальном экземпляре.
Для воспроизводимости запишите фактическую версию установленного vLLM, модельный checkpoint и параметры запуска. Путь /models/your-chat-checkpoint либо /models/your-embedding-checkpoint в команде ниже — заполнитель, а не реальный файл. Наличие GPU, объём памяти и условия лицензии весов проверяются до запуска. Демонстрация не утверждает, что ответ модели заранее известен по буквам.
Проверенные возможности
Официальная документация предупреждает: --api-key либо VLLM_API_KEY аутентифицирует только пути с префиксами /v1, /v2 и /inference; другие маршруты на том же сервере могут быть незащищены. Особо упомянут /invocations, который предоставляет аналогичные возможности инференса. Нельзя считать один флаг полноценной защитой всего HTTP-сервера.
Пошаговая процедура
- Разверните тестовый сервер на loopback, не публикуя порт в интернет.
- Запишите список всех маршрутов, которые доступны вашим клиентам.
- Для /v1 проверьте отрицательный тест без ключа и положительный с тестовым ключом.
- Для остальных маршрутов проектируйте сетевое ограничение или reverse proxy.
- Проведите аудит правил доступа к каждому пути перед внешним развёртыванием.
Команда для тестового запуска на локальном адресе (подставьте законно полученный checkpoint):
vllm serve /models/your-chat-checkpoint --host 127.0.0.1 --port 8000 --api-key YOUR_TEST_TOKEN
Готовый запрос и контроль ответа
В приведённом фрагменте используется стандартная библиотека Python и простой общий помощник для отправки JSON. Подставьте при необходимости Bearer-токен через защищённую переменную окружения и проверьте, что ваш сервер его ожидает.
import json, urllib.request
BASE = "http://127.0.0.1:8000"
def call(path, payload):
data = json.dumps(payload, ensure_ascii=False).encode("utf-8")
request = urllib.request.Request(BASE + path, data=data,
headers={"Content-Type": "application/json"}, method="POST")
with urllib.request.urlopen(request, timeout=120) as reply:
return json.load(reply)
import urllib.error
url = "http://127.0.0.1:8000/v1/models"
try:
urllib.request.urlopen(url, timeout=5)
except urllib.error.HTTPError as error:
print("Без ключа статус:", error.code)
request = urllib.request.Request(url, headers={
"Authorization": "Bearer YOUR_TEST_TOKEN"})
with urllib.request.urlopen(request, timeout=5) as reply:
print("С ключом:", reply.status, "моделей:",
len(json.load(reply).get("data", [])))
Пример входа и ожидаемого результата
Вход — два GET /v1/models к собственному серверу: первый без тестового ключа, второй с ним. Ожидается отказ первому при включённой защите и успешный ответ второму. Эти два ответа проверяют только /v1, а не безопасность остальных путей; исследование охвата проводится конфигурацией прокси.
Как интерпретировать результат
Распространённая ошибка — поднять vLLM с --api-key на интерфейсе 0.0.0.0 и решить, что все пути защищены. Документация прямо говорит обратное; отдельные маршруты могут дать те же возможности инференса за пределами покрываемых префиксов. Не пытайтесь лечить проблему сложным секретом: секрет не работает там, где аутентификация маршрута не применяется. Безопаснее по умолчанию оставить bind на 127.0.0.1 и организовать доступ приложения через серверный backend с явным списком разрешённых путей.
Развёртывание без потери контекста
Reverse proxy должен проверять аутентификацию до всех внешне доступных маршрутов и, при необходимости, вовсе блокировать административные/диагностические пути. Протестируйте и GET, и POST на своём контуре с тестовыми учётными данными; не полагайтесь только на наличие заголовка Authorization в клиентском коде. Ротация ключа, журналы доступа и rate limiting нужны отдельно. Код здесь не демонстрирует обращение к незащищённому инференс-маршруту, чтобы не предлагать ложную схему доступа; контроль проводится через конфигурационный аудит.
Проверки качества и границы метода
Документируйте, какие процессы имеют доступ к порту 8000, как трафик шифруется между приложением и модельным сервером, и где хранится тестовый ключ. Не вставляйте реальный ключ в публикуемый код, журнал команд или пользовательский браузер. После обновления vLLM перечитайте таблицу защищённых маршрутов: покрытия API могут измениться. Перед открытием сервера запустите внутренний аудит правил reverse proxy и сетевых ACL, затем проверьте отказ на каждом неподтверждённом пути.
Даже правильная защита путей API не даёт разделения данных разных клиентов внутри пользовательского приложения. Если вы обрабатываете чат-истории или RAG-документы, проверяйте tenant и права на сервере приложения до отправки prompt в vLLM. Отказ /v1/models без ключа показывает лишь один положительный сигнал; его нельзя писать в отчёте как «вся система безопасна». Если вы не можете гарантировать закрытую сеть и прокси, не публикуйте модельный сервер напрямую.
Критерии готовности
- Отрицательный тест к /v1 выполнен локально.
- Остальные маршруты учтены в правилах прокси или закрытой сети.
- Секрет не попал в клиентский код.
Типичные ошибки и чего не делать
- Не считать --api-key защитой всех endpoints.
- Не открывать порт наружу сразу после локального теста.
- Не хранить ключ в публичном репозитории.
Частые вопросы
Защищает ли --api-key /v1?
Да, документация относит /v1 к покрываемым префиксам.
Защищает ли он все маршруты?
Нет.
Что нужно дополнительно?
Закрытая сеть и защита разрешённых путей на прокси.
Официальные источники
Частые вопросы
Защищает ли --api-key /v1?
Да, документация относит /v1 к покрываемым префиксам.
Защищает ли он все маршруты?
Нет.
Что нужно дополнительно?
Закрытая сеть и защита разрешённых путей на прокси.
Читайте также
Как извлечь JSON по схеме в vLLM через response_format
Схема для извлечения артикула и количества из текста: разбираем ответ и проверяем значения против исходника.
Как обработать named tool call в vLLM без произвольного выполнения кода
Требуем вызов одной безопасной функции, валидируем аргументы и не отдаём модели право запускать произвольные команды.
Как ограничить ответ vLLM вариантами choice при классификации заявок
Получаем одну из заранее разрешённых меток и отдельно проверяем, что классификация совпала с текстом обращения.
Комментарии
Пока тихо. Скажите первое слово