8 min

Come i database multi-tenant influenzano sicurezza e prestazioni

Scopri come i database multi-tenant influenzano sicurezza e prestazioni, i rischi principali (isolamento, noisy neighbors) e i controlli pratici per mantenere i tenant sicuri e reattivi.

Come i database multi-tenant influenzano sicurezza e prestazioni

Cosa significa un database multi-tenant

Un database multi-tenant è una configurazione in cui molti clienti (tenant) condividono lo stesso sistema di database—lo stesso server di database, lo stesso storage sottostante e spesso lo stesso schema—mentre l'applicazione garantisce che ogni tenant possa accedere solo ai propri dati.

Pensalo come un condominio: tutti condividono la struttura e le utenze dell'edificio, ma ogni tenant ha la propria unità chiusa a chiave.

Multi-tenant vs single-tenant (a grandi linee)

In un approccio single-tenant, ogni cliente riceve risorse di database dedicate—per esempio, la propria istanza di database o il proprio server. L'isolamento è più semplice da ragionare, ma di solito è più costoso e operativo mano a mano che il numero dei clienti cresce.

Con la multi-tenancy, i tenant condividono l'infrastruttura, il che può essere efficiente—ma significa anche che il tuo design deve imporre confini in modo intenzionale.

Perché i team SaaS scelgono la multi-tenancy

Le aziende SaaS spesso scelgono la multi-tenancy per motivi pratici:

  • Costo per cliente inferiore (compute, storage, licenze e tempo operativo condivisi)
  • Operazioni più semplici a scala, come meno database da patchare, aggiornare e monitorare
  • Onboarding più veloce per nuovi clienti (non serve provisioning di un intero stack DB)

L'aspettativa chiave: il design determina i risultati

La multi-tenancy di per sé non è automaticamente "sicura" o "veloce." I risultati dipendono da scelte come come i tenant sono separati (schema, righe o database), come viene applicato il controllo accessi, come vengono gestite le chiavi di cifratura e come il sistema impedisce che il carico di un tenant rallenti gli altri.

Il resto di questa guida si concentra su quelle scelte di design—perché nei sistemi multi-tenant, sicurezza e prestazioni sono funzionalità che costruisci, non assunzioni preesistenti.

Modelli comuni di database multi-tenant

La multi-tenancy non è una singola scelta di design—è uno spettro di quanto strettamente condividi l'infrastruttura. Il modello che scegli definisce il tuo confine di isolamento (cosa non deve mai essere condiviso) e questo influenza direttamente sicurezza, isolamento delle prestazioni e operazioni quotidiane.

Database-per-tenant

Ogni tenant ottiene il proprio database (spesso sullo stesso server o cluster).

Confine di isolamento: il database stesso. È solitamente la storia di isolamento più pulita perché l'accesso cross-tenant richiede tipicamente il superamento del confine del database.

Compromessi operativi: più pesante da gestire a scala. Aggiornamenti e migrazioni di schema possono dover essere eseguiti migliaia di volte, e il connection pooling può complicarsi. Backup/restore sono semplici a livello tenant, ma l'overhead di storage e gestione può crescere rapidamente.

Sicurezza e ottimizzazione: generalmente più semplice da mettere in sicurezza e ottimizzare per cliente, e adatto quando i tenant hanno requisiti di compliance differenti.

Schema-per-tenant

I tenant condividono un database, ma ciascuno ha il proprio schema.

Confine di isolamento: lo schema. È una separazione significativa, ma si basa su permessi e tooling corretti.

Compromessi operativi: aggiornamenti e migrazioni sono ancora ripetitive, ma meno pesanti rispetto al database-per-tenant. I backup sono più complicati: molti strumenti trattano il database come unità di backup, quindi operazioni a livello tenant possono richiedere esportazioni dello schema.

Sicurezza e ottimizzazione: più facile far rispettare l'isolamento rispetto alle tabelle condivise, ma serve disciplina sui privilegi e verifica che le query non facciano riferimento allo schema sbagliato.

Table-per-tenant

Tutti i tenant condividono database e schema, ma ogni tenant ha tabelle separate (es. orders_tenant123).

Confine di isolamento: l'insieme di tabelle. Può funzionare per pochi tenant, ma scala male: metadata ingombranti, script di migrazione scomodi e degradazione del piano di query.

