In Terraform, i moduli sono una delle funzionalità più potenti per organizzare e gestire l'infrastruttura come codice in modo riutilizzabile ed efficiente. L'idea di base di un modulo è quella di incapsulare una serie di risorse che sono frequentemente usate insieme, permettendo di creare infrastrutture complesse in modo più modulare e gestibile. Un modulo può essere pensato come una "scatola nera" che prende alcuni input, esegue delle operazioni e restituisce degli output.

Nel contesto di Azure, l'uso di moduli permette di gestire risorse come gruppi di risorse, reti virtuali, subnet, e altre entità in modo coerente e scalabile. In questo capitolo, esploreremo il funzionamento dei moduli in Terraform, con un particolare focus su come strutturare e modularizzare la tua infrastruttura, utilizzando variabili, moduli annidati, e versionamento dei moduli per gestire al meglio la configurazione.

Un esempio comune di utilizzo di un modulo in Terraform è la creazione di una rete virtuale (VNet) in Azure. Nel modulo principale, che potrebbe essere contenuto nel file main.tf, si definiscono risorse come il gruppo di risorse e la rete virtuale, collegando tra loro variabili di input come la posizione e il nome della rete.

Nel codice seguente, vediamo come si possano definire alcune variabili per gestire l'infrastruttura di rete:

hcl
variable "location" { type = string description = "Azure region for all resources" } variable "vnet_name" { type = string description = "Name of the virtual network" default = "default-vnet" } variable "address_space" { type = list(string) description = "Address space for the VNet" default = ["10.0.0.0/16"] }

Nel modulo, queste variabili vengono utilizzate per costruire le risorse necessarie. Per esempio, per creare un gruppo di risorse e una rete virtuale, possiamo utilizzare il seguente codice:

hcl
resource "azurerm_resource_group" "demo_rg" {
name = var.resource_group_name location = var.location } resource "azurerm_virtual_network" "demo_vnet" { name = var.vnet_name resource_group_name = azurerm_resource_group.demo_rg.name location = var.location address_space = var.address_space }

Una volta che il modulo è stato creato, è possibile esporre dettagli utili, come l'ID della rete virtuale, tramite un file outputs.tf:

hcl
output "vnet_id" { description = "ID of the virtual network" value = azurerm_virtual_network.demo_vnet.id }

Con questo modulo, è possibile invocarlo in una configurazione radice (root configuration) utilizzando il seguente codice:

hcl
module "my_network" {
source = "./azure_vnet_module" resource_group_name = "rg-shared" location = "EastUS" vnet_name = "vnet-staging" }

Questo snippet costruisce un pattern riutilizzabile per creare gruppi di risorse e reti virtuali. Se sono necessari altri ambienti, lo stesso modulo può essere invocato con variabili diverse. Ciò garantisce che ogni ambiente rimanga coerente nei nomi, nella struttura e nelle migliori pratiche, semplificando attività come il controllo dei costi e la risoluzione dei problemi.

Inoltre, è possibile aggiungere submoduli per la creazione di subnet o regole di sicurezza, o fornire variabili aggiuntive per affinare le proprietà delle risorse create. Questo approccio permette una gestione più granulare e modulare delle risorse, rendendo l'infrastruttura più semplice da mantenere e modificare.

Un altro concetto fondamentale nella progettazione di infrastrutture Terraform è l'uso di moduli annidati. Questo approccio consente di suddividere componenti complessi in moduli più piccoli, ognuno dei quali gestisce una parte distinta dell'infrastruttura. Ad esempio, un modulo principale potrebbe configurare una rete virtuale e un modulo secondario (figlio) potrebbe essere responsabile per la creazione delle subnet all'interno di quella rete.

Immagina di avere un modulo principale chiamato azure_network, che si occupa di creare la rete virtuale e a sua volta richiama un modulo figlio chiamato azure_subnet, il quale definisce le subnet all'interno della rete virtuale. Ecco come potrebbe essere la struttura:

