Skip to content

Latest commit

 

History

History

terraform

README.md

🏗️ Terraform — Azure IoT Infrastructure

Deploy a complete Azure IoT infrastructure with one terraform apply. IoT Hub + Event Hub + Log Analytics + monitoring — all wired together.


What Gets Created

Resource Type Notes
Resource Group azurerm_resource_group Container for all resources
IoT Hub azurerm_iothub F1 free tier — 8,000 msgs/day, 500 devices
Event Hub Namespace azurerm_eventhub_namespace Standard, 1 TU
Event Hub azurerm_eventhub 2 partitions, 1-day retention
Consumer Group azurerm_eventhub_consumer_group Dedicated for the monitor dashboard
Auth Rules azurerm_eventhub_authorization_rule iothub-send (send) + monitor-listen (listen)
Log Analytics azurerm_log_analytics_workspace 30-day retention
Diagnostic Settings IoT Hub + Event Hub → Log Analytics Connections, telemetry, routing logs
Metric Alert azurerm_monitor_metric_alert Alert when dropped telemetry > 10
IoT Device via az iot hub device-identity N registered devices (default: 1)

Architecture

graph LR
    subgraph EDGE["🔌 Edge"]
        ESP32["ESP32-C3\n+ BMP280 / BME280"]
    end

    subgraph AZURE["☁️ Microsoft Azure"]
        IOTHUB["🔷 IoT Hub\nF1 Free"]
        EH["🔷 Event Hub\nStandard"]
        LOGS["🔷 Log Analytics\n30 days"]
        ALERT["🔔 Alert\nDropped Msgs"]
        IOTHUB -->|"Route"| EH
        IOTHUB -.->|"Diagnostics"| LOGS
        EH -.->|"Diagnostics"| LOGS
        IOTHUB -.-> ALERT
    end

    subgraph DASH["🖥️ Dashboard"]
        FLASK["Flask + Chart.js"]
    end

    ESP32 ==>|"D2C"| IOTHUB
    EH -->|"Consumer Group"| FLASK

    style AZURE fill:#e8f1fb,stroke:#0078d4,stroke-width:3px
    style EDGE fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px
    style DASH fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px
Loading

Full architecture diagram: see README.md


Prerequisites

  1. Terraform ≥ 1.5 — Download
  2. Azure CLI — Download
  3. IoT extension for Azure CLI:
    az extension add --name azure-iot
  4. An Azure account with an active subscription

Quick Start (5 minutes)

Every command shows expected output so you always know if it worked.

1. Login to Azure

az login

What happens: the browser opens — sign in with your Azure account. The terminal then shows:

[
  {
    "name": "Your Subscription Name",
    "id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    ...
  }
]

❌ Browser doesn't open? Try az login --use-device-code.

2. Create the Terraform state backend

If you're not already in the terraform folder:

cd terraform
.\scripts\setup-tfstate-backend.ps1

What you'll see (~1 minute):

Creating resource group 'globalazure-tfstate-rg'...
Creating storage account '...'...
Creating container 'tfstate'...
✅ Backend configuration written to backend.tfvars

3. Configure variables

Copy-Item terraform.auto.tfvars.example terraform.auto.tfvars

No output? That's correct.

Find your Subscription ID:

az account show --query id -o tsv

✅ You'll see a string like xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx. Copy it.

Open the file:

notepad terraform.auto.tfvars

Find the line subscription_id = "ENTER-YOUR-SUBSCRIPTION-ID-HERE" and replace the placeholder with your Subscription ID:

subscription_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

Save (Ctrl+S) and close Notepad.

4. Initialize Terraform

terraform init -backend-config=backend.tfvars

What you'll see:

Initializing the backend...
...
Terraform has been successfully initialized!

❌ "Backend configuration changed"? Type yes to migrate.

5. Review the plan

terraform plan

What you'll see: a list of ~12 Azure resources that will be created. Review them if you want (no changes are made yet).

6. Deploy the infrastructure

terraform apply

Terraform shows the plan again and asks:

Do you want to perform these actions?
  Enter a value:

Type yes and press Enter. Wait 2–3 minutes.

What you'll see at the end:

Apply complete! Resources: 12 added, 0 changed, 0 destroyed.

❌ Error about IoT Hub region? Open terraform.auto.tfvars and change iothub_location to "northeurope".


After Deployment

Get connection strings

# All connection strings in .env format
terraform output -raw dot_env_content

# Individual values
terraform output iothub_name
terraform output eventhub_name
terraform output -raw iothub_service_connection_string
terraform output -raw eventhub_listen_connection_string

Get a device connection string

az iot hub device-identity connection-string show `
  --hub-name (terraform output -raw iothub_name) `
  --device-id globalazure-kit-device-0 `
  -o tsv

Generate the .env file for the monitor

terraform output -raw dot_env_content | Out-File -FilePath ../monitor/.env -Encoding UTF8

Next Steps

Infrastructure is ready! Now:

  1. Wire the hardware — follow the ESP32-C3 quick-start guide (§1–§7)
  2. Flash the firmware — see firmware/README.md
  3. Start the dashboard — see monitor/README.md

Monitoring

Diagnostic logs from IoT Hub and Event Hub are sent to Log Analytics.

Open Azure Portal → Log Analytics workspace → Logs and try these KQL queries:

Device connections (last 24h)

AzureDiagnostics
| where ResourceProvider == "MICROSOFT.DEVICES"
| where Category == "Connections"
| where TimeGenerated > ago(24h)
| project TimeGenerated, OperationName, ResultType, CallerLocalAddress
| order by TimeGenerated desc

Telemetry messages

AzureDiagnostics
| where ResourceProvider == "MICROSOFT.DEVICES"
| where Category == "DeviceTelemetry"
| where TimeGenerated > ago(1h)
| summarize count() by bin(TimeGenerated, 5m)
| render timechart

Customization

Parameter File Default Description
subscription_id terraform.auto.tfvars — Your Azure Subscription ID
project_prefix terraform.auto.tfvars globalazure-kit Resource name prefix
location terraform.auto.tfvars italynorth Region for Event Hub, Log Analytics
iothub_location terraform.auto.tfvars westeurope Region for IoT Hub (not available everywhere)
device_count terraform.auto.tfvars 1 Number of IoT devices to register

Cleanup

To destroy all resources:

terraform destroy

Note: the tfstate Resource Group (globalazure-tfstate-rg) is NOT removed by terraform destroy. To remove it manually:

az group delete --name globalazure-tfstate-rg --yes

File Structure

terraform/
├── main.tf                         # Provider, backend, locals
├── variables.tf                    # Input variables
├── resources.tf                    # IoT Hub, Event Hub, devices
├── monitoring.tf                   # Log Analytics, diagnostics, alerts
├── outputs.tf                      # Connection strings, .env output
├── backend.tfvars.example          # Backend config template
├── terraform.auto.tfvars.example   # Variables template
├── .gitignore                      # Excludes tfstate and sensitive files
├── scripts/
│   └── setup-tfstate-backend.ps1   # Bootstrap storage for tfstate
└── README.md                       # This guide

Estimated Costs

Resource Cost
IoT Hub F1 Free (8,000 msgs/day)
Event Hub Standard ~€10/month (1 TU)
Log Analytics ~€2.50/GB ingested
Storage (tfstate) ~€0.02/month
Estimated total ~€10–15/month

For a workshop lasting a few hours, the cost is negligible. Remember to run terraform destroy when done!


Troubleshooting

"Backend not configured"

You forgot -backend-config=backend.tfvars:

terraform init -backend-config=backend.tfvars

"IoT Hub not available in this region"

Change iothub_location in terraform.auto.tfvars. Use westeurope or northeurope.

"az iot: command not found"

Install the IoT extension:

az extension add --name azure-iot

"Device already exists"

Normal — the provisioner shows a warning but continues.

Wrong Subscription ID

az account list --output table
az account set --subscription "NAME-OR-ID"

Engineered by ExtraNet, AI-accelerated with GitHub Copilot
Global Azure Torino 2026