Sicurezza e ottimizzazione: i permessi possono essere precisi, tuttavia la complessità operativa è alta e aggiungere nuove tabelle o funzionalità può facilmente introdurre errori.

Shared-table (schema condiviso)

Tutti i tenant condividono le stesse tabelle, distinti tramite una colonna tenant_id.

Confine di isolamento: il livello di query e il layer di controllo accessi (comunemente row-level security). Questo modello è efficiente operativamente—uno schema da migrare, una strategia di indici da gestire—ma è il più esigente per sicurezza e isolamento delle prestazioni.

Sicurezza e ottimizzazione: è il più difficile da fare bene perché ogni query deve essere tenant-aware, e il problema del noisy neighbor è più probabile a meno di throttling delle risorse e indici curati.

Una regola utile: più condividi, più le upgrade diventano semplici—ma più rigore serve nei controlli di isolamento e nelle misure di performance.

Come la multi-tenancy cambia il modello di sicurezza

La multi-tenancy non significa solo “più clienti in un database”. Cambia il tuo modello di minacce: il rischio maggiore si sposta dagli esterni che violano il sistema a utenti autorizzati che, per errore o intenzionalmente, vedono dati appartenenti a un altro tenant.

Autenticazione vs autorizzazione: il contesto tenant è una decisione di autorizzazione

L'autenticazione risponde a “chi sei?”, l'autorizzazione a “cosa puoi fare?”. In un database multi-tenant, il contesto tenant (tenant_id, account_id, org_id) deve essere applicato durante l'autorizzazione—non trattato come un filtro opzionale.

Un errore comune è presumere che una volta autenticato l'utente e noto il suo tenant, l'app terrà automaticamente le query separate. In pratica, la separazione deve essere esplicita e applicata in un punto di controllo coerente (es. policy DB o un layer di query obbligatorio).

Regola fondamentale: ogni lettura e scrittura deve essere scorretta al tenant

La regola più semplice e importante: ogni SELECT e ogni UPDATE/DELETE deve essere limitato esattamente a un tenant.

Questo vale per:

  • SELECT (pagine di elenco ed esportazioni)
  • UPDATE/DELETE
  • Job in background e script ETL
  • Tool amministrativi e workflow di supporto

Se lo scoping del tenant è opzionale, prima o poi verrà omesso.

Modalità di fallimento comuni che causano accessi cross-tenant

I leak cross-tenant spesso derivano da piccoli errori di routine:

  • Filtri tenant mancanti in un endpoint o in un percorso di codice
  • Join “rotte” dove una tabella è scopingata ma la tabella joinata no
  • Risposte in cache indicizzate solo per utente o URL, non per tenant
  • Prepared statement riutilizzati che legano il tenant_id sbagliato

Perché "funziona nei test" può comunque perdere dati in produzione

I test solitamente girano con dataset piccoli e ipotesi pulite. La produzione aggiunge concorrenza, retry, cache, dati misti e edge case reali.

Una feature può passare i test perché nel DB di test c'è un solo tenant o i fixture non includono ID sovrapposti tra tenant. I design più sicuri rendono difficile scrivere una query non scoperte, invece di affidarsi ai revisori per individuarla ogni volta.

Controlli di isolamento che prevengono l'accesso cross-tenant

Il rischio centrale in un database multi-tenant è semplice: una query che dimentica di filtrare per tenant può esporre i dati di un altro. Forti controlli di isolamento presumono che gli errori capitino e rendono quegli errori innocui.

Identificatori tenant e pattern di scoping rigorosi

Ogni record appartenente a un tenant dovrebbe avere un identificatore tenant (per esempio tenant_id) e il tuo layer di accesso ai dati dovrebbe sempre scoprire letture e scritture tramite esso.

Un pattern pratico è “tenant context first”: l'app risolve il tenant (da sottodominio, org ID o claim nel token), lo memorizza nel contesto della richiesta e il codice d'accesso ai dati rifiuta di eseguire senza quel contesto.

Guardrail utili:

  • Richiedere tenant_id nelle chiavi primarie/uniche dove appropriato (per evitare collisioni)
  • Aggiungere foreign key che includano tenant_id così da non creare relazioni cross-tenant accidentalmente

