Unable to Create IoT Hub DPS Resource Due to Policy Restriction in Azure Playground

Hey,

I’m currently working in the KodeKloud Azure playground and attempting to deploy an IoT Hub Device Provisioning Service using Terraform. However, the deployment fails with the following error:

│ Error: creating/updating IoT Device Provisioning Service Iot Hub Dps: (Provisioning Service Name "iot-hub-dps-staging-fleet-inverter" / Resource Group "kml_rg_main-eb46a953f95f4f82"): iothub.IotDpsResourceClient#CreateOrUpdate: Failure sending request: StatusCode=403 -- Original Error: Code="RequestDisallowedByPolicy" Message="Resource 'iot-hub-dps-staging-fleet-inverter' was disallowed by policy. Reasons: 'Allowed values for IoT Hub Device Provisioning Service: SKU = 'S1' | Tier = 'Standard' | Capacity = 1. Update configuration to comply.'. See error details for policy resource IDs." Target="iot-hub-dps-staging-fleet-inverter" AdditionalInfo=[{"info":{"evaluationDetails":{"evaluatedExpressions":[{"expression":"type","expressionKind":"Field","expressionValue":"Microsoft.Devices/provisioningServices","operator":"Equals","path":"type","result":"True","t0ca-bade2bac4df4-kml","policyAssignmentId":"/subscriptions/a2b28c85-1948-4263-90ca-bade2bac4df4/providers/Microsoft.Authorization/policyAssignments/global-limits_a2b28c85-1948-4263-90ca-bade2bac4df4-kml","policyAssignmentName":"global-limits_a2b28c85-1948-4263-90ca-bade2bac4df4-kml","policyAssignmentParameters":{},"policyAssignmentScope":"/subscriptions/a2b28c85-1948-4263-90ca-bade2bac4df4","policyDefinitionDisplayName":"iot_dps-kml","policyDefinitionEffect":"deny","policyDefinitionId":"/subscriptions/a2b28c85-1948-4263-90ca-bade2bac4df4/providers/Microsoft.Authorization/policyDefinitions/iot_dps-kml","policyDefinitionName":"iot_dps-kml","policyDefinitionReferenceId":"iot_dps-kml_ref","policyDefinitionVersion":"1.0.0","policyEnrollmentIds":[],"policyExemptionIds":[],"policySetDefinitionDisplayName":"global-limits_a2b28c85-1948-4263-90ca-bade2bac4df4-kml","policySetDefinitionId":"/subscriptions/a2b28c85-1948-4263-90ca-bade2bac4df4/providers/Microsoft.Authorization/policySetDefinitions/global-limits_a2b28c85-1948-4263-90ca-bade2bac4df4-kml","policySetDefinitionName":"global-limits_a2b28c85-1948-4263-90ca-bade2bac4df4-kml","policySetDefinitionVersion":"1.0.0"},"type":"PolicyViolation"}]
│
│   with azurerm_iothub_dps.iothub_dps_fleet_inverter,
│   on main.tf line 40, in resource "azurerm_iothub_dps" "iothub_dps_fleet_inverter":
│   40: resource "azurerm_iothub_dps" "iothub_dps_fleet_inverter" {

I’ve ensured that the DPS resource is configured with:

SKU: S1
Tier: Standard
Capacity: 1

(As in Terraform the sku config only has the parameters capacity and name, the tier should default to Standard)

This is the main terraform file:

# resource "azurerm_resource_group" "rg_fleet_inverter" {
#   name     = "rg-${var.environment}-fleet-inverter"
#   location = var.location

#   tags = {
#     "env"   = var.environment
#     "owner" = "team-123"
#   }
# }


resource "azurerm_iothub_shared_access_policy" "iothub_fleet_inverter_policy" {
  name                = "iothub-${var.environment}-owner-fleet-inverter"
  iothub_name         = azurerm_iothub.iothub_fleet_inverter.name
  resource_group_name = var.playground_rg_name

  registry_read   = true
  registry_write  = true
  service_connect = true
  device_connect  = true
}


resource "azurerm_iothub" "iothub_fleet_inverter" {
  name                = "iot-hub-${var.environment}-fleet-inverter"
  location            = var.location
  resource_group_name = var.playground_rg_name

  sku {
    name     = "S1"
    capacity = 1
  }

  tags = {
    "env"   = var.environment
    "owner" = "team-titan"
  }
}

resource "azurerm_iothub_dps" "iothub_dps_fleet_inverter" {
  name                = "iot-hub-dps-${var.environment}-fleet-inverter"
  location            = var.location
  resource_group_name = var.playground_rg_name
  allocation_policy   = "Hashed" # based on their device id -> even and deterministic distribution (same device always on same hub)}

  sku {
    name     = "S1"
    capacity = 1
  }

  linked_hub {
    # (we also could define more than one linked hub inside a dps)
    # based on this, more or less devices are registered on exactly this linked hub 
    allocation_weight       = 1
    apply_allocation_policy = true
    connection_string       = azurerm_iothub_shared_access_policy.iothub_fleet_inverter_policy.primary_connection_string
    location                = var.location
  }
}

This is the provider configuration:

# Configure the Azure provider
terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~> 3.0.2"
    }
  }

  required_version = ">= 1.1.0"
}

provider "azurerm" {
  features {}
  skip_provider_registration = true
}

As the playground is limited due to terraform resource provider registration, I had to configure the skipping behavior. Maybe this causes the problem?

Could you please help me understand the cause of the error?
Is this playground meant for the usage with Terraform?

I’m not sure where (or even how) to specify the tier, which seems to be the missing in your specification. I’ve looked at the terraform docs, and it seems like this is not specified as part of the azurerm_iothub, but of some kind of container for it. Can’t tell you much more than that.