Una verifica della sicurezza IaC (Infrastructure as Code, ossia infrastruttura come codice versionato) sembra a prima vista «solo un controllo aggiuntivo nella pipeline». In pratica è un concetto operativo: determina se le modifiche rimangono tracciabili, se i secret fuoriescono inosservati dai file di stato e se lo stato effettivo nella cloud o nel data center corrisponde ancora a quanto è nel repository. Soprattutto in ambienti in cui più team lavorano su reti, IAM (Identity and Access Management, ossia controllo di diritti e ruoli) e servizi di piattaforma, i rischi derivano meno da «magia degli hacker» e più da responsabilità poco chiare, workaround dimenticati e permessi troppo ampi.
Questo articolo presenta un approccio solido per amministratori, System Engineers e fornitori di servizi tecnici: integrare in modo sensato lo Terraform-Scanning nella CI/CD, proteggere i State-Files (incluse le tipiche trappole su backend e log) e gestire la Drift-Detection in modo che non degeneri in rumore d’allarme, ma funzioni come sistema di allerta precoce per deviazioni di sicurezza e operative. Il focus non è il marketing degli strumenti, ma l’implementazione, i limiti, il troubleshooting e una strategia di fallback realistica.
Perché la verifica della sicurezza IaC fallisce nella pratica quotidiana (e come evitarlo)
In molte organizzazioni la sicurezza IaC viene introdotta in modo puntuale: uno scanner viene eseguito una volta, genera una lunga lista di findings e poi la traccia si perde. Cause tipiche:
- Definizione di „Definition of Done“ poco chiara: Cosa è un blocker, cosa è un caso di accettazione del rischio, cosa può essere risolto più tardi?
- Mancanza di baseline: Senza “Golden Rules” (p.es. nessuna apertura 0.0.0.0/0 sulle porte di amministrazione, logging obbligatorio, cifratura at REST) ogni finding è discutibile.
- Lo State come punto cieco: Il tfstate spesso contiene più informazioni del previsto, inclusi attributi sensibili — eppure viene trattato come un artefatto di build.
- Drift senza ownership: I report di drift finiscono nel nulla perché nessuno chiarisce se la deviazione sia intenzionale, un incidente o un hotfix.
Una configurazione sostenibile collega tre livelli: (1) check preventivi prima dell’apply (scanning/policy), (2) protezione dei dati di controllo (State, Credentials, Logs), (3) controlli di tipo detective in esercizio (Drift, Audit, Allerta). Solo insieme si ottiene un miglioramento della sicurezza che resiste nella gestione quotidiana.
Componente 1: Introdurre correttamente lo Terraform-Scanning – con gate chiari invece di una valanga di findings
Il Terraform-Scanning in questo contesto significa: analisi statica delle vostre definizioni IaC (HCL), integrata parzialmente dall’analisi del plan (valutazione del Terraform plan), per individuare precocemente errori di configurazione e anti-pattern di security. Importante: gli scanner vedono solo ciò che sono in grado di interpretare. La loro efficacia dipende da dove eseguite la scansione e cosa definite come «non negoziabile».
Livelli di scansione: Pre-Commit, Pull Request, Merge Gate, Nightly
Per l’operatività è efficace un modello a più livelli:
- Pre-Commit (locale): Veloce, ma non vincolante. Utile per la formattazione, errori evidenti e primi avvisi di policy.
- Pull-Request-Checks: Il punto centrale per la verifica di sicurezza dell’IaC. I risultati possono essere esaminati in fase di review e sono collegati alle modifiche.
- Merge Gate: Regole rigide (es. «Public Exposure», «nessun bucket non cifrato», «nessun ruolo admin»).
- Nightly/periodisch: Recupero per moduli esterni, nuove regole, nuove CVE nei plugin dei provider (se verificate anche aspetti della supply chain).
È importante distinguere tra violazioni di policy (dovrebbero bloccare) e avvisi (dovrebbero rimanere visibili come debito tecnico). Se tutto blocca, lo scanning viene aggirato; se nulla blocca, perde efficacia.
Scansione basata sul plan: Perché „terraform plan“ contiene più verità
I controlli statici spesso non vedono quali valori vengono effettivamente impostati alla fine (variabili, moduli, default). La scansione basata sul plan utilizza il Terraform plan come prodotto intermedio per verificare concretamente quali risorse vengono create con quali attributi. Questo è particolarmente utile in esercizio per:
- Ecosistemi di moduli (molte astrazioni, pochi default visibili)
- Setup multi-environment (Dev/Stage/Prod con input differenti)
- «Inherited Risk» da moduli condivisi
Presupposto è che un plan in CI possa essere generato senza esfiltrare segreti o aprire accessi produttivi. Questo porta direttamente alla questione di credenziali, workspace e ruoli isolati (Least Privilege).
Flusso CI minimale con output del plan come artefatto (senza specificare strumenti nell’articolo)
Indipendentemente dal sistema CI, uno schema robusto è: Init → Validate → Plan → scansione del plan → risultato come report. Assicuratevi che gli artefatti del plan siano protetti (permessi di accesso, retention). Un esempio in Bash per uno stage di pipeline generico:
set -euo pipefail
# Im CI: keine interaktiven Prompts
export TF_IN_AUTOMATION=1
terraform fmt -check -recursive
terraform init -input=false
terraform validate
# Plan erzeugen und als JSON exportieren (für plan-basiertes Scanning)
terraform plan -input=false -out=tfplan
terraform show -json tfplan > tfplan.json
# Hinweis: tfplan.json als Artefakt nur intern und kurzzeitig aufbewahren
# Scanner-Aufruf wäre hier (toolabhängig), Ergebnis als CI-Report publizierenQuando fallisce? Spesso quando l’autenticazione del provider non è separata correttamente (es. credenziali degli sviluppatori nel CI), quando i moduli interrogano fonti dati esterne al momento del plan, o quando backend remoti sono configurati senza locking/senza permessi corretti.
Insidie nella scansione di Terraform
- False positives dovuti alla perdita di contesto: Uno scanner «vede» una security group aperta, ma non che esiste solo in una VPC di test isolata. Soluzione: tag/label degli environment coerenti, regole differenziate, eccezioni documentate.
- „Eccezioni“ senza data di scadenza: Le aperture temporanee diventano permanenti. Soluzione: processo per eccezioni con ticket, responsabile, data di scadenza, revisione.
- Moduli provenienti da fonti esterne: Rischi derivanti dalla supply chain (risorse inattese, pattern obsoleti). Soluzione: bloccare le versioni dei moduli (pinning), controllare le sorgenti, eseguire audit periodici.
- Lo scanner blocca, ma nessuno sa perché: Senza report comprensibili e indicazioni di remediation chiare, la pipeline diventa un punto di attrito.
Componente 2: proteggere i file di stato Terraform – perché tfstate spesso contiene dati sensibili
Lo stato di Terraform (tfstate) è il confronto tra „stato desiderato“ e „reale“. Nel file di stato ci sono Resource-IDs, metadati, dipendenze – e a seconda del provider anche attributi che non volete vedere in Git. Anche se Terraform marca campi come sensitive, non è una patente di libertà: il file di stato RESTa un asset altamente critico, perché facilita indirettamente gli accessi all’infrastruttura (ricognizione) e talvolta contiene veri secrets.
Cosa è tipicamente critico nello stato
- Topologia di rete: subnet, routing, security group, nomi DNS interni
- Dettagli IAM: ruoli, ARN/ID delle policy, relazioni di trust
- Endpoint: host dei database, load balancer, servizi interni
- Valori di configurazione: a seconda della risorsa anche password, token, chiavi private (peggiore scenario), contenuti di user-data
La conseguenza è chiara: lo stato deve essere conservato in un deposito controllato con cifratura, controllo degli accessi, versioning e locking. „Nel repo“ o „come artefatto CI“ è negli ambienti produttivi quasi sempre sbagliato.
Remote State Backend: cifratura, accesso, locking, versioning
Un backend remoto (es. Object Storage, Terraform Cloud/Enterprise, o un servizio backend proprio) non è solo comodità, ma la base per sicurezza e operatività. Verificate queste caratteristiche:
- Cifratura at REST: lato server (KMS/gestione chiavi) o lato client. Importante la governance delle chiavi (rotazione, accesso, audit).
- Cifratura in transito: TLS deve essere obbligatorio, incluso il corretto controllo dei certificati sui client.
- Locking: Previene apply paralleli che possono corrompere lo stato. Senza locking si generano drift difficili da riprodurre o modifiche „fantasma“.
- Versioning: Consente rollback, ricostruzione forense e recovery dopo errori.
- IAM rigoroso: Solo il ruolo CI e pochi operatori dovrebbero avere accesso; diritti separati per lettura e per scrittura.
Controlli operativi concreti: dove lo stato spesso „passa inosservato“
In pratica tfstate compare in punti che nelle revisioni di sicurezza vengono spesso trascurati. Una breve checklist:
- Directory home degli sviluppatori: file di state locali dei test che poi finiscono nei backup
- Workspace CI: dischi dei runner, cache, archiviazione degli artefatti, log di debug
- Allegati di ticket: ‚Puoi dare un’occhiata?‘ – e qualcuno allega tfstate o tfplan.json
- Aggregazione dei log: log troppo verbosi che includono dettagli di plan o dello state
Un controllo pratico è una ricerca mirata di firme tipiche (p.es. nomi di file, chiavi JSON). Esempio per un Linux-runner (adattare il percorso):
set -euo pipefail
# Vorsicht: nur auf Systemen ausführen, für die Sie berechtigt sind.
# Sucht nach typischen Terraform-State-Dateinamen in Workspaces und Caches.
find /var/lib -type f ( -name "*.tfstate" -o -name "*.tfstate.backup" -o -name "tfplan.json" ) 2>/dev/nullSe avete ritrovamenti, il lavoro successivo è importante: perché sono stati generati, perché non sono stati ripuliti e come prevenire il ripetersi (pulizia dei workspace, hardening dei runner, retention degli artefatti).
Separare chiaramente l’accesso allo state: operatori, CI e Break-Glass
‚Least Privilege‘ nel contesto IaC significa: la pipeline può applicare esattamente ciò che deve in questo scope – e non di più. Per l’accesso allo state e i diritti di apply si sono dimostrate utili tre ruoli:
- Ruolo CI-Apply: accesso in scrittura allo state + permessi per le risorse nel rispettivo progetto/account/subscription. Nessuna possibilità di login interattivo.
- Ruolo Read-Only-Audit: può leggere lo state (o report), ma non scrivere; adatto per sicurezza e compliance.
- Ruolo Break-Glass: accesso di emergenza fortemente protetto (MFA, Just-in-Time, logging rigoroso), per consentire fix critici in caso di guasti della pipeline.
Importante è il concetto operativo: il Break-Glass deve esistere, ma essere usato raramente. E ogni utilizzo deve essere visibile nei processi di drift e change, altrimenti si generano ‚Shadow Changes‘.
Strategia di fallback per uno state compromesso
Se dovete presumere che un file di state sia stato esfiltrato, trattatelo come un incidente di sicurezza: lo state consente attività di ricognizione e può, a seconda delle risorse, contenere segreti reali. Una strategia di fallback sensata comprende:
- Bloccare gli accessi: ruotare le chiavi/token di accesso al backend, disabilitare i ruoli interessati.
- Ruotare i segreti esposti: password di database, API token, chiavi SSH, a seconda dei sospetti. Non aspettare di avere ‚prove‘.
- Rafforzare il backend: verificare i percorsi di accesso, attivare logging/auditing, adeguare retention e alert.
- Ripristinare lo state: scegliere da un backend versionato un punto di RESTore definito. Eseguire poi Plan/Apply in modo controllato.
- Lavori successivi: perché il segreto era nello state? Spesso la causa è ’secret come attributo della resource‘ o ‚user-data contiene credenziali‘.
Importante: non ogni leak impone di riprovisionare tutte le risorse. Tuttavia, ogni possibilità che segreti reali fossero nello state richiede la rotazione. Se non potete eseguire la rotazione, è un problema di progettazione delle vostre soluzioni aziendali digitali (es. mancanza del ciclo di vita per i segreti) – e dovrebbe essere prioritizzato.
Componente 3: Drift-Detection in esercizio – dal ‚rumore‘ alle deviazioni attendibili
Drift-Detection significa: confrontare regolarmente lo stato desiderato dichiarativo (IaC) con lo stato effettivo nell’ambiente di destinazione. Il drift si genera quando qualcuno modifica manualmente nella console cloud, in vCenter, nel Firewall-Manager o tramite script cambiamenti che non sono presenti nel codice. Non tutti i drift sono dannosi – ma ogni drift è un segnale: o il processo è rotto, o la definizione IaC non è più veritiera.
Quale drift è davvero rilevante (priorità per le operazioni)
Si è dimostrata efficace una prioritizzazione basata sugli impatti:
- Drift di sicurezza: apertura di porte, modifica delle IAM-Policies, disattivazione del logging, rimozione della cifratura, modifica delle trust-relationship.
- Drift di disponibilità: parametri di scaling, health check, destinazioni DNS/load-balancer, classi di storage.
- Drift di costi/risorse: dimensioni delle istanze, limiti di auto-scaling, nuove risorse inaspettate.
- „Solo“ metadati: Tags/Labels, descrizioni; importanti per la governance, ma raramente critici immediatamente.
Se i vostri report di drift trattano tutto allo stesso modo, le deviazioni critiche verranno trascurate. L’obiettivo è un modello di triage: cosa deve entrare immediatamente nel processo di Incident/Change, cosa può andare nel prossimo sprint, cosa è „expected drift“ (p.es. ID provider automatici) e dovrebbe essere soppressa?
Implementare la Drift-Detection a livello tecnico: pianificazione periodica senza Apply
Un modello praticabile è un job periodico (p.es. giornaliero) che per ogni Workspace/Environment esegue un Init/Refresh/Plan e verifica se sono previste modifiche. Importante: non eseguite un apply, ma generate un segnale. Esempio (Bash) come base:
set -euo pipefail
export TF_IN_AUTOMATION=1
erraform init -input=false
# Plan ohne interaktives Apply; Exitcode 2 bedeutet: es gäbe Änderungen
terraform plan -input=false -detailed-exitcode -out=tfdriftplan || rc=$?
rc=${rc:-0}
if [ "$rc" -eq 2 ]; then
echo "DRIFT_DETECTED=1"
terraform show -no-color tfdriftplan > drift.txt
# Hier: an Ticket/Alerting übergeben, aber drift.txt als sensitives Artefakt behandeln
exit 0
elif [ "$rc" -eq 0 ]; then
echo "DRIFT_DETECTED=0"
exit 0
else
echo "Terraform plan failed with exit code $rc" 1>&2
exit "$rc"
fiPerché funziona? Terraform calcola se lo state attuale (ovvero lo stato rilevato dal refresh) devia dallo stato desiderato. Quando fallisce? Quando le API dei provider applicano rate limit, quando le credenziali scadono, quando le data source sono inaffidabili o quando lo state stesso è inconsistente (p.es. dopo modifiche parallele senza locking).
Radicare la Drift-Detection a livello organizzativo: responsabile, Runbook, finestre temporali
La migliore Drift-Detection non serve a nulla senza una reazione chiara. Stabilite:
- Responsabile per Stack/Workspace: Chi decide se la drift va annullata o integrata nell’IaC?
- Tempo di reazione per classe di drift: il drift di sicurezza è più rapido del drift giornaliero.
- Finestra di manutenzione: molti drift possono essere ripuliti correttamente solo durante la finestra di change.
- Runbook: Cosa verifichiamo prima (Audit-Logs, Change-Tickets, ultime esecuzioni della pipeline)?
Come operatore dovreste inoltre accettare: una parte del drift è generata dall’automazione della piattaforma (p.es. Managed Services che aggiornano i parametri „da soli“). Questi effetti devono essere conosciuti e filtrati in modo mirato, altrimenti si generano allarmi persistenti.
Flusso end-to-end: verifica di sicurezza IaC come routine operativa
Implementate i tre componenti in un flusso continuo. Un modello pratico è il seguente:
- Preparazione: definire regole di base (Blocchi vs. Avvisi), responsabilità, processo per le eccezioni.
- Integrazione CI: Validate + Plan + Scanning (HCL e/o Plan), report nelle PR, Blocchi come gate.
- Indurimento dello state: backend remoto con locking e versioning, IAM rigoroso, igiene di artefatti e log.
- Drift operativo: piano periodico, classificazione, ticket/alerting, ciclo di review.
- Gestione delle regole: introdurre in modo controllato nuove policy, nuove feature dei provider, nuovi requisiti (p.es. obbligo di logging).
Checklist: cosa riuscirete a fare realisticamente nella prima settimana
- Definire le top-10 regole blocker (porte admin esposte pubblicamente, nessun bucket di storage aperto, logging attivato, crittografia attivata, IAM non impostato su „*“).
- Attivare i PR-checks: fmt/validate + uno scanner + output dei report.
- Verificare lo state-backend: locking, versioning, controllo accessi, retention.
- Igiene del CI runner: cancellare il workspace dopo il job, minimizzare gli artefatti, log non troppo verbosi.
- Impostare un job di drift come pilota per un ambiente (p.es. Stage) e definire il canale di allarme.
Risoluzione dei problemi: scenari d’errore comuni e contromisure rapide
1) Lo scanner segnala „critico“, ma si tratta di un design intenzionale
Esempio: un servizio deve essere intenzionalmente accessibile pubblicamente. Soluzione: non ignorare l’avviso, ma documentare controlli compensatori (WAF, rate-limit, mTLS dietro proxy, indurimento della Security Group su porte/sorgenti). Eccezione con data di scadenza e responsabile. Verificare se è possibile rendere la regola più precisa (p.es. solo determinati tipi di risorsa).
2) Il rilevamento del drift scatta continuamente a causa di modifiche „managed“
La causa è spesso un Managed Service che imposta automaticamente parametri (p.es. ID, default minori). Contromisure:
- Utilizzare meccanismi Lifecycle/Ignore in modo mirato (ma solo per veri campi di „rumore“).
- Bloccare le versioni dei provider e aggiornare in modo controllato (altrimenti cambiano i default).
- Adattare la classificazione del drift: drift di metadati ≠ drift di sicurezza.
3) Problemi di state-locking e „stuck locks“
Il locking previene modifiche parallele, ma può rimanere „appeso“ se un job si interrompe. La contromisura è un runbook definito: verificare il lock, individuare il responsabile, rimuovere il lock solo in caso di emergenza, quindi eseguire un controllo di consistenza (Plan). Nel lungo periodo: progettare i job CI in modo che terminino correttamente (Timeouts, strategia di Retry, nessun Apply parallelo sullo stesso workspace).
4) Il Plan in CI fallisce perché mancano le credenziali o sono troppo permissive
La separazione e i privilegi minimi aiutano qui: per Plan/Read spesso bastano permessi inferiori rispetto ad Apply. Se risolvete entrambi con un ruolo onnipotente, guadagnate stabilità a breve termine ma perdete sicurezza. Meglio: ruoli separati e, se Plan richiede certe API di lettura, integrarle in modo mirato.
Aspetti di security e compliance che gli amministratori spesso trascurano
IaC viene spesso classificato come „tema DevOps“, ma è centrale per audit e operazioni. Prestate attenzione a:
- Tracciabilità: chi ha autorizzato quale modifica all’infrastruttura e quando? PR-Reviews, i log delle pipeline e gli audit del backend devono corrispondere.
- Protezione del livello di controllo: CI/CD è parte della vostra sicurezza di produzione. Runner, Secrets, ambiti dei token, accessi di rete.
- Minimizzazione dei dati: Plan/State/Reports contengono dettagli. Conservate solo ciò che serve per operazioni e audit, e solo per il tempo strettamente necessario.
- Separazione degli ambienti: Dev/Prod non solo logica, ma tramite account/sottoscrizioni/progetti separati, state distinti, chiavi separate.
Se parallelamente eseguite anche l’hardening di cluster o database, l’effetto formativo è elevato: molti principi (Least Privilege, Audit-Logs, Recovery-Tests) sono identici, cambiano solo gli strumenti. Sono utili collegamenti interni alle guide operative correlate.
Conclusione: la verifica di sicurezza IaC è un processo operativo, non una scansione una tantum
Una verifica di sicurezza IaC efficace nasce quando considerate scanning, protezione dello state e drift detection come un sistema operativo unificato: preventivo (gates nelle PR), protettivo (state/artefatti/runner), investigativo (drift con reazione chiara). Lo sforzo risiede meno negli strumenti che in responsabilità chiare, in poche regole rigide e nella disciplina di limitare temporalmente le eccezioni.
Se lo impostate così, otterrete più di un semplice „segno di spunta“ di conformità: ridurrete i rischi di sicurezza dovuti a errate configurazioni, rileverete prima modifiche non autorizzate o dimenticate e potrete reagire agli incidenti in modo più rapido e affidabile, perché la storia della vostra infrastruttura è tracciabile.
Per questo ambito sono importanti anche la protezione dello state di Terraform e la drift detection. L’articolo inquadra questi aspetti in modo comprensibile e mostra cosa conta nella pratica quotidiana.