Row-level security (RLS) e accesso basato su policy

Dove supportato (notably PostgreSQL), la row-level security può spostare i controlli tenant nel database. Le policy possono limitare SELECT/UPDATE/DELETE in modo che siano visibili solo le righe corrispondenti al tenant corrente.

Questo riduce la dipendenza dal fatto che “ogni sviluppatore ricordasse la WHERE”, e può proteggere contro alcuni scenari di injection o uso improprio degli ORM. Considera RLS come un secondo lucchetto, non l'unico.

Separazione schema/database come strumento di isolamento

Se i tenant hanno dati più sensibili o requisiti di compliance più severi, separare per schema (o per database) può ridurre il raggio d'impatto. Il contro è un aumento dell'overhead operativo.

Default sicuri: deny-by-default e privilegi minimi

Progetta permessi in modo che il default sia “nessun accesso”:

  • I ruoli applicativi dovrebbero avere solo l'accesso minimo necessario alle tabelle.
  • I workflow amministrativi dovrebbero usare account separati e con elevazione auditata.
  • Evita connessioni "superuser" condivise nel codice applicativo.

Questi controlli funzionano meglio insieme: forte scoping tenant, policy imposte dal DB quando possibile e privilegi conservativi che limitano i danni quando qualcosa scivola.

Cifratura e gestione delle chiavi nei datastore condivisi

La cifratura è uno dei pochi controlli che aiuta anche quando altri livelli di isolamento falliscono. In un datastore condiviso, l'obiettivo è proteggere i dati mentre si muovono, mentre sono a riposo e mentre l'app dimostra per quale tenant sta agendo.

Cifrare i dati in transito e a riposo

Per i dati in transito, richiedi TLS per ogni hop: client → API, API → database e per qualsiasi chiamata interna tra servizi. Impònga TLS a livello di database dove possibile (per esempio rifiutando connessioni non TLS) così che "eccezioni temporanee" non diventino permanenti.

Per i dati a riposo, usa cifratura a livello di database o storage (managed disk encryption, TDE, backup cifrati). Questo protegge contro media persi, esposizione di snapshot e alcune classi di compromesso infrastrutturale—ma non impedirà a una query difettosa di restituire righe di un altro tenant.

Chiavi condivise vs chiavi per-tenant

Una singola chiave condivisa è più semplice da operare (meno chiavi da ruotare, meno punti di errore). Lo svantaggio è il raggio d'impatto: se quella chiave è esposta, tutti i tenant sono esposti.

Le chiavi per-tenant riducono il blast radius e possono soddisfare richieste enterprise (alcuni clienti vogliono controllo chiave separato). Il compromesso è complessità: ciclo di vita delle chiavi, rotazioni e workflow di supporto (es. cosa succede se un tenant disabilita la propria chiave).

Un compromesso pratico è l'envelope encryption: una chiave master cifra le chiavi dati per tenant, mantenendo gestibile la rotazione.

Gestione dei segreti per credenziali di database

Conserva le credenziali del database in un secrets manager, non in variabili d'ambiente in configurazioni a lunga vita. Preferisci credenziali a vita breve o rotazione automatica e assegna accesso per ruolo così che una compromissione in un componente non raggiunga automaticamente ogni database.

Token e sessioni: prevenire contesti tenant contraffatti

Tratta l'identità del tenant come critica per la sicurezza. Non accettare mai un tenant ID grezzo dal client come verità. Associa il contesto tenant a token firmati e controlli server-side e convalida tutto ad ogni richiesta prima di qualsiasi chiamata al database.

Audit, monitoraggio e prontezza agli incidenti

Verifica i requisiti di residenza
Distribuisci le app nel paese richiesto e valida prima le ipotesi di isolamento dei tenant.

La multi-tenancy cambia cosa significa “normale”. Non stai solo osservando un database—stai osservando molti tenant che condividono lo stesso sistema, dove un errore può trasformarsi in una esposizione cross-tenant. Una buona auditabilità e monitoraggio riducono sia la probabilità sia il raggio d'impatto degli incidenti.

Log di audit: registra tutta la storia

