TL;DR
On a recent project, we faced a challenge: deploying an Azure Logic App Consumption workflow that securely connects to other Azure services—like Storage—using Managed Identity. We wanted to avoid the hassle of managing credentials while sticking to our tool of choice, Terraform. But here’s the catch: Terraform doesn’t natively support setting up API connections with Managed Identity for Logic App Consumption workflows.
Instead of settling for manual configurations, we devised a solution. Using Terraform’s azapi_resource for API connections and ARM templates for deploying Logic Apps, we managed to bypass these limitations. Along the way, we set up resource groups, storage accounts, and queues, configured API connections for secure authentication, deployed Logic Apps, and assigned roles to keep everything streamlined. This approach gave us the security and simplicity we needed—without compromising automation.
Problem Statement
While working with Azure Logic App Consumption, we needed to securely connect Logic Apps to Azure services like Storage. Using Managed Identity was the obvious choice: it eliminates the need for hardcoded credentials by letting Azure handle authentication seamlessly.
The problem? Terraform doesn’t yet support configuring API connections with Managed Identity for Logic App Consumption workflows. It’s a known gap in Terraform’s capabilities, as described in its documentation. Specifically, it lacks the ability to directly configure API connections with Managed Identity in Logic App Consumption workflows.
This limitation posed a significant hurdle for our project. We needed a way to deploy Logic Apps that could securely authenticate with Azure services—without resorting to manual steps or insecure workarounds.
Solution
To address this issue, we can leverage Terraform in conjunction with the Azure API to create the necessary resources and configuration for Managed Identity-based authentication in Logic App Consumption. This involves:
- Setting up required infrastructure like resource groups, storage accounts, and queues.
- Implementing API connections with Managed Identity via Terraform’s
azapi_resource
since native support is currently limited. - Deploying the Logic App Consumption using
azurerm_template_deployment
, which will allow us to bypass Terraform’s limitation of directly defining the Logic App with its body.
By following these steps, you can securely deploy Logic App Consumption with Managed Identity for seamless authentication to Azure services without the hassle of managing credentials.
Implementation
- Create resource group
resource "azurerm_resource_group" "rg" { name = local.rg_name location = var.location }
- Set Up a Storage Account and Queue
resource "azurerm_storage_account" "storage" { name = var.storage_account_name location = var.location resource_group_name = azurerm_resource_group.rg.name account_tier = "Standard" account_replication_type = "GRS" public_network_access_enabled = var.public_network_access_enabled } resource "azurerm_storage_queue" "queue" { name = local.queue_name storage_account_name = azurerm_storage_account.storage.name }
- Create an API Connection with Managed Identity
resource "azapi_resource" "create_api_connection" { type = "Microsoft.Web/connections@2016-06-01" name = "storage-queue-connection" location = azurerm_resource_group.rg.location parent_id = azurerm_resource_group.rg.id schema_validation_enabled = false body = jsonencode({ properties = { displayName = "Queue" parameterValueSet = { name = "managedIdentityAuth" #By setting this, we are enforcing Managed Identity on API Connection value = {} } api = { name = "azurequeues" displayName = "Azure Queues" id = "/subscriptions/${data.azurerm_subscription.current.subscription_id}/providers/Microsoft.Web/locations/${azurerm_resource_group.rg.location}/managedApis/azurequeues" } } }) }
- Deploy Logic App Consumption Using ARM Template
Example Logic App Arm Template
{ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "logic_app_name": { "defaultValue": "logicapp-e2e-test-01", "type": "String" }, "location": { "defaultValue": "westus", "type": "String" }, "managed_api_id": { "defaultValue": "", "type": "String" }, "azurequeue_connection_id": { "defaultValue": "", "type": "String" }, "storage_account_path": { "defaultValue": "", "type": "String" }, "trigger_name": { "defaultValue": "", "type": "String" } }, "variables": {}, "resources": [ { "type": "Microsoft.Logic/workflows", "apiVersion": "2017-07-01", "name": "[parameters('logic_app_name')]", "location": "[parameters('location')]", "identity": { "type": "SystemAssigned" }, "properties": { "state": "Enabled", "definition": { "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#", "contentVersion": "1.0.0.0", "parameters": { "$connections": { "defaultValue": {}, "type": "Object" } }, "triggers": { "[parameters('trigger_name')]": { "type": "Request", "kind": "Http", "inputs": { "schema": { "type": "object", "properties": { "id": { "type": "string" }, "source": { "type": "string" }, "specversion": { "type": "string" }, "type": { "type": "string" }, "subject": { "type": "string" }, "time": { "type": "string" }, "data": { "type": "string" } } } } } }, "actions": { "Condition": { "actions": { "For_each": { "foreach": "@triggerBody()", "actions": { "HTTP_Webhook": { "type": "HttpWebhook", "inputs": { "subscribe": { "method": "POST", "uri": "@items('For_each')?['data']?['validationUrl']", "body": { "validationResponse": "@items('For_each')?['data']?['validationCode']" } }, "unsubscribe": {} } } }, "type": "Foreach" } }, "runAfter": {}, "else": { "actions": { "Put_a_message_on_a_queue_(V2)": { "type": "ApiConnection", "inputs": { "host": { "connection": { "name": "@parameters('$connections')['azurequeues-1']['connectionId']" } }, "method": "post", "body": "@triggerBody()?['data']", "path": "[parameters('storage_account_path')]" } } } }, "expression": { "and": [ { "equals": [ "@contains(triggerBody()?['data'],'validationUrl')", "True" ] } ] }, "type": "If" } }, "outputs": {} }, "parameters": { "$connections": { "value": { "azurequeues-1": { "id": "[parameters('managed_api_id')]", "connectionId": "[parameters('azurequeue_connection_id')]", "connectionName": "azurequeues-1", "connectionProperties": { "authentication": { "type": "ManagedServiceIdentity" } } } } } } } } ] } data "template_file" "workflow" { template = file(var.arm_file_path) # ARM template file path } resource "azurerm_resource_group_template_deployment" "logic_app_workflow_deployment" { deployment_mode = "Incremental" name = "workflow_deployment" resource_group_name = azurerm_resource_group.rg.name parameters_content = jsonencode({ "logic_app_name" = var.logic_app_name "location" = var.location "azurequeue_connection_id" = "/subscriptions/${var.subscription_id}/resourceGroups/${azurerm_resource_group.rg.name}/providers/Microsoft.Web/connections/storage-queue-connection" "managed_api_id" = "/subscriptions/${var.subscription_id}/providers/Microsoft.Web/locations/${azurerm_resource_group.rg.location}/managedApis/azurequeues" }) template_content = data.template_file.workflow.template }
- Role Assignment for Managed Identity
resource "azurerm_role_assignment" "logic_app_contributor" { scope = azurerm_storage_account.storage.id role_definition_name = "Storage Queue Data Contributor" principal_id = data.azurerm_logic_app_workflow.logic_app.identity[0].principal_id }
- Extract the Callback URL for the Logic App Trigger (Optional)
When you need to integrate Logic App via URL, you will need
callback_url
that has unique path. As we are usingarm_template_deployment
, we need to extract it viaazapi_resource_action
. However, if you create Logic app trigger with Terraform, you can also use output from trigger definition.data "azapi_resource_action" "callback_url_data" { type = "Microsoft.Logic/workflows/triggers@2019-05-01" action = "listCallbackUrl" resource_id = "/subscriptions/${data.azurerm_subscription.current.subscription_id}/resourceGroups/${azurerm_resource_group.rg.name}/providers/Microsoft.Logic/workflows/${local.logic_app_name}/triggers/${local.trigger_name}" }
Conclusion
The approach for Managed Identity in Logic App Consumption allowed us to enhance security by eliminating manual credentials, while also creating a scalable and maintainable solution for authentication. Along the way, we navigated the current limitations of Terraform, carefully tuning configurations to make the integration seamless and efficient.
The result was a robust and future-proof setup that not only met the immediate needs of the project but also laid a foundation for secure and scalable infrastructure in the future. This experience underscored the importance of thoughtful architecture in building systems that are secure, maintainable, and ready for growth.
Note: the picture that illustrates this article has been generated by AI on Bing Image Creator.