Почему обычной авторизации недостаточно

Пользователь может быть корректно аутентифицирован и иметь разрешение на функцию, но из-за ошибки получить документ другого клиента. AWS отдельно подчёркивает: tenant isolation - самостоятельный механизм, который ограничивает ресурсы контекстом tenant, а не побочный эффект login и roles.

Для LLM-релиза поверхность шире обычной базы: prompt, история, файлы, retrieval, память агента, cache и traces могут содержать данные клиента. Граница должна проходить через весь путь запроса.

1
trusted tenant context
N
слоёв повторной проверки
0
tenant IDs от модели

Что считать tenant в AI-продукте

Tenant - организационная граница владения данными, конфигурацией, бюджетом и политикой. Один tenant может включать много пользователей и рабочих пространств. Не путайте tenant, user, project и conversation: они решают разные задачи.

СущностьОтвечает заНе заменяет
TenantИзоляция, contract, billingUser permissions
UserActor и ролиОрганизацию-владельца
WorkspaceСовместную областьSecurity boundary без policy
ProjectКонфиг и бюджет use caseTenant isolation
ConversationКраткосрочный контекстДолговременную память

Tenant context создаётся только из доверенной identity

После аутентификации middleware проверяет membership пользователя, статус tenant и роли, затем создаёт неизменяемый request context. Клиент может выбрать организацию из разрешённого списка, но сервер повторно подтверждает связь. Модель и tool arguments не определяют tenant.

request_id: req_...
actor_id: usr_...
tenant_id: ten_...
workspace_id: ws_...
roles: [editor]
plan: business
data_region: eu
data_classes_allowed: [internal]
policy_version: tenant-policy-v7
budget_scope: project_...
source: verified_identity_token

Silo, pool и bridge: три модели изоляции

Silo

Выделенный stack или resource на tenant.

Pool

Общие resources, строгая policy и partition key.

Bridge

Общий compute, отдельные data resources.

Hybrid может держать большинство клиентов в pool, а регулируемые workloads - в silo. Продуктовый интерфейс и isolation contract при этом остаются едиными.

Как выбрать модель без догм

КритерийPoolSiloHybrid
Стоимость малого tenantНижеВышеПо tier
Blast radiusБольшеМеньшеВыборочно
Операционная сложностьPolicy сложнееFleet сложнееОбе модели
Performance isolationТребует quotasСильнееПо tier
ComplianceЗависит от контроляПроще объяснитьГибко

Выделенный resource не отменяет application authorization, а pool не означает слабую защиту, если policy enforced независимо и регулярно тестируется.

Control plane отделяется от data plane

Control plane управляет tenants, plans, entitlements, provider routing, keys, quotas и lifecycle. Data plane обрабатывает prompts, retrieval и inference. Рабочий запрос получает подписанный или проверенный snapshot политики; модель не обращается к административной базе напрямую.

  • Изменения plan и policy имеют версию.
  • Отключённый tenant блокируется до inference.
  • Data plane fail-closed при неизвестном context.
  • Кэш policy имеет короткий TTL и invalidation.
  • Административные действия идут в отдельный audit trail.

Tenant-aware запрос строится server-side

API не должен принимать произвольный tenant_id и затем использовать его в SQL или vector query. Trusted context добавляется после аутентификации. Repository и policy layer требуют context параметром, поэтому разработчик не может случайно выполнить глобальный запрос.

Every data operation requires TenantContext.
TenantContext cannot be constructed from request body or model output.
Repository adds tenant partition server-side.
Object ownership is checked after lookup.
Missing or conflicting tenant context = deny.
Cross-tenant admin access uses a separate audited workflow.

System prompts и конфигурация тоже tenant data

Клиентские инструкции могут раскрывать процессы, продукты и политику. Храните prompt templates с tenant_id, version, classification и owner. Общая базовая инструкция отделяется от tenant overlay; при сборке prompt runtime проверяет совместимость и entitlement.

  • Нельзя запросить prompt другого tenant по slug.
  • Секреты не вставляются в system prompt.
  • Prompt cache включает tenant и version в key.
  • Трассировка редактирует чувствительные инструкции.
  • Экспорт и удаление охватывают все версии.

RAG: фильтр применяется до retrieval

Запрет отфильтровать чужие chunks после поиска слишком поздний: ranking и метаданные уже могли повлиять на ответ. Query строится только внутри разрешённого namespace или обязательного tenant filter, который добавляет сервер. После retrieval каждый chunk повторно проверяется по ownership и policy.

1
namespace или partition tenant
2
проверки: query и result
TTL
для временного доступа

Namespace полезен, но не является всей авторизацией

Vector database namespace упрощает физическое и логическое разделение, однако приложение всё равно проверяет, какие namespaces доступны actor. Имя пространства нельзя получать от модели. Для shared knowledge отдельно задайте источник, лицензию, data class и право tenant на использование.