Al minimo, registra ogni azione che può leggere, modificare o concedere accesso ai dati dei tenant. Gli eventi di audit più utili rispondono a:

  • Who: identità utente/servizio, metodo di auth, ruolo, IP/dispositivo di origine
  • What: operazione (SELECT/UPDATE/DELETE), oggetti coinvolti, classe di query (non necessariamente SQL completo), before/after per cambi privilegiati
  • When: timestamp con timezone, request/trace ID per correlazione
  • Tenant: tenant ID come campo di prima classe (mai inferito dopo)

Registra anche azioni amministrative: creazione tenant, modifica di policy di isolamento, cambio di RLS, rotazione chiavi e modifica delle stringhe di connessione.

Alert per anomalie cross-tenant e di privilegi

Il monitoraggio dovrebbe rilevare pattern insoliti per un uso SaaS sano:

  • Query che restituiscono righe per più tenant ID, o picchi improvvisi di rifiuti per "tenant mismatch"
  • Accessi da account di servizio a tenant che non toccano normalmente
  • Cambi rapidi di ruolo/permessi, nuovi admin, policy disabilitate o tentativi di bypassare RLS

Collega gli alert a runbook azionabili: cosa controllare, come contenere e chi avvisare.

Controlli amministrativi e procedure break-glass

Tratta l'accesso privilegiato come una modifica in produzione. Usa ruoli a privilegi minimi, credenziali a vita breve e approvazioni per operazioni sensibili (cambi di schema, esportazioni dati, modifiche policy). Per emergenze, mantieni un account break-glass strettamente controllato: credenziali separate, ticket/approvazione obbligatori, accesso limitato nel tempo e logging extra.

Conservazione e accesso ai log per tenant

Imposta la retention basata sui requisiti di compliance e investigazione, ma limita l'accesso ai log così che lo staff di supporto veda solo i log del proprio tenant. Quando i clienti richiedono esportazioni di audit, fornisci report filtrati per tenant invece di log grezzi condivisi.

Nozioni di base sulle prestazioni e il problema del noisy neighbor

La multi-tenancy migliora l'efficienza permettendo a molti clienti di condividere la stessa infrastruttura database. Il compromesso è che le prestazioni diventano un'esperienza condivisa: quello che fa un tenant può influenzare gli altri, anche se i loro dati sono isolati.

Il problema del "noisy neighbor" (in parole semplici)

Un "noisy neighbor" è un tenant la cui attività è così intensa (o così a picchi) da consumare più risorse condivise del dovuto. Il database non è "rotto"—è semplicemente occupato a gestire quel carico, quindi gli altri tenant aspettano di più.

Pensalo come un edificio dove un'unità apre contemporaneamente più docce e la lavatrice; gli altri avvertono una pressione dell'acqua minore.

Cosa è effettivamente condiviso?

Anche quando ogni tenant ha righe o schemi separati, molti componenti critici per le prestazioni sono condivisi:

  • CPU: esecuzione query, ordinamenti, join, cifrature/decifrature, manutenzione in background.
  • Memoria: buffer/cache, memoria di lavoro per le query, code interne.
  • Disk / I/O: lettura file dati, scrittura log, flush di checkpoint, compaction/vacuum.
  • Connessioni: limiti di connessione DB e thread pool.
  • Cache: plan cache, buffer cache e talvolta cache lato applicazione.

Quando queste risorse si saturano, la latenza cresce per tutti.

Perché i workload a picchi danneggiano gli altri

Molti carichi SaaS arrivano a scatti: import massivi, report di fine mese, campagne marketing o cron job all'inizio dell'ora.

I picchi possono creare "ingorghi" nel database:

  • Un tenant lancia molte query costose contemporaneamente, portando la CPU al 100%.
  • Grandi scritture generano I/O extra (scrittura log, manutenzione indici), rallentando le letture.
  • Picchi di connessioni riempiono il pool e gli altri tenant non trovano slot.

Anche se il picco dura pochi minuti, può causare ritardi a catena mentre le code si svuotano.

Cosa notano tipicamente gli utenti

Dal lato cliente, i problemi da noisy neighbor sembrano casuali e ingiusti. Sintomi comuni:

  • Timeout durante login, ricerca, checkout o generazione report
  • Pagine lente, specialmente viste elenco e dashboard
  • Velocità incoerente (veloce alle 10:05, lenta alle 10:10, di nuovo veloce alle 10:20)
  • Job in background in ritardo (esportazioni più lunghe, webhook ritardati)

