La scalabilità di Terraform oltre i confini organizzativi richiede un attento equilibrio tra standardizzazione e flessibilità. Grazie a strutture di team chiare, una governance ben progettata, processi CI/CD automatizzati e un adeguato supporto degli strumenti, anche infrastrutture multi-tenant complesse possono essere gestite in modo efficace. Con queste basi, è possibile estendere la pratica di Terraform dai singoli team all'intera organizzazione, garantendo coerenza, sicurezza ed efficienza.
Questa è la prima parte di una serie sulla progettazione della multi-tenancy come Infrastructure-as-Code in grandi infrastrutture.
Terraform at Scale - Gestione di infrastrutture di grandi dimensioni
Parte 1a: Multi-Tenancy - Ereditarietà delle informazioni verso unità organizzative e clienti
Introduzione
Nel mondo delle moderne infrastrutture cloud, il termine “Multi-Tenancy” può sembrare uno di quei buzzword sentiti durante le conferenze mentre si controllano le e-mail di nascosto sul telefono. Tuttavia, per le aziende che gestiscono decine o addirittura centinaia di tenant, dipartimenti o clienti su un'infrastruttura condivisa, si tratta di una realtà concreta: all’aumentare del numero di tenant, la complessità cresce in modo sproporzionato (spesso in modo quadratico o cubico), poiché aumenta il numero di dipendenze e interfacce.
Immaginate di dover gestire 20 progetti Terraform separati – ognuno con le proprie variabili, il proprio state, backend e versioni dei moduli.
Ora immaginate di dover condividere informazioni di rete fondamentali tra questi progetti, senza utilizzare blocchi di codice duplicati che inevitabilmente divergerebbero alla prima modifica.
Se questo scenario vi sembra ancora gestibile, aggiungete un’ulteriore dimensione organizzativa: immaginate che nei diversi progetti operino anche team differenti e pipeline CI/CD che implementano l'infrastruttura come Infrastructure-as-Code. Magari si tratta persino di team provenienti da altre aree aziendali, con decisori e manager differenti all’interno dell’organigramma.
Benvenuti nel mondo della gestione Multi-Tenancy con Terraform.
Gli approcci tradizionali a Terraform raggiungono rapidamente i loro limiti in questo contesto. Il modello classico – un repository, uno state, un workspace – funziona perfettamente per ambienti di piccole dimensioni. Tuttavia, nel momento in cui è necessario condividere informazioni tra aree infrastrutturali logicamente separate, la situazione si complica. Emergono domande come:
- Come si garantisce che tutti i team abbiano accesso alle stesse configurazioni di rete di base?
- Come si assicura che le modifiche a tali configurazioni di base vengano propagate automaticamente ai team dipendenti?
- Come si evita che team diversi creino configurazioni che si sovrappongano o addirittura si escludano a vicenda, come ad esempio indirizzi di rete duplicati?
- Come si impedisce che un team sovrascriva accidentalmente le risorse di un altro team?
- E come si mantiene una visione d'insieme nonostante la crescente complessità?
In un precedente articolo abbiamo visto quanto sia facile incorrere in catastrofi infrastrutturali. Il caso Knight Capital – dove un’incoerenza nella distribuzione su soli otto server ha portato a una perdita di 460 milioni di dollari – è un monito esemplare. Se un singolo sistema con pochi componenti può causare danni di tale entità, cosa accade in ambienti Multi-Tenant complessi?
La buona notizia: con i giusti modelli e tecniche, questa complessità può essere gestita. Terraform offre, attraverso il concetto di Remote State, un metodo elegante per condividere informazioni tra diversi domini infrastrutturali senza compromettere l'isolamento dei tenant.
In questa prima parte della nostra serie „Terraform at Scale“ affronteremo proprio questo tema:
- Come possiamo utilizzare Terraform in modo efficace per gestire ambienti Multi-Tenancy?
- Come possiamo trasmettere informazioni in modo mirato tra unità organizzative?
Illustreremo modelli pratici applicati con successo in diversi progetti clienti, che vi aiuteranno a portare la vostra infrastruttura Terraform al livello successivo – senza errori da 460 milioni di dollari.
Comprendere la Multi-Tenancy – più di semplici ambienti separati
Quando si parla di Multi-Tenancy – o multitenancy – nel mondo del cloud, molti pensano inizialmente ad ambienti completamente isolati: il cliente A ottiene la propria rete, il cliente B ottiene la propria rete e i due non dovrebbero mai entrare in contatto. Questa visione non è errata, ma è limitata, soprattutto quando si considera l'Infrastructure-as-Code (IaC).
Nel contesto di Terraform, la Multi-Tenancy non riguarda solo la separazione tecnica delle risorse, ma anche la strutturazione organizzativa del codice, degli state e dei flussi di lavoro. Si tratta di modularizzare l’infrastruttura in modo che rifletta la realtà dell’organizzazione – sia che si tratti di un fornitore di servizi con clienti esterni, sia di un’azienda con diverse unità di business e progetti.
Separazione logica vs. fisica dei tenant
Nella separazione fisica, ogni tenant riceve risorse dedicate – server, reti, sistemi di storage propri. Questo approccio garantisce la massima isolamento, ma è costoso e spesso eccessivamente rigido. La separazione logica, invece, utilizza risorse fisiche condivise, ma separa i dati e gli accessi a livello applicativo. Nella pratica, si adottano spesso soluzioni ibride:
- Livello di rete: VPC o subnet dedicate per ciascun tenant, ma infrastruttura fisica condivisa
- Livello di calcolo: Istanza VM dedicate, ma su hardware condiviso
- Livello dati: Database o schemi separati, ma potenzialmente su server di database condivisi
- Livello identità: Policy IAM e ruoli separati, ma all'interno di un sistema di identità comune
Con Terraform, possiamo modellare in modo efficace questi diversi livelli di separazione, ma dobbiamo gestire attentamente i flussi informativi tra di essi.
L’organizzazione dei tenant nella realtà
Nella pratica, le strutture multi-tenant sono raramente unidimensionali. Una tipica azienda, ad esempio, ha:
- Unità di business (Finanza, HR, Produzione, Vendite)
- Team funzionali all'interno di queste unità (Sviluppo, QA, Operations)
- Progetti, spesso trasversali tra le unità
- Ambienti (Sviluppo, Test, Produzione) per ciascun progetto
- Strutture regionali per motivi normativi o di latenza
Queste dimensioni organizzative si sovrappongono e la nostra struttura Terraform deve essere in grado di rappresentare tale complessità.
Mentre i provider cloud come AWS con Organizations o OCI con Compartments offrono strutture gerarchiche, il codice Terraform deve spesso essere organizzato in modo ancora più granulare. Infatti, in diverse unità aziendali e team operano persone con competenze, responsabilità e persino aspettative differenti, oltre a obiettivi e – nel caso di aziende globali – contesti culturali diversi.
Tutti questi fattori aggiungono un livello di complessità che può portare a sorprese continue quando si cerca di tradurli in codice - sia positive che negative.
La sfida consiste anche nel fatto che le diverse dimensioni forniscono e richiedono informazioni differenti. Ad esempio:
- Il team di rete definisce reti e subnet di base,
- il team di sicurezza configura firewall, policy e certificati,
- il team di storage si occupa di file system, storage a blocchi, object storage e backup,
- il team database fornisce i database,
- e i team di sviluppo applicativo devono poter accedere a queste informazioni rilevanti senza doverle duplicare.
Il problema dell’ereditarietà delle informazioni
Ed è proprio qui che risiede la vera difficoltà: come possiamo garantire che le modifiche alle componenti infrastrutturali fondamentali vengano automaticamente propagate a tutte le componenti dipendenti?
- Se il nostro team di rete modifica un CIDR di una subnet, come vengono informate tutte le VM?
- Se aggiungiamo nuove regioni cloud, come possiamo garantire che tutti i team utilizzino le stesse impostazioni predefinite?
In un ambiente di piccole dimensioni, potremmo gestire tutto questo in un unico Terraform State. Tuttavia, ciò porta rapidamente a un monolite di State con:
- Centinaia o migliaia di risorse
- Tempi di pianificazione lunghi
- Il rischio che un team modifichi accidentalmente le risorse di un altro team
L'alternativa – States completamente separati senza scambio di informazioni – porta a:
- Duplicazione,
- Incoerenze,
- e il famigerato „Copy & Paste DevOps“, che tutti cerchiamo di evitare.
Fortunatamente, Terraform offre con il concetto di Remote State una soluzione elegante a questo dilemma. Nel prossimo paragrafo vedremo come, sfruttando in modo mirato i Remote States, possiamo consentire un’ereditarietà delle informazioni flessibile e scalabile tra i tenant – senza compromettere l’isolamento dei tenant stessi.
Il Terraform Remote State
Terraform memorizza le informazioni relative alla vostra infrastruttura in un file di stato – il cosiddetto State File, che funge da Single Source of Truth per l’infrastruttura.
Chiunque abbia mai cancellato accidentalmente un file .tfstate locale lo sa bene: questo file apparentemente insignificante è la memoria di Terraform – senza di esso, Terraform non sa più quali risorse sono già state create e tenterà di riprovisionarle tutte da zero – spesso con conseguenze catastrofiche.
Che cos'è il Terraform Remote State e a cosa serve?
Questo concetto offre diversi vantaggi fondamentali:
- Collaborazione: Più membri del team possono lavorare sulla stessa infrastruttura senza dover scambiarsi manualmente i file di state.
- Sicurezza: I file di state contengono spesso informazioni sensibili – una memorizzazione centralizzata consente una protezione più efficace.
- State-Locking: Previene modifiche simultanee da parte di più persone, evitando possibili incongruenze.
- Scambio di informazioni: I Remote State possono fungere da fonte dati per altri progetti Terraform.
Nelle grandi infrastrutture, quest'ultimo punto è particolarmente critico. Esso consente di costruire un'architettura scalabile e modulare:
- Ogni team o progetto gestisce il proprio Terraform State, evitando di scrivere dipendenze dirette verso altri team all'interno del codice.
- Componenti infrastrutturali condivisi (ad es. reti, controllo delle identità e degli accessi, servizi comuni) possono essere gestiti come Remote State dai rispettivi team responsabili.
- Le modifiche all'infrastruttura globale vengono automaticamente propagate ai progetti dipendenti.
Importanza del Remote State per le architetture Multi-Tenancy
In un ambiente tipico Multi-Tenancy, esistono diversi livelli infrastrutturali che si basano l'uno sull'altro:
- Infrastruttura globale: Reti di base, configurazioni IAM, servizi condivisi
- Risorse specifiche per tenant: Database, application server, soluzioni di storage...
- Livello applicativo: I workload effettivi del tenant
Con i Remote State possiamo separare chiaramente questi livelli, evitando che gli strati superiori debbano duplicare informazioni di quelli inferiori.
Un team applicativo, ad esempio, può accedere alle informazioni di rete gestite dal team di networking, senza dover definire risorse di rete proprie.
Remote State nella pratica
Vediamo come questo concetto si applica nella pratica:
- Un team centrale per l’infrastruttura gestisce le configurazioni di rete fondamentali e i sistemi di storage per tutti i team in un proprio progetto Terraform.
- Il Security NOC centrale definisce firewall, regole di sicurezza e policy.
- Il team database gestisce i database e fornisce ai tenant partizioni di database isolate.
- Un team applicativo può quindi accedere, nei propri progetti Terraform relativi ai vari Value Streams, alle informazioni di rete, ai sistemi di storage, alle policy di sicurezza e ai database senza doverli ridefinire. Allo stesso modo, le pipeline dei diversi Value Streams possono scambiarsi dati tramite Remote State.
- Se il team di rete, storage, sicurezza o database apporta modifiche, queste vengono automaticamente propagate ai progetti a valle.
La data source "terraform_remote_state" in dettaglio
Il cuore di questo scambio di informazioni è la data source terraform_remote_state. Essa consente a un progetto Terraform di accedere allo State di un altro progetto. Ecco un esempio semplice:
data "terraform_remote_state" "network" { backend = "remote" config = { organization = "my-org" workspaces = { name = "network-global" } } } resource "cloud_instance" "app_server" { image_id = "image-12345678" instance_type = "standard" subnet_id = data.terraform_remote_state.network.outputs.private_subnet_id }
In questo esempio, il team applicativo accede all'ID della subnet definito dal team di rete. Un aspetto fondamentale è che è possibile accedere solo ai valori esplicitamente definiti come output – questo crea un'interfaccia chiara tra i progetti.
Un'altra funzionalità potente: è possibile accedere a State memorizzati in backend diversi, consentendo lo scambio di informazioni tra ambienti differenti (ad esempio, AWS e OCI). Questo è particolarmente utile per le organizzazioni che adottano strategie multi-cloud.
Considerazioni sulla sicurezza nella condivisione dello State
Per quanto potente sia il concetto di Remote State, esso richiede una pianificazione attenta in termini di sicurezza. I file di State possono contenere informazioni sensibili:
- Controllo degli accessi: Non tutti i team dovrebbero avere accesso a tutti i Remote State. Utilizzate i meccanismi di controllo del vostro provider di backend (ad esempio, IAM Policies per S3).
- Dati sensibili: I file di State possono contenere password e altri segreti. Utilizzate l'attributo sensitive = true per gli output di Terraform e valutate l’uso di HashiCorp Vault per la gestione dei segreti critici.
- Crittografia: Assicuratevi che i file di State siano crittografati sia a riposo che in transito.
- Controllo degli output: Esporre solo le informazioni strettamente necessarie negli output. Ogni output crea una dipendenza e un potenziale rischio di sicurezza. Evitate di includere dati sensibili negli output. Inoltre, Terraform non permette di ereditare valori definiti con sensitive = true, quindi è preferibile gestire tali informazioni con altri strumenti.
Un modello particolarmente efficace consiste nel creare specifici “State di interfaccia” o “Proxy State” che servono esclusivamente a fornire informazioni selezionate ad altri team. Questi State non contengono risorse effettive, ma solo Data Source che estraggono informazioni dallo State principale e le forniscono come output filtrati. Il tenant ottiene così accesso a un Remote State con le sole informazioni necessarie, senza poter visualizzare dati sensibili o destinati ad altri tenant.
Con queste basi possiamo ora analizzare un esempio architetturale: come si presenta la Multi-Tenancy nella pratica e come possiamo sfruttare i Remote State per ereditare informazioni tra le unità organizzative?
Ne parleremo presto nella prossima parte di questa serie.