Управление ролями (RBAC)
Контроль доступа к ресурсам Meridian через роли. Три встроенные роли с фиксированной матрицей разрешений, защита от self-lockout и инвалидация сессий при смене роли.
Обзор
RBAC (Role-Based Access Control) в Meridian отвечает за авторизацию — что разрешено делать аутентифицированному пользователю. Аутентификация (кто пользователь) — отдельный слой; RBAC решает, какие из эндпоинтов API и разделов панели управления ему доступны.
Каждый пользователь имеет ровно одну роль, и роль определяет матрицу разрешений вида «ресурс × операция». Когда HTTP-запрос приходит на защищённый эндпоинт, middleware authz.Require(resource, operation) сверяет роль пользователя с матрицей; если разрешения нет — возвращается 403 Forbidden.
Ключевые свойства:
- Три встроенные роли с фиксированными разрешениями —
admin,auditor,user_manager. Создание собственных ролей и редактирование матрицы из UI или API не предусмотрено. - Защита от self-lockout — нельзя понизить или удалить последнего администратора, нельзя изменить или удалить собственную учётную запись.
- Инвалидация сессий при смене роли — после смены роли все сессии пользователя сбрасываются и он вынужден войти заново с новыми разрешениями.
Три роли
| Роль | Разрешения |
|---|---|
Admin (admin) | Полный набор операций (View, Read, Create, Update, Delete, Download) на всех ресурсах. |
Auditor (auditor) | Только чтение (View, Read, Download) на всех ресурсах. Не может ничего изменять. |
User Manager (user_manager) | Полный набор операций на Customers, Teams, VirtualKeys, Governance. Только чтение на остальных ресурсах. Доступ к ресурсу RBAC отсутствует — User Manager не может управлять ролями других пользователей. |
Роли соответствуют типичным ролям enterprise-среды: Admin — для платформенной команды, Auditor — для compliance / security, User Manager — для команды governance, которая управляет квотами и виртуальными ключами без доступа к платформенным настройкам.
Матрица разрешений
Разрешение — это пара «ресурс × операция». Шесть операций:
| Операция | Назначение |
|---|---|
View | Доступ к UI-разделу (видимость пункта меню, страницы). |
Read | Чтение данных через API (GET-эндпоинты). |
Create | Создание нового объекта (POST). |
Update | Изменение существующего объекта (PUT/PATCH). |
Delete | Удаление объекта (DELETE). |
Download | Экспорт данных (например, скачивание лога). |
Список ресурсов определяется в framework/authz/authz.go. Часть ресурсов скрывается feature-flag'ами: на этапе сборки можно отключить видимость отдельных подсистем (например, MCP Gateway, Plugins, Adaptive Routing, Audit Logs, Guardrails, User Provisioning, Prompt Deployments). API ответ GET /api/rbac/roles возвращает только включённые ресурсы — FilterPermissions отбрасывает выключенные перед отдачей в UI.
Базовые ресурсы (в текущей сборке):
Cluster, Settings, Users, Logs, Observability, VirtualKeys, ModelProvider, Customers, Teams, RBAC, Governance, RoutingRules, PIIRedactor, PromptRepository.
Если в вашей сборке включён, например, EnableMCPGateway, в матрице появится ресурс MCPGateway. Если выключен — этот ресурс не будет виден ни в API, ни в UI, и middleware authz.Require(ResourceMCPGateway, ...) всё равно отработает корректно (проверка ведётся по строковой константе ресурса в коде).
Назначение роли пользователю
- Перейдите в Governance → Roles & Permissions.
- Раскройте нужную роль — увидите список её пользователей.
- Напротив пользователя нажмите выпадающий список и выберите новую роль.
- После сохранения сессии этого пользователя инвалидируются — он войдёт заново с обновлёнными правами.

