Provisions a single Azure IoT Hub Device Provisioning Service (DPS) β the zero-touch onboarding front door that assigns devices to your IoT hubs β hardened by default and targeting
hashicorp/azurerm ~> 4.0.
- βοΈ Creates one
azurerm_iothub_dps(the keystonethis) β an IoT Hub Device Provisioning Service in a resource group you already own. - ποΈ Renders the mandatory
skublock (tier + capacity) with a sane, minimal default so the empty call is valid. - π Links one or more IoT hubs via inline
linked_hubblocks driven by a keyed map, with the allocation policy (Hashed/GeoLatency/Static) that decides how devices are spread across them. - π‘οΈ Constrains reachable source ranges via inline
ip_filter_ruleblocks driven by a keyed map (rule name = map key). - π Ships locked down:
public_network_access_enabled = false, so the empty call yields a private service. - π·οΈ Carries the universal
tags+timeoutstail.
π‘ Why it matters: DPS is how devices bootstrap themselves onto the right IoT hub without hard-coded connection strings. Getting its exposure, allocation policy, and hub links right β securely, and as reviewable code β is the difference between a fleet that self-registers safely and one that leaks a provisioning endpoint to the open internet.
If this module saves you time, a little support goes a long way:
- β Star the repository to help others find it.
- π€ Connect on LinkedIn: linkedin.com/in/microsoftexpert
- β Buy me a coffee: buymeacoffee.com/microsoftexpert
flowchart LR
rg["terraform-azurerm-resource-group"] -->|"resource_group_name + location"| dps["terraform-azurerm-iothub-dps"]
hub["terraform-azurerm-iothub (sibling)"] -->|"connection_string via linked_hub"| dps
dps -->|"id_scope + host names"| devices["provisioned devices"]
dps -->|"allocates devices to"| hub
eg["enrollment groups (sibling module)"] -->|"registers against id_scope"| dps
pe["terraform-azurerm-private-endpoint (sibling)"] -->|"private access to id"| dps
classDef me fill:#0078D4,stroke:#004578,color:#fff;
classDef keystone fill:#004578,stroke:#002236,color:#fff;
classDef ext fill:#eef2f7,stroke:#b8c4d0,color:#1b2733;
class dps me;
class hub keystone;
class rg,devices,eg,pe ext;
flowchart TB
subgraph inputs["Inputs"]
v1["name / resource_group_name / location"]
v2["sku {name, capacity}"]
v3["linked_hubs (keyed map)"]
v4["ip_filter_rules (keyed map)"]
v5["public_network_access_enabled = false"]
end
this["azurerm_iothub_dps.this"]
subgraph blocks["Inline blocks"]
b1["sku"]
b2["linked_hub (per map entry)"]
b3["ip_filter_rule (per map entry)"]
end
subgraph outputs["Outputs"]
o1["id"]
o2["name"]
o3["id_scope"]
o4["device_provisioning_host_name"]
o5["service_operations_host_name"]
end
v1 --> this
v2 --> this
v3 --> this
v4 --> this
v5 --> this
this --> b1
this --> b2
this --> b3
this -->|"emits"| o1
this -->|"emits"| o2
this -->|"emits"| o3
this -->|"emits"| o4
this -->|"emits"| o5
classDef me fill:#0078D4,stroke:#004578,color:#fff;
classDef keystone fill:#004578,stroke:#002236,color:#fff;
classDef ext fill:#eef2f7,stroke:#b8c4d0,color:#1b2733;
class this keystone;
class b1,b2,b3 me;
class v1,v2,v3,v4,v5,o1,o2,o3,o4,o5 ext;
Resource inventory
| Element | Kind | Cardinality |
|---|---|---|
azurerm_iothub_dps.this |
keystone resource | 1 |
sku |
inline block | exactly 1 (rendered from the sku object) |
linked_hub |
inline block | 0..N (one per linked_hubs entry) |
ip_filter_rule |
inline block | 0..N (one per ip_filter_rules entry) |
timeouts |
inline block | 0..1 |
| Requirement | Value |
|---|---|
| Terraform floor | >= 1.12.0 |
| Provider | hashicorp/azurerm, pinned ~> 4.0 |
| Provider block | None in this module β the caller configures provider "azurerm" { features {} }, auth, and subscription |
Schema notes that bite (verified against the live provider schema):
name,resource_group_name, andlocationare immutable β changing any of them forces replacement of the service.data_residency_enabledis immutable β changing it forces a new resource, and enabling it removes the cross-region (geo-paired) disaster-recovery replica.sku.nameonly acceptsS1; there is no other Device Provisioning Service tier.public_network_access_enableddefaults totruein the provider; this module deliberately defaults it tofalse.linked_hub.connection_stringis a secret and is marked sensitive by the provider β provision it out of band and pass a reference, never a literal.allocation_policyonly affects behavior once more than one hub is linked.
Contributoron the target resource group, or a custom role grantingMicrosoft.Devices/provisioningServices/*at the resource-group scope (create / read / update / delete the service and its inline configuration).- Linking a hub requires a valid IoT hub connection string; no additional role on the DPS is needed beyond the write permission above.
- An existing resource group in a supported US Azure region.
- The
Microsoft.Devicesresource provider registered on the target subscription. - For each linked hub: an existing IoT hub and a shared-access-policy connection string with registry write (and service) permissions, supplied out of band (for example via a Key Vault reference).
- The caller configures the
provider "azurerm" { features {} }block, auth, and subscription; this module declares none of these.
terraform-azurerm-iothub-dps/
βββ providers.tf # required_version >= 1.12.0; azurerm ~> 4.0; no provider block
βββ variables.tf # deeply-typed object() schemas + secure defaults + tags/timeouts tail
βββ main.tf # keystone azurerm_iothub_dps.this; dynamic sku/linked_hub/ip_filter_rule/timeouts
βββ outputs.tf # id first, then name, id_scope, and the two host names
βββ README.md # this file
βββ SCOPE.md # the cross-module contract
βββ LICENSE # MIT
βββ .gitignore # canonical library ignore set
provider "azurerm" {
features {}
}
module "dps" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-iothub-dps.git?ref=v1.0.0"
name = "dps-fleet-prod"
resource_group_name = "rg-iot-prod"
location = "eastus"
}βΉοΈ The empty call produces a private service (
public_network_access_enabled = false) on theS1SKU with capacity1. The caller owns the provider, auth, subscription, and the mandatoryfeatures {}block. Pin?ref=v1.0.0β never a branch.
Consumes
| Input | Type | From |
|---|---|---|
resource_group_name |
string |
terraform-azurerm-resource-group output name |
location |
string |
caller / resource group location |
linked_hubs[*].connection_string |
string (secret) |
an IoT hub owner / shared-access-policy connection string, provisioned out of band |
linked_hubs[*].location |
string |
the linked IoT hub's region |
Emits
| Output | Description | Consumed by |
|---|---|---|
id |
Service Resource ID (first) | diagnostics, private endpoint, role assignments |
name |
Service name | diagnostics / tagging conventions |
id_scope |
DPS ID Scope devices present to the global provisioning endpoint | enrollment groups, device firmware |
device_provisioning_host_name |
Device-facing provisioning endpoint hostname | device firmware / provisioning config |
service_operations_host_name |
Service-operations endpoint hostname | management-plane tooling |
1 Β· Minimal, private service
module "dps" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-iothub-dps.git?ref=v1.0.0"
name = "dps-fleet-prod"
resource_group_name = "rg-iot-prod"
location = "eastus"
}π No
skuneeded β it defaults to{ name = "S1", capacity = 1 }. Public network access is off.
2 Β· Scaling registration throughput (SKU capacity)
module "dps" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-iothub-dps.git?ref=v1.0.0"
name = "dps-fleet-prod"
resource_group_name = "rg-iot-prod"
location = "eastus"
sku = {
name = "S1"
capacity = 3
}
}π‘ Each unit raises registration throughput;
S1is the only tier the service offers, so onlycapacitymoves.
3 Β· Link a single IoT hub
module "dps" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-iothub-dps.git?ref=v1.0.0"
name = "dps-fleet-prod"
resource_group_name = "rg-iot-prod"
location = "eastus"
linked_hubs = {
primary = {
connection_string = var.hub_primary_connection_string # provisioned out of band
location = "eastus"
}
}
}π
connection_stringis a secret. Pass a reference (e.g. a Key Vault-sourced value), never a committed literal. The provider marks the field sensitive.
4 Β· Multiple hubs with Hashed allocation and weights
module "dps" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-iothub-dps.git?ref=v1.0.0"
name = "dps-fleet-prod"
resource_group_name = "rg-iot-prod"
location = "eastus"
allocation_policy = "Hashed"
linked_hubs = {
east = {
connection_string = var.hub_east_connection_string
location = "eastus"
apply_allocation_policy = true
allocation_weight = 2
}
west = {
connection_string = var.hub_west_connection_string
location = "westus2"
apply_allocation_policy = true
allocation_weight = 1
}
}
}π‘ With
Hashed,allocation_weightbiases how many devices land on each hub β here roughly 2:1 towardeast.
5 Β· Lowest-latency allocation (GeoLatency)
module "dps" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-iothub-dps.git?ref=v1.0.0"
name = "dps-fleet-global"
resource_group_name = "rg-iot-prod"
location = "eastus"
allocation_policy = "GeoLatency"
linked_hubs = {
east = {
connection_string = var.hub_east_connection_string
location = "eastus"
}
west = {
connection_string = var.hub_west_connection_string
location = "westus2"
}
}
}βΉοΈ
GeoLatencyassigns each device to whichever linked hub is lowest-latency for it β weights are ignored.
6 Β· Pin devices to one hub (Static)
module "dps" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-iothub-dps.git?ref=v1.0.0"
name = "dps-fleet-fixed"
resource_group_name = "rg-iot-prod"
location = "eastus"
allocation_policy = "Static"
linked_hubs = {
only = {
connection_string = var.hub_primary_connection_string
location = "eastus"
}
}
}βΉοΈ
Staticpins allocation to a fixed hub β useful for single-region fleets or migrations.
7 Β· Restrict source ranges with IP filter rules
module "dps" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-iothub-dps.git?ref=v1.0.0"
name = "dps-fleet-prod"
resource_group_name = "rg-iot-prod"
location = "eastus"
# opt in to public reachability, then constrain it
public_network_access_enabled = true
ip_filter_rules = {
"allow-corp" = {
ip_mask = "203.0.113.0/24"
action = "Accept"
}
"deny-rest" = {
ip_mask = "0.0.0.0/0"
action = "Reject"
}
}
}
β οΈ Turningpublic_network_access_enabledon opens the service to the internet. Always pair it withip_filter_rules(or prefer a private endpoint).
8 Β· Target device vs service endpoints separately
module "dps" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-iothub-dps.git?ref=v1.0.0"
name = "dps-fleet-prod"
resource_group_name = "rg-iot-prod"
location = "eastus"
public_network_access_enabled = true
ip_filter_rules = {
"devices-from-field" = {
ip_mask = "198.51.100.0/24"
action = "Accept"
target = "deviceApi"
}
"ops-from-office" = {
ip_mask = "203.0.113.10/32"
action = "Accept"
target = "serviceApi"
}
}
}π‘
targetscopes a rule todeviceApi,serviceApi, orallβ letting devices and operators come from different networks.
9 Β· Data residency (single-region, no geo-pair)
module "dps" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-iothub-dps.git?ref=v1.0.0"
name = "dps-fleet-regional"
resource_group_name = "rg-iot-prod"
location = "eastus2"
data_residency_enabled = true
}
β οΈ data_residency_enabledis immutable and disables the cross-region disaster-recovery replica. Decide before first apply β changing it later forces replacement.
10 Β· Security-hardened variant (private, explicit)
module "dps" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-iothub-dps.git?ref=v1.0.0"
name = "dps-fleet-prod"
resource_group_name = "rg-iot-prod"
location = "eastus"
public_network_access_enabled = false # already the default; stated for reviewability
tags = {
environment = "prod"
data_class = "restricted"
owner = "iot-platform"
}
}π The most locked-down posture: no public reachability. Compose a private endpoint for connectivity.
11 Β· Many linked hubs via for_each at scale
locals {
regional_hubs = {
east = { connection_string = var.hub_east_cs, location = "eastus" }
east2 = { connection_string = var.hub_east2_cs, location = "eastus2" }
west = { connection_string = var.hub_west_cs, location = "westus2" }
central = { connection_string = var.hub_central_cs, location = "centralus" }
}
}
module "dps" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-iothub-dps.git?ref=v1.0.0"
name = "dps-fleet-global"
resource_group_name = "rg-iot-prod"
location = "eastus"
allocation_policy = "GeoLatency"
linked_hubs = local.regional_hubs
}π‘ The map key is a stable handle; adding or removing one hub never re-indexes the others.
12 Β· Tags and custom timeouts
module "dps" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-iothub-dps.git?ref=v1.0.0"
name = "dps-fleet-prod"
resource_group_name = "rg-iot-prod"
location = "eastus"
tags = {
environment = "prod"
cost_center = "iot-1042"
}
timeouts = {
create = "30m"
delete = "30m"
}
}βΉοΈ Omit
timeoutsto inherit provider defaults; set only the phases you need.
13 Β· Consuming resource-group and iothub sibling outputs
module "rg" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-resource-group.git?ref=v1.0.0"
name = "rg-iot-prod"
location = "eastus"
}
module "hub" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-iothub.git?ref=v1.0.0"
name = "iot-fleet-prod"
resource_group_name = module.rg.name
location = module.rg.location
sku = { name = "S1", capacity = 1 }
}
module "dps" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-iothub-dps.git?ref=v1.0.0"
name = "dps-fleet-prod"
resource_group_name = module.rg.name
location = module.rg.location
linked_hubs = {
primary = {
connection_string = var.hub_owner_connection_string # sourced from a secret store, not the hub module output
location = module.rg.location
}
}
}π The hub's owner connection string is a secret provisioned out of band β do not wire a plaintext secret output between modules.
14 Β· ποΈ End-to-end composition
provider "azurerm" {
features {}
}
# 1) Resource group
module "rg" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-resource-group.git?ref=v1.0.0"
name = "rg-iot-prod"
location = "eastus"
tags = { environment = "prod", workload = "iot" }
}
# 2) The IoT hub devices will be allocated to
module "hub" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-iothub.git?ref=v1.0.0"
name = "iot-fleet-prod"
resource_group_name = module.rg.name
location = module.rg.location
sku = { name = "S1", capacity = 1 }
tags = { environment = "prod", workload = "iot" }
}
# 3) The Device Provisioning Service, linking the hub
module "dps" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-iothub-dps.git?ref=v1.0.0"
name = "dps-fleet-prod"
resource_group_name = module.rg.name
location = module.rg.location
allocation_policy = "Hashed"
public_network_access_enabled = false
linked_hubs = {
primary = {
connection_string = var.hub_owner_connection_string # from Key Vault, provisioned out of band
location = module.rg.location
}
}
tags = { environment = "prod", workload = "iot" }
}
# Devices bootstrap against this value
output "dps_id_scope" {
value = module.dps.id_scope
}ποΈ Resource group β IoT hub β DPS. Devices present
module.dps.id_scopeto the global provisioning endpoint and are allocated to the linked hub. The hub connection string stays a secret, provisioned out of band.
Identity (required) β name, resource_group_name, location (all immutable / force-new).
Core (optional, secure defaults) β sku ({ name = "S1", capacity = 1 }), allocation_policy ("Hashed"), data_residency_enabled (false, immutable), public_network_access_enabled (false).
Repeating blocks (keyed maps) β linked_hubs ({}), ip_filter_rules ({}).
Universal tail β tags ({}), timeouts (null).
Full object() schemas
variable "name" { type = string } # immutable
variable "resource_group_name" { type = string } # immutable
variable "location" { type = string } # immutable
variable "sku" {
type = object({
name = optional(string, "S1") # only "S1" is offered
capacity = optional(number, 1) # >= 1
})
default = {}
}
variable "allocation_policy" {
type = string
default = "Hashed" # Hashed | GeoLatency | Static
}
variable "data_residency_enabled" {
type = bool
default = false # immutable; disables the geo-paired DR replica
}
variable "public_network_access_enabled" {
type = bool
default = false # secure default (provider default is true)
}
variable "linked_hubs" {
type = map(object({
connection_string = string # secret; provider marks it sensitive
location = string
apply_allocation_policy = optional(bool) # provider default: true
allocation_weight = optional(number) # provider default: 1
}))
default = {}
}
variable "ip_filter_rules" {
type = map(object({ # map key is the rule name
ip_mask = string # CIDR
action = string # Accept | Reject
target = optional(string) # all | deviceApi | serviceApi
}))
default = {}
}
variable "tags" {
type = map(string)
default = {}
}
variable "timeouts" {
type = object({
create = optional(string)
read = optional(string)
update = optional(string)
delete = optional(string)
})
default = null
}| Output | Description | Notes |
|---|---|---|
id |
Service Resource ID | emitted first |
name |
Service name | β |
location |
Azure region, in the canonical form Azure uses. | Read from the resource, not var.location. |
id_scope |
DPS ID Scope devices present at provisioning time | not a secret |
device_provisioning_host_name |
Device-facing provisioning endpoint hostname | β |
service_operations_host_name |
Service-operations endpoint hostname | β |
resource_group_name |
Resource group holding the service | Force-new. |
sku_name / capacity |
Tier (always S1) and provisioned units |
Capacity is 1β200 and billed continuously. |
billed_whether_used |
Constant true |
A DPS is provisioned throughput, not consumption. |
allocation_policy |
Hashed, GeoLatency or Static |
Inert until more than one hub is linked. |
public_network_access_enabled |
Public reachability, stated positively | Module default false; provider default true. |
data_residency_enabled |
Provisioning data pinned to the region | Force-new, and it removes the geo-paired DR replica. |
linked_hub_count / has_no_linked_hubs |
How many hubs devices can be assigned to | A service with none deploys cleanly and provisions nothing. |
linked_hub_locations |
Map: hub key β that hub's region | Linked hubs need not share this service's region. |
linked_hubs_excluded_from_allocation |
Hubs that will receive no devices | apply_allocation_policy = false, or weight 0 under Hashed. |
accepts_iot_hub_connection_strings |
Constant true |
There is no identity-based alternative on this resource. |
ip_filter_rule_count |
Number of IP filter rules | |
publicly_reachable_from_anywhere |
Public access on, no rules | Every address on the internet reaches both endpoints. |
ip_filter_rules_are_inert |
Rules configured while public access is off | Accepted, stored, restricting nothing. |
id_scope_changes_if_the_service_is_replaced |
Constant true |
A replacement is a fleet-wide reconfiguration. |
βΉοΈ No connection strings are emitted. Linked-hub connection strings are inputs only.
π΄
id_scopeis the fact with the longest reach. Azure issues it at creation and every provisioned device carries it in its own configuration.name,resource_group_name,locationanddata_residency_enabledare all force-new, so changing any one of them replaces the service, issues a new ID Scope, and silently breaks every device already in the field. A plan that reads as one resource replacement is a fleet-wide reconfiguration.
β οΈ The linked-hub connection string is a secret whose drift is invisible. The provider marks itsensitive, which redacts plan output and does not encrypt state β the value sits in the state file in plaintext, so an encrypted, access-controlled backend is the control that matters. Azure returns the key portion as****rather than the real value and the provider suppresses the difference, so rotating the hub's shared-access key out of band produces no drift here: Terraform has nothing real to compare against.
β οΈ Markinglinked_hubssensitive makes everything derived from it sensitive too β a plain count included β and Terraform refuses to emit a sensitive output without an explicit mark. The counts and region maps above are unwrapped withnonsensitive()deliberately; the connection strings are never derived from and never emitted.
- One keystone, no owned children. This module manages exactly one
azurerm_iothub_dps.this. DPS certificates and shared-access policies are separate sibling modules on purpose; this module owns only the service and its inlinesku,linked_hub, andip_filter_ruleblocks. - Keyed maps drive stable rendering.
linked_hubsandip_filter_rulesare keyed maps rendered asdynamicblocks withfor_each, so adding or removing one entry never re-indexes the rest. Theip_filter_ruleskey is used as the rule name. - Force-new fields bite.
name,resource_group_name,location, anddata_residency_enabledare immutable β Terraform replaces the service if you change any of them. Decide on data residency before the first apply. - Secret handling.
linked_hub.connection_stringis marked sensitive by the provider, so it is redacted in plan output and state. Thelinked_hubsvariable is intentionally not declared sensitive at the module level so the keyed map can drivefor_eachβ provision the connection strings out of band and pass references, never literals. The module never emits a connection string. features {}dependence. The module carries noprovider {}block. The service will not plan without a caller-sideprovider "azurerm" { features {} }block; that is expected and lives in the root module.
| Concern | Secure default (empty call) | Opt-out (caller must type it) |
|---|---|---|
| Public network access | public_network_access_enabled = false |
set to true |
| Source-range restriction | no rules, but exposure is off by default | set public_network_access_enabled = true and add ip_filter_rules |
| Secret material | connection strings are inputs, never outputs; provider-sensitive | β |
| Data residency | data_residency_enabled = false (keeps the geo-paired DR replica) |
set to true (immutable) |
terraform init -backend=false
terraform validate
terraform fmt -check- Pin the module at
?ref=v1.0.0β never a branch. - This is plan-only during authoring. A human runs
terraform plan/applyagainst real credentials from CI. - The caller supplies
provider "azurerm" { features {} }, auth, and subscription.
The offline proof gate runs without any cloud calls:
terraform init -backend=falseβ resolves the provider without configuring a backend.terraform validateβ proves the configuration is type-correct against the pinned provider schema; the deeply-typedobject()inputs and thevalidation {}enum guards surface bad values here, before any ARM call.terraform fmt -checkβ enforces canonical formatting.
Only terraform plan (run by a human, against real credentials, from CI) exercises the ARM API. This module is never applied during authoring.
$ terraform output
id = "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-iot-prod/providers/Microsoft.Devices/provisioningServices/dps-fleet-prod"
name = "dps-fleet-prod"
id_scope = "0ne00ABCDEF"
device_provisioning_host_name = "dps-fleet-prod.azure-devices-provisioning.net"
service_operations_host_name = "dps-fleet-prod.azure-devices-provisioning.net"| Symptom | Cause | Fix |
|---|---|---|
Provider configuration not present / init fails on features |
The root module is missing provider "azurerm" { features {} } |
Add the provider block with features {} to the caller's root module. |
| Plan shows the whole service being replaced | You changed name, resource_group_name, location, or data_residency_enabled |
These are immutable. Keep them stable, or accept replacement deliberately. |
sku.name must be "S1" at plan |
A non-S1 SKU was passed |
The Device Provisioning Service only offers S1; set sku.name = "S1" (or omit sku). |
allocation_policy must be one of: Hashed, GeoLatency, Static |
An invalid policy value | Use one of the three legal values. |
| Devices cannot reach the provisioning endpoint | public_network_access_enabled = false (default) with no private path |
Compose a private endpoint, or set public access true and add ip_filter_rules. |
| Allocation weights appear ignored | allocation_policy is GeoLatency or Static, or only one hub is linked |
Weights apply only to Hashed with more than one linked hub. |
| Connection string visible where you did not expect | It was passed as a literal in code | Provision it out of band (Key Vault reference); the provider redacts it in plan/state but committed literals still leak in source. |
- Provider resource:
azurerm_iothub_dps - Sibling:
terraform-azurerm-iothubβ the IoT hub devices are allocated to. - Sibling:
terraform-azurerm-iothub-dps-certificateβ DPS certificate management. azurerm_iothub_dps_shared_access_policyβ DPS shared-access policies. Not yet available as a module in this suite; declare the resource directly for now.- Sibling:
terraform-azurerm-private-endpointβ private connectivity to this service'sid. - Sibling:
terraform-azurerm-monitor-diagnostic-settingβ platform logs/metrics against this service'sid. - This module's
SCOPE.mdβ the cross-module contract.
π "Infrastructure as Code should be standardized, consistent, and secure."