Questi sintomi sono segnali che servono tecniche di isolamento delle risorse (vedi dopo), non solo "più hardware".

Tecniche di isolamento risorse e throttling

Testa l'isolamento precocemente
Crea test negativi che tentano letture/scritture cross-tenant e blocca le modifiche rischiose.

La multi-tenancy funziona meglio quando un cliente non può prendere in prestito più della sua quota di capacità database. L'isolamento delle risorse è l'insieme di guardrail che impedisce a un tenant pesante di rallentare tutti gli altri.

Limiti di connection pooling e quote per tenant

Un errore comune è avere connessioni senza limiti: un picco di traffico di un tenant apre centinaia di sessioni e prosciuga il database.

Imposta limiti fissi in due punti:

  • Nel pool applicativo: limita le connessioni max per istanza del servizio e riserva un minimo per job in background.
  • Per tenant: applica quote come “N richieste concorrenti” o “M sessioni DB concorrenti” mappate sul piano del tenant.

Anche se il DB non può imporre direttamente "connessioni per tenant", puoi approssimarlo instradando ciascun tenant attraverso un pool dedicato o una partizione del pool.

Rate limiting e shaping del carico (app + DB)

Il rate limiting è questione di equità nel tempo. Applicalo vicino al bordo (API gateway/app) e, dove supportato, dentro il database (resource groups/workload management).

Esempi:

  • Limiti token-bucket per tenant su endpoint costosi (export, search)
  • Tier di priorità così che le richieste interattive prevalgano sui batch
  • Shaping basato su code per smussare i picchi invece di spingerli direttamente nel DB

Timeout di query, limiti di statement e circuit breaker

Proteggi il database da query "runaway":

  • Timeout su query/statement per fermare scansioni lunghe
  • Numero massimo di righe/byte restituiti per endpoint che possono esplodere in dimensione dei risultati
  • Circuit breaker che bloccano temporaneamente feature costose per un tenant quando errori o latenza superano soglie

Questi controlli dovrebbero degradare in modo elegante: restituire un errore chiaro e suggerire retry/backoff.

Replica di lettura e caching per ridurre la contesa

Sposta il traffico di sola lettura lontano dal primario:

  • Read replica per dashboard, reporting e query di tipo analytics
  • Cache (con chiavi per-tenant, TTL brevi) per lookup ripetuti e dati di configurazione

L'obiettivo non è solo velocità—è ridurre lock e contesa CPU affinché i tenant rumorosi abbiano meno modi di impattare gli altri.

Scelte di modellazione dati che influenzano la velocità

I problemi di prestazioni multi-tenant spesso sembrano “il database è lento”, ma la causa reale è di solito il modello dati: come i dati dei tenant sono indicizzati, filtrati, e disposti fisicamente. Un buon modello rende le query tenant-scoped naturalmente veloci; un modello scarso forza il DB a lavorare troppo.

Indicizzazione per query scoperte al tenant

La maggior parte delle query SaaS dovrebbe includere un identificatore tenant. Modellalo esplicitamente (per esempio tenant_id) e crea indici che lo inizino. Nella pratica, un indice composito come (tenant_id, created_at) o (tenant_id, status) è molto più utile dell'indicizzare solo created_at o status isolati.

Vale anche per l'unicità: se le email sono uniche solo per tenant, applicala con (tenant_id, email) piuttosto che un vincolo globale su email.

Evitare full-table scan (filtri tenant mancanti)

Un pattern comune di query lente è una scansione cross-tenant accidentale: una query che dimentica il filtro tenant e tocca una grande porzione della tabella.

