Home QuickSecure Docs Tenant Isolation

Enterprise Tenant Isolation

Multi-tenant data isolation for MSSP and enterprise deployments with zero breaking changes

Overview

QuickSecure supports enterprise multi-tenant isolation at the database, API, and ML governance layers. Each tenant's data is isolated while sharing the global threat intelligence and model infrastructure.

Resolution

  • X-Tenant-Id header
  • License-based auto-resolution
  • Middleware injection
  • Legacy compatibility (null = global)

Data Layer

  • EF Core global query filters
  • SaveChangesInterceptor
  • Auto-inject TenantId on write
  • Cross-tenant write prevention

ML Layer

  • Per-tenant inference metrics
  • Per-tenant drift detection
  • Hybrid model registry
  • Tenant training eligibility

Tenant Resolution

The TenantResolutionMiddleware resolves tenant context on every request using a priority chain:

PrioritySourceDescription
1X-Tenant-Id headerExplicit tenant ID from the agent or API client
2License lookupIf the API key maps to a license with a TenantId, use it
3Null (global)Legacy endpoints without tenant context. Fully supported.

How It Works

# Agent heartbeat with explicit tenant
curl -X POST https://corxor.com/api/telemetry/heartbeat \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "X-Tenant-Id: tenant-abc" \
  -H "Content-Type: application/json" \
  -d '{"machineId":"MACHINE-001","machineName":"WORKSTATION-1"}'

# Legacy endpoint (no tenant header) — still works, uses global context
curl -X POST https://corxor.com/api/telemetry/heartbeat \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"machineId":"MACHINE-002"}'
Zero breaking changes: Existing agents without X-Tenant-Id continue to work. Their data lives in the global partition (TenantId = null).

Data Safety

Two EF Core mechanisms enforce tenant isolation at the database level:

1. Global Query Filters

Every query on tenant-aware entities automatically includes a WHERE TenantId = @currentTenant filter. This is applied by EF Core at the provider level — application code cannot bypass it.

2. SaveChanges Interceptor

The TenantSaveChangesInterceptor runs on every SaveChangesAsync call:

  • New entities: TenantId is auto-injected from the current request context
  • Modified entities: If TenantId is being changed, the write is blocked and an error is logged
  • Null context: If no tenant is resolved, the entity is written with TenantId = null (global)
Cross-tenant writes are blocked. If an entity's TenantId is being modified to a different value, the operation throws a TenantViolationException. This is audit-logged as a security event.

Tenant-Aware Entities

EntityTenantId ColumnNotes
TelemetryEventV4string?All telemetry events
ModelVersionstring?null = global, non-null = tenant-dedicated
DriftRecordstring?Per-tenant drift snapshots
InferenceMetricstring?Per-tenant confusion matrix
ThreatEventstring?Per-tenant threat events
AutonomousDecisionstring?Per-tenant AI Judge decisions

Legacy Data Backfill

Existing data created before tenant isolation can be retroactively tagged using the TenantBackfillWorker.

How Backfill Works

  1. Runs once at application startup
  2. Finds ML rows where TenantId IS NULL but the EndpointId maps to a License with a TenantId
  3. Updates TenantId via the chain: EndpointIdEndpoint.LicenseIdLicense.TenantId
  4. Processes in batches of 1,000 rows to avoid long-running transactions
Safe operation: Backfill only touches rows where TenantId is currently null. It never overwrites an existing TenantId value.

Admin Visibility

The admin ML dashboard supports tenant-scoped queries via the tenantId query parameter:

# Global ML status (all tenants combined)
GET /api/telemetry/admin/ml/status

# Tenant-specific ML status
GET /api/telemetry/admin/ml/status?tenantId=tenant-abc

# Tenant-specific model versions
GET /api/telemetry/admin/ml/models?tenantId=tenant-abc

# Tenant-specific drift history
GET /api/telemetry/admin/ml/drift?tenantId=tenant-abc