Files
SQS-service/doc/architecture/tenant-isolation.md
T

4.3 KiB
Raw Blame History

Разделение доступа пользователей (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-Credential query 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.gotenantQueueKey(), countTenantQueues()
  • app/tenant/tenant_store.goTenantStore с тремя индексами (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) → доступ только к своим очередям