☁ Cloud e DevOps

Terraform in pratica: provider, stato, piano e moduli

Come funziona Terraform: provider e risorse, il file di stato e dove custodirlo, il ciclo plan e apply, variabili, moduli e gli errori più comuni.

Terraform è uno degli strumenti più diffusi per gestire l'infrastruttura come codice. Funziona con quasi tutti i provider cloud e con molti servizi esterni, dal DNS al monitoraggio, usando un linguaggio dichiarativo chiamato HCL. Dopo il cambio di licenza deciso da HashiCorp nel 2023 è nato anche OpenTofu, un fork open source compatibile; i concetti descritti qui valgono per entrambi.

Provider e risorse

Un provider è il plugin che sa parlare con un certo servizio: il provider di un cloud, quello di Cloudflare, quello di GitHub. Una risorsa è un singolo oggetto gestito, come una macchina virtuale, un bucket o un record DNS.

terraform {
  required_providers {
    cloudflare = {
      source  = "cloudflare/cloudflare"
      version = "~> 4.0"
    }
  }
}

resource "cloudflare_record" "www" {
  zone_id = var.zone_id
  name    = "www"
  type    = "CNAME"
  content = "example.pages.dev"
  proxied = true
}

Il blocco iniziale fissa il provider e la sua versione; il secondo descrive un record. Non c'è nessun comando «crea»: si dichiara che il record deve esistere con quelle caratteristiche. Nota che il nome esatto degli attributi può cambiare tra una versione maggiore e l'altra di un provider, motivo in più per fissarne la versione.

Il ciclo di lavoro

Il flusso quotidiano si basa su pochi comandi:

  1. terraform init scarica i provider e prepara la cartella di lavoro.
  2. terraform plan confronta il codice con la realtà e mostra cosa verrebbe creato, modificato o distrutto.
  3. terraform apply esegue le modifiche, dopo aver mostrato di nuovo il piano e chiesto conferma.
  4. terraform destroy elimina tutte le risorse gestite da quella configurazione.

Il passo più importante è il secondo. Il piano usa simboli chiari: + per le creazioni, ~ per le modifiche, - per le distruzioni e -/+ per le risorse che verranno distrutte e ricreate. Quest'ultimo caso merita sempre attenzione: alcuni attributi non possono essere cambiati sul posto, e modificarli comporta la cancellazione della risorsa. Su un database, significa perdere i dati.

Lo stato: la memoria di Terraform

Terraform deve sapere quali risorse reali corrispondono a quali blocchi di codice. Questa associazione è salvata nel file di stato, di solito terraform.tfstate. Senza stato, Terraform non sa cosa ha creato e proverebbe a ricreare tutto.

Lo stato ha tre caratteristiche da conoscere bene:

  • contiene dati sensibili: password generate, chiavi, indirizzi interni, spesso in chiaro;
  • è condiviso: se due persone lavorano sulla stessa infrastruttura devono usare lo stesso stato;
  • va protetto dalle scritture concorrenti: due apply simultanei possono corromperlo.

Per questi motivi lo stato non va lasciato sul computer di qualcuno né salvato nel repository Git. Si usa un backend remoto, come un bucket di object storage con versioning e cifratura attivi oppure un servizio dedicato, con un meccanismo di lock che impedisce esecuzioni contemporanee.

Variabili, output e ambienti

Le variabili rendono il codice riutilizzabile: dimensione delle macchine, regione, nome dell'ambiente. Gli output espongono valori utili dopo l'applicazione, come l'indirizzo IP di un server.

Per gestire più ambienti, la soluzione più leggibile è di solito tenere configurazioni separate per staging e produzione, ciascuna con il proprio stato, che richiamano gli stessi moduli con valori diversi. In questo modo un errore in staging non può toccare la produzione, e chi legge capisce subito su cosa sta lavorando.

I moduli

Un modulo è una cartella di codice Terraform riutilizzabile, con variabili in ingresso e output in uscita. Se ogni applicazione ha bisogno di una macchina, un record DNS e una regola di firewall, si scrive un modulo che li crea insieme e lo si richiama con parametri diversi.

I moduli vanno progettati con equilibrio. Un modulo troppo generico, con decine di opzioni, diventa difficile quanto il codice che doveva semplificare. Un buon modulo rappresenta un concetto chiaro del tuo dominio, come «un servizio web standard», e nasconde i dettagli ripetitivi.

Errori comuni

  • Modificare a mano risorse gestite da Terraform: al piano successivo Terraform proverà a riportarle allo stato dichiarato, annullando la modifica.
  • Non fissare le versioni di provider e moduli: un aggiornamento automatico può cambiare comportamento senza preavviso.
  • Applicare senza leggere il piano, specialmente quando compaiono distruzioni.
  • Mettere segreti nel codice: vanno passati tramite variabili da un archivio sicuro, ricordando che finiranno comunque nello stato.
  • Un'unica configurazione enorme per tutto: piani lenti, rischio esteso e conflitti tra persone. Meglio dividere per area o per servizio.

Proteggere le risorse critiche

Per le risorse che non devono mai sparire, come database di produzione o bucket con dati, Terraform offre l'impostazione prevent_destroy nel blocco lifecycle: qualunque piano che preveda di distruggerle viene rifiutato con un errore. Insieme alla protezione dalla cancellazione offerta da molti provider, è una cintura di sicurezza economica contro gli errori più costosi.

In sintesi

  • Terraform descrive risorse di molti provider in modo dichiarativo; OpenTofu è un'alternativa open source compatibile.
  • Leggi sempre il piano prima di applicarlo, con particolare attenzione alle risorse distrutte e ricreate.
  • Lo stato contiene dati sensibili: tienilo in un backend remoto cifrato, versionato e con lock.
  • Separa gli ambienti in configurazioni distinte e usa moduli che rappresentano concetti chiari.
  • Fissa le versioni, non modificare a mano le risorse gestite e proteggi quelle critiche dalla distruzione.
MM
Marco Marzaduri

Marco Marzaduri si occupa di cybersecurity, informatica forense e sviluppo web. Laureato in informatica e in psicologia, unisce l'analisi tecnica alla comprensione del fattore umano.

Leggi anche