hcl
resource "azurerm_virtual_network" "parent_vnet" {
name = var.vnet_name resource_group_name = var.resource_group_name location = var.location address_space = ["10.0.0.0/16"] } module "subnet_module" { source = "./modules/azure_subnet" resource_group_name = var.resource_group_name vnet_name = azurerm_virtual_network.parent_vnet.name subnet_name = var.subnet_name subnet_address_prefix = var.subnet_address_prefix }

Nel modulo secondario (azure_subnet), vengono definiti i parametri necessari per la creazione di una subnet:

hcl
variable "resource_group_name" { type = string } variable "vnet_name" { type = string } variable "subnet_name" { type = string } variable "subnet_address_prefix" { type = string } resource "azurerm_subnet" "child_subnet" { name = var.subnet_name resource_group_name = var.resource_group_name virtual_network_name = var.vnet_name address_prefixes = [var.subnet_address_prefix] }

Questo approccio consente di separare le risorse in moduli specifici per ogni componente, semplificando la gestione del codice e la manutenzione, oltre a migliorare la modularità della tua infrastruttura. Ogni modulo figlio può essere sviluppato e gestito indipendentemente, con la possibilità di aggiornare o sostituire un modulo senza influire sull'intero sistema.

Infine, il versionamento dei moduli è una pratica fondamentale per garantire la stabilità e la coerenza nell'ambiente di produzione. Utilizzando il versionamento, si può evitare di introdurre modifiche non testate nei moduli, proteggendo così l'ambiente esistente da cambiamenti improvvisi. Un approccio comune è quello di memorizzare il codice del modulo in un repository Git, taggare ogni rilascio stabile e fare riferimento a tale versione nella configurazione Terraform. Questo processo consente di mantenere il controllo sulle modifiche, decidendo quando aggiornare i moduli e garantendo la riproducibilità degli ambienti.

Quando un modulo viene aggiornato, è possibile farlo riferimento a una versione specifica con un tag, come nel seguente esempio:

hcl
module "prod_vnet" { source = "git::https://github.com/example-org/terraform-azure-vnet.git//azure_vnet?ref=v1.2.1" resource_group_name = "rg-production" location = "EastUS" vnet_name = "prod-vnet" }

Questo approccio evita di caricare codice non testato e permette di gestire versioni successive dei moduli, garantendo che ogni ambiente possa scegliere quando adottare una nuova versione.

Il versionamento dei moduli è una tecnica fondamentale per mantenere l'infrastruttura stabile e gestibile nel tempo, evitando rotture improvvise e migliorando la prevedibilità delle modifiche.

Gestione Sicura dei Segreti con Azure Key Vault e Terraform

Nel mondo moderno delle applicazioni e dei servizi basati sul cloud, la gestione sicura dei segreti rappresenta uno degli aspetti cruciali per garantire la protezione dei dati sensibili. I segreti, come le credenziali di accesso a database, API keys, certificati, e altre informazioni riservate, devono essere custoditi in modo sicuro per evitare perdite o attacchi. Azure Key Vault è uno strumento di Microsoft Azure che consente di gestire e proteggere questi segreti in modo centralizzato, e con l'aiuto di Terraform è possibile automatizzare l'intero processo di gestione e configurazione.

Quando si configurano le politiche di accesso a un Key Vault, ad esempio, è necessario specificare quali permessi sono concessi agli utenti o alle applicazioni. In un esempio pratico di configurazione di Terraform, si definisce una risorsa di accesso che concede a un client i permessi di "get", "list", "set" e "delete" sui segreti. La configurazione potrebbe essere la seguente:

hcl
resource "azurerm_key_vault_access_policy" "example" { key_vault_id = azurerm_key_vault.example.id tenant_id = data.azurerm_client_config.current.tenant_id object_id = data.azurerm_client_config.current.object_id key_permissions = ["get", "list"] secret_permissions = ["get", "set", "delete", "list"] }

Questa configurazione garantisce che l'utente attuale possa ottenere, impostare, eliminare e elencare i segreti nel Key Vault. Una volta definiti i permessi, si possono aggiungere i segreti veri e propri, come ad esempio le credenziali di accesso a un database:

