I'm attempting to deploy a standard logic app with a service bus connector using a user assigned managed identity but I can't get it to work via terraform and ARM.
It looks connected in portal when I edit the workflow in designer...
But when I actually trigger the workflow I get the following error...
Failed to get oauth token for managed identity in logic app. Response: '{"statusCode":400,"message":"No User Assigned or Delegated Managed Identity found for specified ClientId/ResourceId/PrincipalId.","correlationId":"3b95b432-d690-4703-a571-c5e0d9730c43"}'
This is my service bus api connection...
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"connections_servicebus_name": {
"defaultValue": "servicebus",
"type": "String"
},
"location": {
"defaultValue": "uksouth",
"type": "String"
},
"principal_id": {
"type": "String"
},
"servicebus_namespace": {
"type": "String"
},
"subscriptionId": {
"type": "String"
},
"tenant_id": {
"type": "String"
}
},
"variables": {},
"resources": [
{
"type": "Microsoft.Web/connections",
"apiVersion": "2016-06-01",
"name": "[parameters('connections_servicebus_name')]",
"location": "[parameters('location')]",
"kind": "V2",
"properties": {
"api": {
"id": "[concat('/subscriptions/', parameters('subscriptionId'), '/providers/Microsoft.Web/locations/', parameters('location'), '/managedApis/servicebus')]"
},
"parameterValueSet": {
"name": "managedIdentityAuth",
"values": {
"namespaceEndpoint": {
"value": "[concat('sb://', parameters('servicebus_namespace'), '.servicebus.windows.net/')]"
}
}
},
"displayName": "[parameters('connections_servicebus_name')]"
}
},
{
"type": "Microsoft.Web/connections/accessPolicies",
"apiVersion": "2016-06-01",
"name": "[concat(parameters('connections_servicebus_name'),'/',parameters('principal_id'))]",
"location": "[parameters('location')]",
"dependsOn": [
"[resourceId('Microsoft.Web/connections', parameters('connections_servicebus_name'))]"
],
"properties": {
"principal": {
"type": "ActiveDirectory",
"identity": {
"objectId": "[parameters('principal_id')]",
"tenantId": "[parameters('tenant_id')]"
}
}
}
}
],
"outputs": {
"connectionRuntimeUrl": {
"type": "String",
"value": "[reference(resourceId('Microsoft.Web/connections', parameters('connections_servicebus_name'))).connectionRuntimeUrl]"
}
}
}
This is the terraform for deploying the above ARM template...
data "template_file" "servicebus_connection" {
template = file("../logic-apps/api-connections/servicebus.json")
}
resource "azurerm_resource_group_template_deployment" "servicebus_connection" {
resource_group_name = data.azurerm_resource_group.rg.name
template_content = data.template_file.servicebus_connection.template
parameters_content = jsonencode({
"principal_id" = { value = "${data.azurerm_user_assigned_identity.identity.principal_id}" }
"subscriptionId" = { value = "${var.target-subscription-id}" }
"servicebus_namespace" = { value = "pip-exec" }
"tenant_id" = { value = "${data.azurerm_user_assigned_identity.identity.tenant_id}" }
}
)
name = "connection-${filemd5("../logic-apps/api-connections/servicebus.json")}"
deployment_mode = "Incremental"
lifecycle {
ignore_changes = [
parameters_content
]
}
}
This is the terraform for my standard logic app deployment....
resource "azurerm_logic_app_standard" "product_feed_4" {
depends_on = [
azurerm_resource_group_template_deployment.servicebus_connection,
azurerm_resource_group_template_deployment.keyvault_connection ]
name = "product-feed-5"
location = "uksouth"
resource_group_name = data.azurerm_resource_group.rg.name
enabled = true
storage_account_name = data.azurerm_storage_account.storage_account.name
app_service_plan_id = azurerm_service_plan.slo_app_plan.id
storage_account_access_key = data.azurerm_storage_account.storage_account.primary_access_key
https_only = true
version = "~4"
identity {
type = "UserAssigned"
identity_ids = [ data.azurerm_user_assigned_identity.identity.id ]
}
app_settings = {
"FUNCTIONS_WORKER_RUNTIME" = "node"
"WEBSITE_NODE_DEFAULT_VERSION" = "~18"
"keyVault_VaultUri" = data.azurerm_key_vault.key-vault.vault_uri
"ResourceGroup" = var.resource_group
"SubscriptionId" = var.target-subscription-id
"UserAssignedManagedIdentity" = data.azurerm_user_assigned_identity.identity.name
"connectionRuntimeUrl" = jsondecode(azurerm_resource_group_template_deployment.servicebus_connection.output_content).connectionRuntimeUrl.value
}
}
This is my connections.json
...
{
"managedApiConnections": {
"servicebus": {
"api": {
"id": "/subscriptions/@appsetting('SubscriptionId')/providers/Microsoft.Web/locations/uksouth/managedApis/servicebus"
},
"authentication": {
"identity": "/subscriptions/@appsetting('SubscriptionId')/resourcegroups/@appsetting('ResourceGroup')/providers/Microsoft.ManagedIdentity/userAssignedIdentities/@appsetting('UserAssignedManagedIdentity')",
"type": "ManagedServiceIdentity"
},
"connection": {
"id": "/subscriptions/@appsetting('SubscriptionId')/resourceGroups/@appsetting('ResourceGroup')/providers/Microsoft.Web/connections/servicebus"
},
"connectionProperties": {
"authentication": {
"audience": "https://servicebus.azure.net",
"identity": "/subscriptions/@appsetting('SubscriptionId')/resourcegroups/@appsetting('ResourceGroup')/providers/Microsoft.ManagedIdentity/userAssignedIdentities/@appsetting('UserAssignedManagedIdentity')",
"type": "ManagedServiceIdentity"
}
},
"connectionRuntimeUrl": "@appsetting('connectionRuntimeUrl')"
}
}
}
And finally, this is the JSON representation of my workflow which just has 1 service bus action after the trigger...
{
"definition": {
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
"actions": {
"Get_messages_from_a_queue_(peek-lock)": {
"inputs": {
"host": {
"connection": {
"referenceName": "servicebus"
}
},
"method": "get",
"path": "/@{encodeURIComponent(encodeURIComponent('narvar_events'))}/messages/batch/peek",
"queries": {
"maxMessageCount": 20,
"queueType": "Main",
"sessionId": ""
}
},
"runAfter": {},
"type": "ApiConnection"
}
},
"contentVersion": "1.0.0.0",
"outputs": {},
"triggers": {
"When_a_HTTP_request_is_received": {
"kind": "Http",
"type": "Request"
}
}
},
"kind": "Stateful"
}
Where am I going wrong here?
The API connection shows as 'connected'...
And the user assigned managed identity has the 'Azure Service Bus Data Owner' role against the service bus...