4.3 KiB
Разделение доступа пользователей (Tenant Isolation)
Дата: 2026-04-13
Аутентификация (два пути)
1. AWS SigV4 (для SQS-клиентов)
Стандартная AWS-подпись. В заголовке Authorization передаётся AccessKey формата SSAK-{hex}, по нему находится тенант в TenantStore.
AccessKey:SSAK-{12 hex bytes}SecretKey:{64 hex chars}(32 random bytes)- Заголовок:
Authorization: AWS4-HMAC-SHA256 Credential={AccessKeyId}/{date}/{region}/sqs/aws4_request, SignedHeaders=..., Signature=... - Presigned URLs тоже поддерживаются (через
X-Amz-Credentialquery parameter)
2. JWT (для UI-консоли)
Токен от облачной платформы Nubes. При первом входе тенант автоматически создаётся из JWT-клейма sub. Возвращаются access_key + secret_key.
Клеймы JWT:
sub— UUID пользователя (используется для идентификации)email— email пользователяexp— время истеченияiss— издатель
Генерация TenantID из JWT: SHA256(sub) → первые 8 байт → hex → "sless-{16hex}".
Валидация подписи JWT не делается (trusted perimeter). Проверяется структура, exp, и через PingNubesAPI() — принимает ли облачный API этот токен.
Изоляция очередей
Каждая очередь в памяти хранится с ключом "{accessKey}:{queueName}":
Очередь тенанта A: SSAK-aaa:my-queue
Очередь тенанта B: SSAK-bbb:my-queue
Все операции (SendMessage, ReceiveMessage, ListQueues и т.д.) строят ключ через tenantQueueKey(tenant.AccessKey, queueName) — тенант берётся из контекста запроса. Тенант A физически не может обратиться к ключу SSAK-bbb:*, потому что его AccessKey другой.
Файлы:
app/gosqs/tenant_helpers.go—tenantQueueKey(),countTenantQueues()app/tenant/tenant_store.go—TenantStoreс тремя индексами (byID,byAccessKey,bySub)
TenantStore — три индекса
byID map[string]*Tenant — для admin API: GetByID(tenantID)
byAccessKey map[string]*Tenant — для SQS auth: GetByAccessKey(accessKey)
bySub map[string]*Tenant — для JWT auth: GetBySub(sub)
Защита от IDOR в UI
В jwtMiddleware (admin.go) проверяется что tenantID из URL совпадает с tenantID из JWT-токена. Если не совпадает — 403 Forbidden.
Управление тенантами (admin API)
| Метод | Путь | Назначение | Доступ |
|---|---|---|---|
| POST | /admin/tenants |
Создать тенанта | Bearer token (admin) |
| GET | /admin/tenants |
Список тенантов | Bearer или JWT (UI видит только себя) |
| GET | /admin/tenants/{id} |
Детали тенанта | Bearer или JWT |
| DELETE | /admin/tenants/{id} |
Удалить тенанта + все очереди | Bearer token (admin) |
| GET | /admin/tenants/{id}/queues |
Очереди тенанта | Bearer или JWT |
SecretKey показывается только при создании. Потом получить нельзя.
Роутинг и защита эндпоинтов
/health → PUBLIC
/metrics → PUBLIC
/admin/** → Bearer token auth
/ui/api/auth → PUBLIC (вход через JWT)
/ui/api/** → JWT auth
/ (SQS API) → AWS SigV4 auth
Схема потока запроса
HTTP запрос
↓
AuthMiddleware.extractAccessKeyID()
↓
TenantStore.GetByAccessKey(accessKey)
↓
verifySigV4 (проверка подписи)
↓
context.WithValue(TenantContextKey, tenant)
↓
actionHandler (SendMessage, ReceiveMessage, ...)
↓
tenantQueueKey(tenant.AccessKey, queueName) → доступ только к своим очередям