Rendi la via sicura quella semplice:

  • Richiedi filtri tenant nel layer di query (scope dell'ORM, repository)
  • Usa protezioni DB dove disponibili (view tenant default o policy) così che l'accesso non scoperte fallisca rapidamente

Partizionamento e sharding: per tenant o per tempo

Il partizionamento può ridurre la quantità di dati che ogni query deve considerare. Partiziona per tenant quando i tenant sono grandi e squilibrati. Partiziona per tempo quando l'accesso è principalmente recente (eventi, log, fatture), spesso con tenant_id come colonna d'indice principale dentro ogni partizione.

Considera lo sharding quando un singolo database non tiene il passo con il throughput di picco, o quando il carico di un tenant minaccia gli altri.

Gestire tenant "hot"

I "hot tenant" appaiono per volumi di letture/scritture sproporzionati, contesa di lock o indici sovradimensionati.

Individua i hot tenant monitorando tempo query per tenant, righe lette e tassi di scrittura. Quando un tenant domina, isolalo: spostalo su uno shard/database separato, dividi tabelle grandi per tenant o introduce cache e rate limit dedicati così gli altri tenant mantengano performance.

Pratiche operative che proteggono sia la sicurezza sia le prestazioni

La multi-tenancy raramente fallisce perché il database "non può farlo". Fallisce quando le operazioni quotidiane permettono a piccole incoerenze di trasformarsi in lacune di sicurezza o regressioni di performance. L'obiettivo è rendere la via sicura il comportamento predefinito per ogni cambiamento, job e deploy.

Standardizza la chiave tenant (e applicala ovunque)

Scegli un identificatore tenant canonico (es. tenant_id) e usalo coerentemente su tabelle, indici, log e API. La coerenza riduce sia errori di sicurezza (query verso il tenant sbagliato) sia sorprese di performance (indici compositi mancanti).

Salvaguardie pratiche:

  • Richiedi tenant_id in tutti i percorsi di accesso primari (query, repository, scope ORM)
  • Aggiungi indici compositi che iniziano con tenant_id per ricerche comuni
  • Preferisci vincoli DB dove possibile (foreign key che includono tenant_id, o check constraint) per intercettare scritture errate presto

Proteggiti dagli errori di mixaggio tenant nei job background

I worker asincroni sono fonte comune di incidenti cross-tenant perché operano "out of band" rispetto alla richiesta che ha stabilito il contesto tenant.

Pattern operativi utili:

  • Passa tenant_id esplicitamente in ogni payload di job; non fare affidamento su contesto ambientale
  • Includi la chiave tenant nelle chiavi di idempotenza e nelle cache
  • Logga tenant_id all'inizio/fine job e ad ogni retry così le indagini possono rapidamente delimitare l'impatto

Rendi le migrazioni sicure per i tenant fin dalla progettazione

Le migrazioni di schema e dati dovrebbero essere distribuibili senza un rollout perfettamente sincronizzato.

Usa cambiamenti in rolling:

  • Strategia expand/contract (aggiungi colonna/indice, dual-write/read, poi rimuovi i percorsi vecchi)
  • Evita operazioni bloccanti lunghe; esegui backfill a batch per tenant per controllare il carico
  • Assicurati che ogni backfill sia tenant-scoped e rate-limited per evitare effetti noisy-neighbor auto-inflitti

Test per fallimenti di isolamento—non solo per i casi favorevoli

Aggiungi test negativi automatici che tentano intenzionalmente di accedere ai dati di un altro tenant (lettura e scrittura). Trattali come blocchi di rilascio.

Esempi:

  • Tentare di recuperare un record noto di Tenant A mentre si è autenticati come Tenant B
  • Eseguire test di job background con tenant_id disallineato e verificare il fallimento netto
  • Test di regressione per ogni helper di query per confermare che lo scoping tenant sia sempre applicato

Backup, restore e operazioni dati a livello tenant

Adatta al tuo stack SaaS
Genera un frontend React e un backend Go con PostgreSQL per rispecchiare il tuo stack di produzione.

I backup sono facili da descrivere ("copia il database") e sorprendentemente difficili da eseguire in sicurezza in un database multi-tenant. Nel momento in cui molti clienti condividono tabelle, serve un piano per recuperare un tenant senza esporre o sovrascrivere altri.

Strategie di backup/restore: un tenant vs tutti

Un backup completo del database resta la base per il disaster recovery, ma non basta per i casi di support day-to-day. Approcci comuni:

  • Backup completi + point-in-time recovery per incidenti che coinvolgono tutti (corruzione, outage di regione)
  • Export logici per tenant (dump filtrati per tenant_id) per ripristinare i dati di un singolo tenant
  • Storage separato per tenant (quando fattibile) per rendere i restore naturalmente limitati al tenant

Se fai affidamento su export logici, tratta il job di export come codice di produzione: deve imporre isolamento tenant (es. tramite RLS) invece di fidarsi di una WHERE scritta una volta e dimenticata.

Export/delete a livello tenant (richieste di privacy)

Le richieste di privacy (export, delete) toccano sicurezza e prestazioni. Costruisci workflow ripetibili e auditati per:

  • Esportare i dati di un tenant in uno snapshot coerente
  • Cancellare i dati di un tenant senza lasciare righe orfane
  • Dimostrare il completamento tramite log e checksum

Prevenire restore accidentali cross-tenant

Il rischio maggiore non è un hacker—è un operatore frettoloso. Riduci l'errore umano con guardrail:

  • Richiedi un identificatore tenant più una conferma secondaria (nome tenant, ID fatturazione)
  • Verifica conteggi righe e distribuzione di tenant_id prima dell'import
  • Ripristina prima in un ambiente di quarantena, poi promuovi

Drill di DR e verifica dei confini dopo

Dopo un disaster recovery drill, non fermarti a “l'app è su”. Esegui controlli automatici che confermino l'isolamento tenant: query campione tra tenant, revisione dei log di audit e verifica che chiavi di cifratura e ruoli d'accesso siano ancora correttamente scoperte.

Quando la multi-tenancy smette di essere la scelta giusta

La multi-tenancy è spesso la scelta predefinita migliore per SaaS, ma non è una decisione permanente. Man mano che prodotto e mix di clienti evolvono, l'approccio del "datastore condiviso" può iniziare a creare rischi di business o rallentare il delivery.

Segnali che è il momento di aumentare l'isolamento

Considera di passare a più isolamento quando uno o più di questi segnali si presentano costantemente:

  • Effetti di crescita e scala: pochi tenant consumano una quota sproporzionata di traffico, storage o job, e la taratura per tutti gli altri diventa più difficile.
  • Requisiti di compliance/contrattuali: i clienti richiedono ambienti dedicati, controlli di residenza, possesso separato delle chiavi o confini di audit più rigorosi di quanto il modello condiviso possa offrire.
  • Tenant pesanti con pattern unici: import massivi, picchi di reporting o integrazioni custom che creano contesa ricorrente e non risolvibile con tuning e throttles.

Modelli ibridi che tengono i costi ragionevoli

Non devi scegliere tra "tutto condiviso" e "tutto dedicato". Approcci ibridi comuni:

  • Estrapolare pochi tenant top-tier in database o cluster separati mantenendo la long tail su infrastruttura condivisa.
  • Offerte a livelli: condiviso di default, isolato per piani enterprise.
  • Isolamento funzionale: lasciare transazionali condivisi, ma spostare analytics/reporting dei tenant pesanti in store separati.

Costi e complessità da spiegare agli stakeholder

Più isolamento solitamente significa spesa infrastrutturale maggiore, maggiore overhead operativo (migrazioni, monitoraggio, on-call) e più coordinamento di release (cambi schema su più ambienti). Il trade-off è garanzie di prestazioni più chiare e conversazioni di compliance più semplici.

Prossimi passi

Se stai valutando opzioni di isolamento, rivedi le guide correlate nella sezione /blog o confronta piani e opzioni di deployment nella pagina /pricing.

Se vuoi prototipare un SaaS velocemente e testare le ipotesi multi-tenant precocemente (scoping tenant, schemi compatibili con RLS, throttling e workflow operativi), una piattaforma di prototipazione come Koder.ai può aiutarti a creare un'app React + Go + PostgreSQL funzionante dalla chat, iterare in modalità planning e distribuire con snapshot e rollback—quindi esportare il codice sorgente quando sei pronto a consolidare l'architettura per la produzione.

Domande frequenti

Cos'è un database multi-tenant in parole semplici?

Un database multi-tenant è un'architettura in cui più clienti condividono la stessa infrastruttura di database (e spesso lo stesso schema), mentre l'applicazione e/o il database assicurano che ogni tenant possa accedere solo ai propri dati. Il requisito fondamentale è lo scoping rigoroso del tenant su ogni lettura e scrittura.

Perché i team SaaS scelgono la multi-tenancy?

La multi-tenancy viene spesso scelta per:

  • Costo per cliente più basso (compute/storage/licenze condivise)
  • Operazioni più semplici a scala (meno database da patchare, aggiornare e monitorare)
  • Onboarding più rapido (non serve provisionare un intero stack DB per ogni cliente)

Il compromesso è che bisogna costruire intenzionalmente guardrail per l'isolamento e le prestazioni.

Quali sono i principali modelli di database multi-tenant?

I modelli comuni (da maggiore isolamento a maggiore condivisione) sono:

  • Database-per-tenant: confine di isolamento più forte, operazioni più pesanti.
  • Schema-per-tenant: buona separazione, migrazioni ripetitive.
  • Table-per-tenant: può funzionare brevemente, spesso non scala bene.
  • Shared-table (colonna tenant_id): operazioni più semplici, più difficile da mettere in sicurezza e ottimizzare.

La scelta determina il confine di isolamento e il carico operativo.

In che modo la multi-tenancy cambia il modello di minacce?

Il rischio principale si sposta verso accessi cross-tenant causati da errori di routine, non solo da attacchi esterni. Il contesto tenant (come tenant_id) deve essere trattato come un requisito di autorizzazione, non come un filtro opzionale. Serve considerare anche le condizioni reali di produzione: concorrenza, caching, retry e job in background.

Cosa causa tipicamente perdite di dati tra tenant?

Le cause più comuni includono:

  • Filtri tenant mancanti in un percorso di codice
  • Join dove una tabella è scorporata ma la tabella joinata no
  • Cache indicizzate per URL/utente ma non per tenant
  • Prepared statement che legano il tenant_id sbagliato
  • Job in background che perdono il contesto tenant

Progetta guardrail in modo che le query non scoperte siano difficili (o impossibili) da eseguire.

Quando usare la row-level security (RLS) e cosa protegge?

La row-level security (RLS) sposta i controlli di tenant dentro il database con policy che limitano SELECT/UPDATE/DELETE alle righe del tenant corrente. Riduce la dipendenza dal fatto che "tutti ricordino la clausola WHERE", ma dovrebbe essere affiancata da scoping a livello app, privilegi minimi e test robusti. Tratta RLS come un lucchetto aggiuntivo, non come l'unico.

Quali sono i controlli di isolamento più importanti per prevenire accessi cross-tenant?

Una baseline pratica include:

  • Un tenant_id canonico nelle tabelle possedute dai tenant
  • Unicità e foreign key composite che includono tenant_id
  • Permessi "deny-by-default" e ruoli DB a privilegi minimi
  • Accesso amministrativo separato e auditato (evitare superuser nel codice app)
  • Test negativi che tentano letture/scritture cross-tenant

L'obiettivo è far sì che gli errori falliscano in modo sicuro.

Come funzionano cifratura e gestione delle chiavi in un datastore condiviso?

La cifratura aiuta ma copre rischi diversi:

  • In transito (TLS): protegge i dati tra servizi.
  • A riposo: protegge snapshot/dischi/backup, ma non ferma query difettose.
  • Chiavi per tenant riducono il raggio d'impatto ma aumentano la complessità operativa.

Tratta l'identità del tenant come critica: non fidarti di un tenant ID grezzo dal client; legalo a token firmati e controlli server-side.

Cos'è il problema del noisy neighbor e come si mitiga?

Il problema del noisy neighbor si verifica quando un tenant consuma risorse condivise (CPU, memoria, I/O, connessioni) rallentando gli altri. Mitigazioni pratiche:

  • Limiti severi sul pool di connessioni (e quote per tenant quando possibile)
  • Rate limiting e shaping del carico per endpoint costosi
  • Timeout di query, limiti su righe/byte restituiti e circuit breaker
  • Read replica e cache con chiavi per-tenant

Punta all'equità, non solo alla massima potenza.

Quando dovresti allontanarti dalla multi-tenancy completa e quali opzioni ibride esistono?

È il momento di aumentare l'isolamento quando:

  • Alcuni tenant consumano in modo sproporzionato risorse e la taratura per tutti diventa difficile
  • Richieste di compliance per ambienti dedicati, residenza o controllo chiavi
  • Workload che non si riescono a contenere con throttling e tuning

Opzioni ibride comuni: spostare pochi tenant top-tier su DB/cluster separati, piani a livelli (shared vs dedicated), o isolare l'analytics/reporting in store separati.

Related posts