RAG isolation
  1. Namespace выбирает trusted runtime.
  2. Chunk metadata содержит tenant и source.
  3. Ingestion проверяет destination.
  4. Retrieval применяет mandatory filter.
  5. Results повторно проверяются.
  6. Cache key включает policy scope.
  7. Deletion удаляет vectors и derived artifacts.
  8. Cross-tenant negative tests запускаются в CI.

Conversation state и agent memory изолируются отдельно

Conversation ID не является секретом и не доказывает право доступа. Session lookup требует tenant и actor scope. Долговременная память хранит provenance, consent, TTL и область видимости: private user, workspace или tenant. Агент не может сам повысить visibility.

ПамятьKeyКонтроль
Conversationtenant + conversationMembership и ownership
User memorytenant + userPrivate by default
Workspace memorytenant + workspaceRole policy
Tenant knowledgetenant + sourceAdmin ingestion
Global knowledgeplatform + licensed sourceEntitlement

Cache - частый источник скрытой утечки

Semantic cache может вернуть похожий ответ другому клиенту, если key учитывает только текст вопроса. Включайте tenant, workspace, model, prompt, policy, retrieval corpus version и data classification. Общий cache разрешён только для действительно публичных данных и отдельного pipeline.

cache_scope = SHA256(
  tenant_id + workspace_id + actor_policy_hash
  + model_version + prompt_version
  + corpus_version + data_class
)

Public cache uses a separate explicit scope.
Never infer public status from absence of tenant_id.

API keys и provider credentials не принадлежат модели

Provider keys хранятся в vault и выдаются gateway через workload identity. Модель видит только разрешённые tools. Для BYOK зашифрованный ключ связывается с tenant, region и allowed providers; его нельзя вернуть через API, prompt или trace.

  • Service account вместо общего ключа разработчика.
  • Раздельные credentials по environment.
  • Rotation без изменения prompt.
  • Egress allowlist у gateway.
  • Per-tenant provider routing policy.
  • Аудит использования BYOK без логирования секрета.

Quotas защищают и бизнес, и соседей

Ограничивайте concurrency, RPM, TPM, daily budget, agent steps, file storage, vector count и batch jobs. Quota применяется до дорогой операции; расход резервируется, затем сверяется с фактическим usage. Лимиты каскадируются platform → tenant → project → user.

Admission

Проверяет entitlement и остаток.

Reserve

Worst-case budget до вызова.

Reconcile

Фактические tokens и refund.

Noisy neighbor лечится scheduling, а не только rate limit

Один tenant может занять worker pool длинными context requests или агентными loops, даже не превысив RPM. Используйте weighted fair queues, per-tenant concurrency, размерные классы задач, deadlines и backpressure. Интерактивный и batch-трафик получают разные pools или приоритеты.

РесурсИзоляцияСигнал
Model callsTenant TPM/RPMThrottle rate
WorkersFair concurrencyQueue age by tenant
Long contextSize class и budgetTokens per request
Agent loopsStep/deadline limitSteps per success
Vector searchQuery and storage quotaLatency by tenant

Metering начинается с неизменяемого события

Каждый model call, embedding, tool execution, storage change и human review создаёт usage event с tenant, project, request, provider, model, измерениями и pricing version. Событие идемпотентно и не редактируется; исправление создаёт adjustment.

event_id: evt_...
tenant_id: ten_...
project_id: prj_...
request_id: req_...
provider: ...
model_resolved: ...
input_tokens: ...
output_tokens: ...
cached_tokens: ...
tool_units: ...
pricing_version: price_...
occurred_at: ...
idempotency_key: ...

Billing сверяется, а не вычисляется из логов

Application logs могут теряться или дублироваться. Usage ledger принимает идемпотентные события, агрегирует их по billing period и сверяет с отчётом провайдера. Клиенту показывайте понятные продуктовые единицы и детализацию, не обещая, что внутренний token count всегда равен счёту провайдера.

  • Разделяйте measured usage и billed amount.
  • Фиксируйте pricing version.
  • Поддерживайте credits и adjustments.
  • Сверяйте provider invoice по model/project.
  • Alert на резкий рост tenant spend.
  • Не блокируйте критический workflow без grace policy.

Логи, traces и evals также tenant-aware

Trace содержит prompts, tool arguments и retrieved chunks, поэтому доступ к observability ограничивается так же строго, как к production data. Индексы логов, object storage и dashboards фильтруются по trusted tenant context. Для platform support нужен отдельный audited break-glass workflow.

Observability
  1. Tenant ID добавляет runtime.
  2. Payload redaction до экспорта.
  3. Dashboard query имеет mandatory scope.
  4. Trace links не являются bearer secrets.
  5. Eval dataset хранит provenance и consent.
  6. Support access ограничен временем и целью.
  7. Retention следует договору tenant.

Fine-tuning требует отдельного решения о данных

Нельзя автоматически использовать prompts всех клиентов для общего обучения. Зафиксируйте legal basis, consent, purpose, retention и возможность удаления. Microsoft рекомендует отдельно рассматривать tenant-specific, shared и tuned shared models и объяснять клиентам использование их данных.

