Skip to content

Multi-Tenancy

BoilStream provides full tenant isolation within a single deployment, enabling secure multi-tenant data platforms.

Isolation Model

Each tenant (user) gets isolated:

ResourceIsolation
DuckLakesSeparate catalogs per tenant
SecretsEncrypted, tenant-scoped secret storage
FilesystemChroot to tenant-specific directory
AttachmentsIsolated DuckDB attachments
SessionsSeparate session management

Architecture

DuckLake Isolation

Each user can have multiple DuckLakes, completely isolated from other users:

sql
-- User A's catalogs
FROM boilstream_ducklakes();
┌──────────────────┬─────────────────────┐
namedescription
├──────────────────┼─────────────────────┤
│ analytics        │ Analytics warehouse │
│ events__stream   │ Event streaming     │
└──────────────────┴─────────────────────┘

-- User B cannot see or access User A's catalogs

DuckDB Remote Secrets Store

Tenants can store secrets remotely via the boilstream extension:

sql
-- Create persistent secret onto BoilStream server
CREATE PERSISTENT SECRET s3_minio IN boilstream (
    TYPE S3,
    KEY_ID 'minioadmin',
    SECRET 'minioadmin',
    REGION 'eu-west-1',
    ENDPOINT 'localhost:9000',
    USE_SSL false,
    URL_STYLE 'path',
    SCOPE 's3://ingestion-data/'
);

-- Secrets are automatically available after login
-- Other tenants cannot access your secrets

Secrets are:

  • Encrypted with AES-256-GCM
  • Scoped to the authenticated tenant
  • Automatically loaded on session start
  • Synced across DuckDB clients

Filesystem Isolation

Each tenant is chrooted to their own directory:

yaml
# config.yaml
pgwire:
  tenant_data_base_path: "/data/tenants"

Results in:

/data/tenants/
├── user_abc123/     # Tenant A's files
│   ├── uploads/
│   └── exports/
├── user_def456/     # Tenant B's files
│   ├── uploads/
│   └── exports/

Tenants cannot access files outside their directory.

Session Isolation

  • Each tenant has independent sessions
  • Session credentials are tenant-specific
  • Concurrent session limits per tenant (configurable)
yaml
auth:
  max_concurrent_sessions: 20 # Per user
  max_session_ttl_hours: 8

Role-Based Access

Superadmins can assign BoilStream roles to control tenant capabilities:

RoleCapabilities
ReaderQuery DuckLakes, read secrets
WriterAbove + create tables, ingest data
AdminAbove + create DuckLakes, manage secrets
SuperuserFull access
bash
# Assign role to user
boilstream-admin roles assign data-engineers --user tenant@example.com

# Assign role to SAML group
boilstream-admin roles assign analysts --group "Data Team"

S3 Bucket Isolation

Tenants can be assigned to specific S3 buckets via BoilStream roles:

bash
# Create role with bucket access
boilstream-admin roles create tenant-a-role \
    --bucket tenant-a-data-bucket \
    --access-level writer

Configuration

yaml
# Multi-tenant settings
pgwire:
  tenant_data_base_path: "/data/tenants"
  max_connections: 100 # Total across all tenants

auth:
  max_concurrent_sessions: 20 # Per tenant
  max_sessions_per_hour: 1000 # Rate limit per tenant

auth_server:
  auto_create_default_ducklake: true # Auto-provision DuckLake for new users

Best Practices

  1. Use BoilStream roles - Assign roles to control tenant access levels
  2. Enable auto-provisioning - New users automatically get a DuckLake
  3. Set resource limits - Configure per-tenant session and connection limits
  4. Use SAML groups - Map IdP groups to BoilStream roles for SSO users
  5. Monitor per-tenant - Use tenant labels in Prometheus metrics

Next Steps