Пользователи и ключи
Политика живёт на человеке, ключи её наследуют. Это главное, что стоит понять про эту страницу.
Страница /keys устроена по людям, а не по ключам: карточка на человека, внутри
— его ключи. Так и организовано то, о чём эта страница: наценка и потолок числа
ключей задаются один раз на человека, и плоский список ключей делал владельца
колонкой, а вопрос «сколько ему можно» оставлял на другой странице. Ключи без
владельца — служебные — идут отдельным разделом в конце: наследовать наценку им
не от кого.
/settings остаётся про то, кто может войти: создание записей, роли, пароли,
каталог. Наценка, потолок, метки и сами ключи — здесь.
Учётная запись¶
| Поле | Смысл |
|---|---|
| Адрес и имя | вход и подпись в интерфейсе |
| Роль | admin видит панель; user — только свои ключи и расход |
| Множитель стоимости | наценка на все его ключи |
| Ключей не больше | потолок; пусто — общий лимит, ноль — ни одного |
| Всего запросов в минуту | на все ключи вместе |
| Всего токенов в минуту | на все ключи вместе |
| Общий бюджет | на все ключи вместе, с периодическим сбросом |
| Метки | визуальные ярлыки, гейт их не читает |
Источник учётной записи — локальный пароль (Argon2id) или каталог (см. Вход через каталог).
Последнего администратора нельзя ни разжаловать, ни удалить: иначе панель осталась бы без входа, а путь восстановления — ручной INSERT.
Множитель стоимости¶
Наценка поверх цены модели. Её применяет гейт при расчёте запроса, поэтому она попадает и в журнал, и в накопленный расход, и в бюджет, который с ним сравнивается — все три говорят в одних единицах.
Одна на человека, а не на ключ. Иначе у одного человека с ключом на ноутбуке и ключом в CI были бы две разные цены, и счёт зависел бы от того, каким credential сделан запрос. Ключ переспорить наценку не может.
Служебный ключ без владельца тарифицируется по себестоимости: наследовать не от кого.
Ноль запрещён. Ключ, который никогда не накапливает расход, выглядит точно как отсутствующая тарифная карта, а «бесплатно» в этой панели уже выражается ценой ноль.
Владельцу наценка не показывается. Он видит уже умноженную цену — и в валюте отображения, если она задана.
Ключи¶
Один человек — сколько угодно ключей, до потолка. Ключ на машину или на задачу: потерянный отзывается сам по себе, не трогая остальные.
| Поле | Смысл |
|---|---|
| Название | видно в журнале |
| Владелец | откуда берётся наценка; пусто — служебный ключ |
| Запросов в минуту (rpm) | пусто — без ограничения, ноль — запретить всё |
| Токенов в минуту (tpm) | то же |
| Бюджет | в долларах; при исчерпании 402 |
| Сброс бюджета | ежедневно / еженедельно / ежемесячно |
| Действует до | срок действия |
| Разрешённые провайдеры | пусто — все |
| Разрешённые модели | пусто — все |
Пусто и ноль — намеренно разные значения: пусто снимает потолок, ноль ставит его в «ничего нельзя».
Сырое значение ключа показывается один раз, при создании. В базе только SHA-256: утёкшая база не воспроизводится против гейта. Потерянный ключ не восстанавливается — только перевыпускается, и старое значение перестаёт работать в тот же момент.
Почему SHA-256, а не медленный хеш: это 256 бит машинной энтропии, а не человеческий пароль — низкоэнтропийного пространства перебора, от которого защищал бы KDF, здесь нет. А проверять приходится на каждом запросе.
Ограничения доступа¶
Проверяются по уже разрешённой цели, поэтому работают и с префиксом, и без.
Правило можно написать любым из двух способов — gpt-4o или openai/gpt-4o —
и обойти его, написав запрос иначе, не получится.
Регистр не важен, см. Адресация моделей.
У ключа два списка моделей, и они складываются, а не заменяют друг друга:
| Список | Кто задаёт | Где |
|---|---|---|
allowed_models |
администратор | /keys |
owner_allowed_models |
владелец ключа | «Мои ключи» |
Действующий набор — пересечение, где пустое с любой стороны означает «без ограничения». Владелец сужает выданное, но не расширяет: модель, которой ему не выдали, отклоняется с указанием, какая именно.
Два списка, а не один, по конкретной причине. Если бы владелец писал в тот же столбец, то, сузив ключ до одной модели, он потерял бы разрешение на остальные: его собственное сужение стало бы потолком, и вернуть модель, которую администратор разрешил, было бы нечем. С rpm, tpm и бюджетом этого не возникает — там потолок задан политикой самообслуживания, а на ключе лежит действующее значение.
Общие лимиты человека¶
Лимиты на ключе отвечают на вопрос «сколько можно этой машине». Вопрос «сколько можно этому человеку» они не закрывают: ключ на ноутбуке, ключ в CI и ключ в скрипте по отдельности вписываются в свои бюджеты, а вместе тратят втрое. Поэтому у учётной записи есть свои rpm, tpm и бюджет, считаемые по сумме всех её ключей.
Оба уровня действуют одновременно. Запрос проходит, если проходит и по ключу, и по человеку. Отказ называет сработавший уровень:
API key "ноутбук" exceeded its request-per-minute limit
account "Разработчик" exceeded its request-per-minute limit across all of its keys
account "Разработчик" has reached its total spending limit across all of its keys
Без этого «429» пришлось бы разбирать вслепую — на ключе-то лимит ещё есть.
Накопленный расход человека лежит отдельным столбцом на учётной записи, а не считается суммой по ключам на каждом запросе: гейт и так читает эту строку одним JOIN при проверке ключа, и наращивает оба счётчика одним оператором — двумя осталось бы окно, в котором ключ списан, а человек ещё нет, и это ровно то окно, через которое лимит и проскакивает.
Общий бюджет сбрасывается по своему расписанию: человек на месячном лимите может держать ключи со недельным сбросом. Обнулить его вручную можно кнопкой в его настройках — расход по отдельным ключам при этом остаётся, это разные потолки.
Служебный ключ без владельца ничего этого не наследует: наследовать не от кого.
Владелец видит свои общие лимиты на «Моих ключах» — иначе отказ «исчерпан общий бюджет» был бы необъясним. Опустить их со своей стороны он не может: это потолок администратора на него целиком, а ограничивать он может отдельные ключи.
Лимит rpm и tpm¶
rpm проверяется до запроса. tpm — по уже потраченному за минуту, поэтому
один запрос может его превысить: стоимость запроса неизвестна до его завершения,
а отказывать начинать работу, цена которой ещё не знаема, — хуже.
Окно фиксированное, минутное: две целых числа на ключ, что имеет значение, когда лимитер стоит перед каждым запросом. Пограничный эффект — до двойной скорости на стыке окон — приемлем для квоты, которая существует чтобы остановить разогнавшегося клиента, а не чтобы точно формировать трафик.
Самообслуживание¶
Если включено в настройках, человек без прав администратора выпускает ключи сам, на странице «Мои ключи».
Ключ выпускается с потолками из политики самообслуживания: rpm, tpm, бюджет и период сброса. Лимиты берутся из политики, а не из формы — ключ, который человек выдаёт себе, не должен быть ключом, размер которого он же и выбирает.
Владелец может опустить лимиты своего ключа ниже выданных, но не поднять. Попытка поднять отклоняется, а не подрезается молча: тихо записать другое число, чем набрано, — так человек и приходит к уверенности в лимите, которого у него нет. Пустое поле означает «сколько разрешено», а не «без ограничения».
Владелец может и удалить свой ключ: держать несколько имеет смысл только если один можно отдать. История запросов при этом остаётся — она денормализована.
Сужение по моделям тоже в его руках: рядом с лимитами есть список моделей с
чипами того, что ему выдано (а если не выдано ничего конкретного — того, что
доступно через его провайдеров). Очистка поля возвращает всё выданное: потолок
администратора никуда не девался. Каталог /v1/models сужается вместе с этим —
клиент видит ровно то, чем ключ может пользоваться.
Потолок числа ключей один и тот же, выпускаете ли вы ключ себе или его выдаёт администратор: обойти его через чужие руки нельзя. Администратору, которому нужен ещё один, следует поднять потолок человеку — так остаётся один ответ на вопрос «сколько ему можно».
Что видит не-администратор¶
Страница «Мои ключи»: свои ключи и их лимиты, расход за 30 дней, разбивка по моделям и по дням, последние запросы со временем и скоростью, цены доступных моделей — уже с наценкой и в валюте отображения. Плюс возможность опустить лимиты и сузить ключ по моделям.
Ни наценки, ни чужих ключей, ни провайдеров, ни журнала целиком. Каждый запрос этой страницы ограничен ключами, которыми владеет вошедший.