fetch_ml/docs/src/multi-tenant-security.md
Jeremie Fraeys 5d75f3576b
docs: comprehensive documentation updates
- Update TEST_COVERAGE_MAP with current requirements
- Refresh ADR-004 with C++ implementation details
- Update architecture, deployment, and security docs
- Improve CLI/TUI UX contract documentation
2026-03-04 13:23:48 -05:00

6.1 KiB

Multi-Tenant Security Implementation Summary

Overview

This document summarizes the Multi-Tenant Server Security features implemented for tenant isolation, cross-tenant access prevention, resource quotas, worker sanitization, and per-tenant audit logging.


Tenant Isolation

Tenant Manager (internal/worker/tenant/manager.go)

Core Types:

  • Tenant - Represents an isolated tenant with metadata, config, and lifecycle state
  • TenantConfig - Holds tenant-specific configuration including quotas and security policies
  • IsolationLevel - Defines isolation degree: soft, hard, or dedicated

Key Methods:

  • CreateTenant() - Creates isolated tenant workspace with subdirectories (artifacts, snapshots, logs, cache)
  • GetTenant() - Retrieves active tenant by ID
  • DeactivateTenant() - Soft-delete tenant
  • GetTenantWorkspace() - Returns isolated workspace path for tenant
  • ListTenants() - Returns all active tenants

Workspace Isolation:

/tenants/
  ├── {tenant-id}/
  │   ├── artifacts/
  │   ├── snapshots/
  │   ├── logs/
  │   └── cache/

Security Defaults (DefaultTenantConfig):

  • IsolationLevel: hard (container-level)
  • RequireEncryption: true
  • RequireAuditLogging: true
  • RequireSandbox: true
  • NetworkPolicy: "restricted"

Cross-Tenant Access Prevention

Middleware (internal/worker/tenant/middleware.go)

HTTP Middleware:

  • Middleware.Handler() - Validates tenant ID from headers/query params/context
  • ExtractTenantID() - Extracts tenant ID from request (header: X-Tenant-ID, query param, or context)
  • Automatic audit logging of all tenant requests

Resource Access Control:

  • ResourceAccessChecker - Validates cross-tenant resource access
  • CheckAccess() - Denies all cross-tenant access by default
  • CheckResourceOwnership() - Validates resource belongs to requesting tenant
  • ValidateResourcePath() - Ensures path within tenant workspace

Cross-Tenant Denial:

// All cross-tenant access denied by default
if requestingTenantID != resourceTenantID {
    return fmt.Errorf("cross-tenant access denied")
}

Resource Quotas per Tenant

Quota Manager (internal/worker/tenant/quota.go)

ResourceQuota Structure:

  • MaxConcurrentJobs - Job concurrency limit
  • MaxGPUs - GPU allocation limit
  • MaxMemoryGB - Memory usage limit
  • MaxStorageGB - Storage quota
  • MaxCPUCores - CPU core limit
  • MaxRuntimeHours - Maximum job runtime
  • MaxArtifactsPerHour - Artifact creation rate limit

QuotaManager Features:

  • CheckQuota() - Validates resource request against tenant limits
  • Allocate() - Reserves resources for tenant
  • Release() - Frees resources when done
  • RecordArtifact() - Tracks artifact creation rate
  • Automatic hourly counter reset

Default Quotas:

MaxConcurrentJobs:   5
MaxGPUs:             1
MaxMemoryGB:         32
MaxStorageGB:        100
MaxCPUCores:         8
MaxRuntimeHours:     24
MaxArtifactsPerHour: 10

Worker Sanitization Between Tenants

Sanitization (internal/worker/tenant/manager.go)

SanitizeForTenant():

  • Clears tenant-specific caches
  • Logs tenant transition for audit
  • Prepares worker environment for different tenant

Called When:

  • Worker switches between tenant tasks
  • New tenant session begins

Audit Event: AuditWorkerSanitized


Per-Tenant Audit Logging

Audit Logger (internal/worker/tenant/quota.go)

AuditEvent Types:

  • AuditTenantCreated - Tenant provisioned
  • AuditTenantDeactivated - Tenant deactivated
  • AuditTenantUpdated - Configuration changed
  • AuditResourceAccess - Resource accessed
  • AuditResourceCreated - Resource created
  • AuditResourceDeleted - Resource deleted
  • AuditJobSubmitted - Job queued
  • AuditJobCompleted - Job finished
  • AuditJobFailed - Job error
  • AuditCrossTenantDeny - Cross-tenant blocked
  • AuditQuotaExceeded - Quota violation
  • AuditWorkerSanitized - Worker cleaned
  • AuditEncryptionOp - Encryption operation
  • AuditDecryptionOp - Decryption operation

Audit Log Structure:

/tenants/
  └── {tenant-id}/
      └── audit.log (JSON format)

Features:

  • Per-tenant isolated log files
  • Structured JSON format
  • IP address tracking
  • Success/failure status
  • Detailed context in Details field

Files Created

Core Implementation

  1. internal/worker/tenant/manager.go - Tenant lifecycle and isolation
  2. internal/worker/tenant/quota.go - Resource quotas and audit logging
  3. internal/worker/tenant/middleware.go - HTTP middleware and access control

Worker Integration

  1. internal/worker/worker.go - Added TenantManager field to Worker struct

Testing

Build verification:

make dev  # Successful

All Go packages compile on:

  • macOS (Darwin)
  • Linux
  • Windows

Security Impact

Feature Threat Mitigated Implementation
Tenant Isolation Data leakage between tenants Hard isolation with dedicated workspaces
Cross-Tenant Access Unauthorized data access Deny-by-default with audit logging
Resource Quotas Resource exhaustion / DoS Per-tenant limits with enforcement
Worker Sanitization Cross-contamination State clearing between tenant switches
Per-Tenant Audit Compliance gaps Isolated audit logs per tenant

HIPAA Compliance

All features support HIPAA compliance:

  • Tenant isolation ensures data separation
  • Cross-tenant access prevention blocks unauthorized access
  • Per-tenant audit logs enable compliance tracking
  • Resource quotas prevent resource-based DoS

Integration Points

Worker Usage:

// Initialize tenant manager
w.TenantManager, _ = tenant.NewManager("/tenants", w.Logger)

// Create tenant
tenant, _ := w.TenantManager.CreateTenant(ctx, "tenant-1", "Acme Corp", config)

// Validate resource access
err := w.TenantManager.ValidateTenantAccess(ctx, requestingTenant, resourceTenant)

// Sanitize between tenants
w.TenantManager.SanitizeForTenant(ctx, newTenantID)

HTTP Middleware Usage:

middleware := tenant.NewMiddleware(tenantManager, logger)
http.Handle("/api/", middleware.Handler(apiHandler))