МодельДанныеРиск
Shared baseБез tenant training dataОбщая inference capacity
Tenant-specificОдин tenantИзоляция artifacts и endpoint
Tuned sharedРазрешённый общий corpusMemorization и governance
RAG overlayTenant indexRetrieval isolation

Cross-tenant evals должны пытаться сломать границу

Позитивный тест «tenant A видит свой файл» недостаточен. Нужны отрицательные сценарии: подмена tenant_id, известный object ID другого клиента, похожий semantic query, poisoned cache, handoff агенту с другим scope, экспорт, удаление и восстановление.

Isolation eval suite
  1. Forged tenant и workspace IDs.
  2. Direct object reference другого tenant.
  3. RAG query на уникальную фразу соседа.
  4. Semantic cache collision.
  5. Conversation ID enumeration.
  6. Agent tool с чужим resource ID.
  7. Indirect prompt injection на смену namespace.
  8. BYOK reference другого tenant.
  9. Trace и export links.
  10. Удалённый tenant не остаётся в cache, vectors и backups по policy.

Lifecycle tenant: onboarding, migration, export и deletion

Onboarding создаёт policy, quotas, encryption scope, namespaces и billing account идемпотентно. Миграция между pool и silo сохраняет object IDs и блокирует двойную запись. Offboarding останавливает inference, отзывает keys, экспортирует разрешённые данные и запускает проверяемое удаление derived artifacts.

  1. Freeze или dual-read по утверждённому плану.
  2. Сделать inventory всех data stores.
  3. Перенести immutable snapshot.
  4. Проверить counts, hashes и permissions.
  5. Переключить routing atomically.
  6. Очистить старые cache и indexes.
  7. Подтвердить metering boundary.
  8. Сохранить audit evidence.

Incident response при подозрении на утечку

Cross-tenant exposure - приоритетный инцидент. Сразу остановите затронутый путь через feature flag, сохраните evidence, отзовите credentials и определите все tenant/request IDs. Не удаляйте логи до расследования и не делайте вывод только по одному trace.

Contain

Kill switch, revoke, isolate.

Scope

Requests, data, tenants и duration.

Recover

Fix, regression tests, controlled restore.

Production-чек-лист multi-tenant LLM-сервиса

Перед запуском
  1. Tenant context приходит из verified identity.
  2. Модель не задаёт tenant, roles, namespace или keys.
  3. Silo/pool/hybrid выбран по risk и TCO.
  4. Control plane отделён от data plane.
  5. Все repositories требуют TenantContext.
  6. Prompts, files, RAG, memory и cache имеют scope.
  7. Retrieval фильтруется до поиска и после него.
  8. Provider secrets находятся в vault.
  9. Quotas каскадируются по tenant и project.
  10. Fair scheduling защищает от noisy neighbor.
  11. Usage events идемпотентны и сверяются.
  12. Logs, traces и evals tenant-aware.
  13. Cross-tenant negative suite работает в CI.
  14. Export, migration и deletion протестированы.
  15. Есть kill switch и incident runbook.
Что такое мультитенантный LLM-сервис?
Это AI/SaaS-продукт, где несколько организаций используют общую платформу, но их данные, настройки, бюджеты и доступ изолированы. Инфраструктура может быть общей, выделенной или гибридной.
Разве JWT с tenant_id не решает изоляцию?
Он даёт исходный trusted context, но каждый storage, retrieval, cache, tool и trace должен применять его самостоятельно. Аутентифицированный пользователь всё ещё может получить чужой объект из-за IDOR или ошибочного запроса.
Что лучше для LLM SaaS: silo или pool?
Универсального ответа нет. Pool эффективнее для множества небольших клиентов, silo даёт более сильную resource isolation, hybrid позволяет выделять регулируемые или крупные workloads. Выбор зависит от риска, compliance, performance и TCO.
Как изолировать RAG между клиентами?
Trusted runtime выбирает tenant namespace или добавляет обязательный partition filter до retrieval, затем проверяет ownership каждого результата. Ingestion, cache, export и deletion используют тот же scope.
Можно ли использовать общий semantic cache?
Только для явно публичных данных в отдельном scope. Для клиентских ответов cache key должен включать tenant, policy, model, prompt и corpus version, иначе возможна cross-tenant утечка.
Как защититься от noisy neighbor?
Используйте per-tenant RPM/TPM и concurrency, weighted fair queues, размерные классы, отдельные pools для interactive и batch, deadlines, agent step limits и admission control по бюджету.
Как считать использование и выставлять счёт?
Создавайте идемпотентные usage events на каждый model/tool/storage unit с tenant, project и pricing version. Агрегируйте в ledger, учитывайте adjustments и сверяйте результат с provider usage и invoice.
Как доказать отсутствие cross-tenant доступа?
Автоматическими negative tests и аудитом: подмена IDs, прямые ссылки, запросы к RAG, cache collision, conversation enumeration, tools, traces, exports и удаление. Тесты запускаются при каждом изменении policy и data path.
← Все статьи блога