Skip to content

Commit fa4e2f3

Browse files
committed
struc + iot ready
1 parent 0e0730e commit fa4e2f3

26 files changed

Lines changed: 1151 additions & 2 deletions

7_iot/README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,20 @@ Costa Rica
55
[![GitHub](https://img.shields.io/badge/--181717?logo=github&logoColor=ffffff)](https://github.com/)
66
[brown9804](https://github.com/brown9804)
77

8-
Last updated: 2026-02-09
8+
Last updated: 2026-02-17
99

1010
------------------------------------------
1111

1212
> [!IMPORTANT]
1313
> This folder contains sample Terraform templates for Azure IoT services. These templates are starting points and should be customized based on your application needs.
1414
15+
## Templates available
16+
17+
- [Azure IoT Hub](./iot-hub)
18+
- [Azure IoT Edge (Device Update for IoT Hub)](./iot-edge)
19+
- [Azure Digital Twins](./digital-twins)
20+
- [Azure Time Series Insights (IoT)](./time-series-insights)
21+
1522
<!-- START BADGE -->
1623
<div align="center">
1724
<img src="https://img.shields.io/badge/Total%20views-1930-limegreen" alt="Total views">

7_iot/digital-twins/README.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Terraform Template - Azure Digital Twins
2+
3+
Costa Rica
4+
5+
[![GitHub](https://img.shields.io/badge/--181717?logo=github&logoColor=ffffff)](https://github.com/)
6+
[brown9804](https://github.com/brown9804)
7+
8+
Last updated: 2026-02-17
9+
10+
------------------------------------------
11+
12+
> This template creates an Azure Digital Twins instance.
13+
14+
## Usage
15+
16+
```sh
17+
az login
18+
terraform init -upgrade
19+
terraform validate
20+
terraform plan
21+
terraform apply -auto-approve
22+
```
23+
24+
<!-- START BADGE -->
25+
<div align="center">
26+
<img src="https://img.shields.io/badge/Total%20views-1930-limegreen" alt="Total views">
27+
<p>Refresh Date: 2026-02-17</p>
28+
</div>
29+
<!-- END BADGE -->

7_iot/digital-twins/main.tf

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
data "azurerm_client_config" "current" {}
2+
3+
resource "azapi_resource" "resource_group" {
4+
type = "Microsoft.Resources/resourceGroups@2022-09-01"
5+
name = var.resource_group_name
6+
location = var.location
7+
parent_id = "/subscriptions/${data.azurerm_client_config.current.subscription_id}"
8+
9+
body = jsonencode({
10+
tags = var.tags
11+
})
12+
13+
response_export_values = [
14+
"id",
15+
"name"
16+
]
17+
}
18+
19+
resource "random_string" "suffix" {
20+
length = var.random_suffix_length
21+
upper = false
22+
special = false
23+
numeric = true
24+
25+
keepers = {
26+
resource_group_name = var.resource_group_name
27+
location = var.location
28+
base_name = var.digital_twins_name
29+
}
30+
}
31+
32+
locals {
33+
suffix = var.append_random_suffix ? random_string.suffix.result : ""
34+
name_raw = var.append_random_suffix ? "${var.digital_twins_name}-${local.suffix}" : var.digital_twins_name
35+
}
36+
37+
resource "azurerm_digital_twins_instance" "dt" {
38+
name = local.name_raw
39+
location = var.location
40+
resource_group_name = var.resource_group_name
41+
42+
dynamic "identity" {
43+
for_each = var.enable_system_assigned_identity ? [1] : []
44+
content {
45+
type = "SystemAssigned"
46+
}
47+
}
48+
49+
tags = var.tags
50+
51+
depends_on = [
52+
azapi_resource.resource_group
53+
]
54+
}

7_iot/digital-twins/outputs.tf

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
output "resource_group_id" {
2+
description = "The resource ID of the Resource Group."
3+
value = azapi_resource.resource_group.id
4+
}
5+
6+
output "digital_twins_instance_id" {
7+
description = "The resource ID of the Azure Digital Twins instance."
8+
value = azurerm_digital_twins_instance.dt.id
9+
}
10+
11+
output "digital_twins_instance_name" {
12+
description = "The name of the Azure Digital Twins instance."
13+
value = azurerm_digital_twins_instance.dt.name
14+
}
15+
16+
output "digital_twins_host_name" {
17+
description = "The host name for the Azure Digital Twins instance."
18+
value = azurerm_digital_twins_instance.dt.host_name
19+
}

7_iot/digital-twins/provider.tf

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
terraform {
2+
required_version = ">= 1.8, < 2.0"
3+
4+
required_providers {
5+
azurerm = {
6+
source = "hashicorp/azurerm"
7+
version = "~> 3.116"
8+
}
9+
10+
azapi = {
11+
source = "Azure/azapi"
12+
version = "~> 1.13"
13+
}
14+
15+
random = {
16+
source = "hashicorp/random"
17+
version = "~> 3.6"
18+
}
19+
}
20+
}
21+
22+
provider "azurerm" {
23+
features {
24+
resource_group {
25+
prevent_deletion_if_contains_resources = false
26+
}
27+
}
28+
29+
# Uses the current Azure CLI context (az login + az account set)
30+
skip_provider_registration = false
31+
}
32+
33+
provider "azapi" {
34+
# Uses the current Azure CLI context (az login + az account set)
35+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
resource_group_name = "rg-digital-twins-dev"
2+
location = "eastus"
3+
4+
digital_twins_name = "dt-dev"
5+
6+
tags = {
7+
env = "dev"
8+
}

7_iot/digital-twins/variables.tf

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
variable "resource_group_name" {
2+
description = "The name of the Azure Resource Group to deploy into. This template will create the RG if it does not exist (idempotent ARM PUT)."
3+
type = string
4+
5+
validation {
6+
condition = length(trimspace(var.resource_group_name)) > 0
7+
error_message = "resource_group_name must not be empty."
8+
}
9+
}
10+
11+
variable "location" {
12+
description = "The Azure region for the deployment."
13+
type = string
14+
15+
validation {
16+
condition = length(trimspace(var.location)) > 0
17+
error_message = "location must not be empty."
18+
}
19+
}
20+
21+
variable "append_random_suffix" {
22+
description = "Whether to append a random suffix to the Digital Twins instance name to reduce naming collisions."
23+
type = bool
24+
default = true
25+
}
26+
27+
variable "random_suffix_length" {
28+
description = "Length of the random suffix appended when append_random_suffix is true."
29+
type = number
30+
default = 6
31+
32+
validation {
33+
condition = var.random_suffix_length >= 4 && var.random_suffix_length <= 16
34+
error_message = "random_suffix_length must be between 4 and 16."
35+
}
36+
}
37+
38+
variable "digital_twins_name" {
39+
description = "Base name for the Azure Digital Twins instance. If append_random_suffix is true, the final name will be '<base>-<suffix>'."
40+
type = string
41+
42+
validation {
43+
condition = length(trimspace(var.digital_twins_name)) >= 3
44+
error_message = "digital_twins_name must be at least 3 characters."
45+
}
46+
}
47+
48+
variable "enable_system_assigned_identity" {
49+
description = "Whether to enable a System Assigned Managed Identity on the Digital Twins instance."
50+
type = bool
51+
default = true
52+
}
53+
54+
variable "tags" {
55+
description = "A map of tags to assign to resources."
56+
type = map(string)
57+
default = {}
58+
}

7_iot/iot-edge/README.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Terraform Template - Azure IoT Edge (Device Update for IoT Hub)
2+
3+
Costa Rica
4+
5+
[![GitHub](https://img.shields.io/badge/--181717?logo=github&logoColor=ffffff)](https://github.com/)
6+
[brown9804](https://github.com/brown9804)
7+
8+
Last updated: 2026-02-17
9+
10+
------------------------------------------
11+
12+
> This template creates an Azure IoT Hub and a Device Update for IoT Hub account + instance.
13+
14+
> [!IMPORTANT]
15+
> If your subscription is not registered for `Microsoft.DeviceUpdate`, the apply can fail with `MissingSubscriptionRegistration`. This template attempts to register the provider automatically via AzAPI (`register_deviceupdate_resource_provider = true`).
16+
>
17+
> Manual fallback:
18+
>
19+
> ```sh
20+
> az provider register --namespace Microsoft.DeviceUpdate
21+
> az provider show --namespace Microsoft.DeviceUpdate --query registrationState -o tsv
22+
> ```
23+
24+
## Usage
25+
26+
```sh
27+
az login
28+
terraform init -upgrade
29+
terraform validate
30+
terraform plan
31+
terraform apply -auto-approve
32+
```
33+
34+
<!-- START BADGE -->
35+
<div align="center">
36+
<img src="https://img.shields.io/badge/Total%20views-1930-limegreen" alt="Total views">
37+
<p>Refresh Date: 2026-02-17</p>
38+
</div>
39+
<!-- END BADGE -->

7_iot/iot-edge/main.tf

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
data "azurerm_client_config" "current" {}
2+
3+
resource "azapi_resource_action" "register_deviceupdate" {
4+
count = var.register_deviceupdate_resource_provider ? 1 : 0
5+
6+
type = "Microsoft.Resources/providers@2021-04-01"
7+
resource_id = "/subscriptions/${data.azurerm_client_config.current.subscription_id}/providers/Microsoft.DeviceUpdate"
8+
action = "register"
9+
method = "POST"
10+
11+
response_export_values = [
12+
"registrationState"
13+
]
14+
}
15+
16+
resource "azapi_resource" "resource_group" {
17+
type = "Microsoft.Resources/resourceGroups@2022-09-01"
18+
name = var.resource_group_name
19+
location = var.location
20+
parent_id = "/subscriptions/${data.azurerm_client_config.current.subscription_id}"
21+
22+
body = jsonencode({
23+
tags = var.tags
24+
})
25+
26+
response_export_values = [
27+
"id",
28+
"name"
29+
]
30+
}
31+
32+
resource "random_string" "suffix" {
33+
length = var.random_suffix_length
34+
upper = false
35+
special = false
36+
numeric = true
37+
38+
keepers = {
39+
resource_group_name = var.resource_group_name
40+
location = var.location
41+
iothub_base_name = var.iothub_name
42+
dua_base_name = var.device_update_account_name
43+
}
44+
}
45+
46+
locals {
47+
suffix = var.append_random_suffix ? random_string.suffix.result : ""
48+
iothub_name_final = var.append_random_suffix ? "${var.iothub_name}-${local.suffix}" : var.iothub_name
49+
device_update_account_raw = var.append_random_suffix ? "${var.device_update_account_name}-${local.suffix}" : var.device_update_account_name
50+
}
51+
52+
resource "azurerm_iothub" "hub" {
53+
name = local.iothub_name_final
54+
location = var.location
55+
resource_group_name = var.resource_group_name
56+
57+
sku {
58+
name = var.iothub_sku_name
59+
capacity = var.iothub_sku_capacity
60+
}
61+
62+
tags = var.tags
63+
64+
depends_on = [
65+
azapi_resource.resource_group
66+
]
67+
}
68+
69+
resource "azurerm_iothub_device_update_account" "dua" {
70+
name = local.device_update_account_raw
71+
location = var.location
72+
resource_group_name = var.resource_group_name
73+
74+
dynamic "identity" {
75+
for_each = var.enable_device_update_system_assigned_identity ? [1] : []
76+
content {
77+
type = "SystemAssigned"
78+
}
79+
}
80+
81+
tags = var.tags
82+
83+
depends_on = [
84+
azapi_resource.resource_group,
85+
azapi_resource_action.register_deviceupdate
86+
]
87+
}
88+
89+
resource "azurerm_iothub_device_update_instance" "instance" {
90+
name = var.device_update_instance_name
91+
device_update_account_id = azurerm_iothub_device_update_account.dua.id
92+
iothub_id = azurerm_iothub.hub.id
93+
94+
depends_on = [
95+
azurerm_iothub.hub,
96+
azurerm_iothub_device_update_account.dua
97+
]
98+
}

7_iot/iot-edge/outputs.tf

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
output "resource_group_id" {
2+
description = "The resource ID of the Resource Group."
3+
value = azapi_resource.resource_group.id
4+
}
5+
6+
output "iothub_id" {
7+
description = "The resource ID of the IoT Hub."
8+
value = azurerm_iothub.hub.id
9+
}
10+
11+
output "iothub_name" {
12+
description = "The name of the IoT Hub."
13+
value = azurerm_iothub.hub.name
14+
}
15+
16+
output "device_update_account_id" {
17+
description = "The resource ID of the Device Update for IoT Hub account."
18+
value = azurerm_iothub_device_update_account.dua.id
19+
}
20+
21+
output "device_update_account_name" {
22+
description = "The name of the Device Update for IoT Hub account."
23+
value = azurerm_iothub_device_update_account.dua.name
24+
}
25+
26+
output "device_update_instance_id" {
27+
description = "The resource ID of the Device Update instance."
28+
value = azurerm_iothub_device_update_instance.instance.id
29+
}

0 commit comments

Comments
 (0)