В панели управления нет создания собственных ролей и нет редактирования матрицы разрешений — роли и их разрешения зашиты в коде.
curl -X PUT http://localhost:8080/api/users/{user_id}/role \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <admin_token>" \
-d '{
"role": "auditor"
}'Допустимые значения role: admin, auditor, user_manager.
Возможные ошибки:
| Код | Причина |
|---|---|
400 Bad Request | Неизвестное значение role, попытка изменить собственную роль, попытка понизить последнего admin. |
404 Not Found | Пользователь с таким ID не найден. |
403 Forbidden | У вызывающего нет права Update на ресурсе RBAC (или Users). |
Безопасность
Запрет понижения последнего admin'а. Сервер вычисляет количество пользователей с ролью admin под FOR UPDATE-локом и отказывает в смене роли, если демоция оставит систему без admin'ов. Тот же лок защищает от TOCTOU-гонки между двумя одновременными запросами понижения.
Запрет смены и удаления собственной учётной записи. API отвергает PUT /api/users/{id}/role и DELETE /api/users/{id}, если в качестве id передан вызывающий пользователь. Это защита от случайного блокирования доступа к собственному кабинету.
Инвалидация сессий при смене роли. После успешного PUT /api/users/{id}/role все сессии этого пользователя удаляются — следующий запрос от него вернёт 401 Unauthorized, и он переаутентифицируется. Без этого старые токены продолжали бы давать доступ по старой роли.
Поведение при отключённой аутентификации. Если в запросе нет роли (auth полностью выключена), middleware authz.Require пропускает запрос дальше: за блокировку неаутентифицированных запросов отвечает auth-middleware, а не authz. Если роль установлена в пустую строку — это считается некорректным состоянием и запрос отвергается с 403 Forbidden.
Управление пользователями
Список пользователей:
curl http://localhost:8080/api/usersПолучить пользователя:
curl http://localhost:8080/api/users/{user_id}Создать пользователя:
curl -X POST http://localhost:8080/api/users \
-H "Content-Type: application/json" \
-d '{
"username": "alice.smith",
"display_name": "Alice Smith",
"password": "S3cure-Passw0rd!",
"role": "user_manager"
}'Требования к полям:
| Поле | Требования |
|---|---|
username | Только буквы, цифры, дефис, подчёркивание и точка. Не более 255 символов. Уникален. |
password | Минимум 8 символов. Хешируется на сервере. |
role | admin, auditor или user_manager. |
display_name | Опционально; если не указан — берётся username. |
Изменить отображаемое имя:
curl -X PUT http://localhost:8080/api/users/{user_id} \
-H "Content-Type: application/json" \
-d '{
"display_name": "Alice S."
}'PUT /api/users/{id} меняет только display_name. Смена username или password через этот эндпоинт не поддерживается.
Смена собственного пароля:
curl -X PUT http://localhost:8080/api/users/me/password \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <user_token>" \
-d '{
"current_password": "old-password",
"new_password": "new-S3cure-Passw0rd!"
}'Удалить пользователя:
curl -X DELETE http://localhost:8080/api/users/{user_id}Удаление защищено теми же правилами, что и смена роли: нельзя удалить себя, нельзя удалить последнего admin'а.
Получить список ролей и их матрицу
curl http://localhost:8080/api/rbac/rolesОтвет возвращает три роли, в каждой — описание, матрицу разрешений (после feature-flag-фильтрации) и список присвоенных пользователей:
{
"roles": [
{
"name": "admin",
"display_name": "Admin",
"description": "Full control of everything",
"permissions": {
"Cluster": ["View", "Read", "Create", "Update", "Delete", "Download"],
"VirtualKeys": ["View", "Read", "Create", "Update", "Delete", "Download"],
"Users": ["View", "Read", "Create", "Update", "Delete", "Download"]
},
"users": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"username": "alice.smith",
"display_name": "Alice Smith"
}
]
},
{
"name": "auditor",
"display_name": "Auditor",
"description": "Read-only access to all resources",
"permissions": { "...": "..." },
"users": []
},
{
"name": "user_manager",
"display_name": "User Manager",
"description": "Manage customers, teams, virtual keys, and governance; read-only access to other resources",
"permissions": { "...": "..." },
"users": []
}
]
}Эта ручка нужна UI для отрисовки страницы Roles & Permissions и используется как справочник для самостоятельной интеграции с внешними панелями (например, чтобы понять, кто из пользователей сейчас имеет роль admin).
Телеметрия
Полноценный мониторинг шлюза Meridian на основе Prometheus с кастомными метриками и метками. Автоматический сбор HTTP-метрик и метрик upstream-провайдеров без влияния на латентность запросов.
Семантическое кеширование
Интеллектуальное кэширование ответов на основе семантической близости. Снижает стоимость и задержку за счёт выдачи закэшированных ответов на семантически близкие запросы.