hcl
resource "azurerm_key_vault_secret" "db_username" {
name = "db-username" value = "myusername" key_vault_id = azurerm_key_vault.example.id } resource "azurerm_key_vault_secret" "db_password" { name = "db-password" value = "mypassword" key_vault_id = azurerm_key_vault.example.id }

In questo esempio, stiamo creando due segreti nel Key Vault di Azure: uno per il nome utente del database e uno per la password. Questo approccio permette di centralizzare le informazioni sensibili, evitando che vengano esposte in vari punti del codice o nelle configurazioni delle applicazioni.

Per accedere ai segreti memorizzati nel Key Vault all'interno di una configurazione Terraform, è possibile utilizzare il data source azurerm_key_vault_secret. Ad esempio, per recuperare il nome utente e la password del database, la configurazione sarà la seguente:

hcl
data "azurerm_key_vault_secret" "db_username" { name = "db-username" key_vault_id = azurerm_key_vault.example.id } data "azurerm_key_vault_secret" "db_password" { name = "db-password" key_vault_id = azurerm_key_vault.example.id }

Una volta ottenuti questi segreti, possono essere utilizzati per configurare risorse come un server SQL in Azure, ad esempio:

hcl
resource "azurerm_sql_server" "example" {
name = "mysqlserver" resource_group_name = azurerm_resource_group.example.name location = azurerm_resource_group.example.location version = "12.0" administrator_login = data.azurerm_key_vault_secret.db_username.value administrator_login_password = data.azurerm_key_vault_secret.db_password.value }

In questa configurazione, i segreti recuperati dal Key Vault vengono utilizzati per configurare il login amministrativo di un server SQL, garantendo che le credenziali non vengano mai scritte direttamente nel codice, riducendo così il rischio di esposizione.

Un altro aspetto fondamentale della gestione dei segreti è il monitoraggio e la registrazione degli accessi ai segreti stessi. Azure Key Vault si integra perfettamente con Azure Monitor e Azure Log Analytics, offrendo la possibilità di visualizzare i log e configurare alert basati su determinate condizioni. Ad esempio, possiamo configurare un setting diagnostico per inviare i log degli eventi di accesso a un workspace di Log Analytics:

hcl
resource "azurerm_log_analytics_workspace" "example" { name = "exampleworkspace" location = azurerm_resource_group.example.location resource_group_name = azurerm_resource_group.example.name sku = "PerGB2018" retention_in_days = 30 } resource "azurerm_monitor_diagnostic_setting" "example" { name = "example" target_resource_id = azurerm_key_vault.example.id log_analytics_workspace_id = azurerm_log_analytics_workspace.example.id log { category = "AuditEvent" enabled = true retention_policy { enabled = true days = 7 } } metric { category = "AllMetrics" retention_policy { enabled = true days = 7 } } }

In questo esempio, viene configurato un workspace di Log Analytics con una politica di conservazione dei dati di 30 giorni. I log di audit e le metriche di performance vengono inviati a questo workspace, con una politica di conservazione di 7 giorni per ciascun tipo di dato. I log di audit registrano gli eventi legati all'accesso e all'uso dei segreti, come la lettura o la scrittura di un segreto, mentre le metriche forniscono dati sulle prestazioni generali del Key Vault.

Il monitoraggio continuo permette di rilevare attività sospette, come accessi non autorizzati o tentativi di abuso, e consente di configurare avvisi per notificare gli amministratori in caso di comportamenti anomali. Azure offre anche il log delle attività di Key Vault, che registra tutte le operazioni di scrittura, come PUT, PATCH e DELETE, eseguite su un Key Vault. Questo livello di visibilità è fondamentale per garantire la sicurezza e l'integrità dei segreti memorizzati.

Oltre alla configurazione di base di Terraform, un altro aspetto importante è l'adozione di politiche di gestione dei segreti a lungo termine, come la rotazione periodica delle chiavi e la gestione delle versioni. È fondamentale avere processi chiari per la rotazione dei segreti, in modo da limitare il rischio in caso di esposizione accidentale o compromissione. Utilizzare Terraform consente di automatizzare questo processo e di mantenere un livello di sicurezza costante e facilmente riproducibile.