{"id":16037,"date":"2025-01-30T00:00:00","date_gmt":"2025-01-30T08:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/ise\/?p=16037"},"modified":"2025-01-30T02:19:53","modified_gmt":"2025-01-30T10:19:53","slug":"managed-identity-on-logic-app-consumption","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/ise\/managed-identity-on-logic-app-consumption\/","title":{"rendered":"Using Managed Identity on Logic App consumption"},"content":{"rendered":"<h1>TL;DR<\/h1>\n<p>On a recent project, we faced a challenge: deploying an Azure Logic App Consumption workflow that securely connects to other Azure services\u2014like Storage\u2014using Managed Identity. We wanted to avoid the hassle of managing credentials while sticking to our tool of choice, Terraform. But here\u2019s the catch: Terraform doesn\u2019t natively support setting up API connections with Managed Identity for Logic App Consumption workflows.<\/p>\n<p>Instead of settling for manual configurations, we devised a solution. Using Terraform&#8217;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\u2014without compromising automation.<\/p>\n<h2>Problem Statement<\/h2>\n<p>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.<\/p>\n<p>The problem? Terraform doesn&#8217;t yet support configuring API connections with Managed Identity for Logic App Consumption workflows. It\u2019s a known gap in Terraform\u2019s capabilities, as described in its documentation. Specifically, it lacks the ability to directly configure <a href=\"https:\/\/registry.terraform.io\/providers\/hashicorp\/azurerm\/latest\/docs\/resources\/api_connection\">API connections<\/a> with Managed Identity in <a href=\"https:\/\/registry.terraform.io\/providers\/hashicorp\/azurerm\/latest\/docs\/resources\/logic_app_workflow\">Logic App Consumption workflows<\/a>.<\/p>\n<p>This limitation posed a significant hurdle for our project. We needed a way to deploy Logic Apps that could securely authenticate with Azure services\u2014without resorting to manual steps or insecure workarounds.<\/p>\n<h2>Solution<\/h2>\n<p>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:<\/p>\n<ol>\n<li>Setting up required infrastructure like resource groups, storage accounts, and queues.<\/li>\n<li>Implementing API connections with Managed Identity via Terraform&#8217;s <code>azapi_resource<\/code> since native support is currently limited.<\/li>\n<li>Deploying the Logic App Consumption using <code>azurerm_template_deployment<\/code>, which will allow us to bypass Terraform&#8217;s limitation of directly defining the Logic App with its body.<\/li>\n<\/ol>\n<p>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.<\/p>\n<h3>Implementation<\/h3>\n<ol>\n<li>Create resource group\n<pre><code class=\"language-terraform\">resource \"azurerm_resource_group\" \"rg\" {\r\n  name     = local.rg_name\r\n  location = var.location\r\n}<\/code><\/pre>\n<\/li>\n<li>Set Up a Storage Account and Queue\n<pre><code class=\"language-terraform\">resource \"azurerm_storage_account\" \"storage\" {\r\n  name                             = var.storage_account_name\r\n  location                         = var.location\r\n  resource_group_name              = azurerm_resource_group.rg.name\r\n  account_tier                     = \"Standard\"\r\n  account_replication_type         = \"GRS\"\r\n  public_network_access_enabled    = var.public_network_access_enabled\r\n}\r\n\r\nresource \"azurerm_storage_queue\" \"queue\" {\r\n  name                 = local.queue_name\r\n  storage_account_name = azurerm_storage_account.storage.name\r\n}<\/code><\/pre>\n<\/li>\n<li>Create an API Connection with Managed Identity\n<pre><code class=\"language-terraform\">resource \"azapi_resource\" \"create_api_connection\" {\r\n  type                      = \"Microsoft.Web\/connections@2016-06-01\"\r\n  name                      = \"storage-queue-connection\"\r\n  location                  = azurerm_resource_group.rg.location\r\n  parent_id                 = azurerm_resource_group.rg.id\r\n  schema_validation_enabled = false\r\n\r\n  body = jsonencode({\r\n     properties = {\r\n        displayName = \"Queue\"\r\n        parameterValueSet = {\r\n           name  = \"managedIdentityAuth\" #By setting this, we are enforcing Managed Identity on API Connection\r\n           value = {}\r\n        }\r\n        api = {\r\n        name        = \"azurequeues\"\r\n        displayName = \"Azure Queues\"\r\n        id          = \"\/subscriptions\/${data.azurerm_subscription.current.subscription_id}\/providers\/Microsoft.Web\/locations\/${azurerm_resource_group.rg.location}\/managedApis\/azurequeues\"\r\n        }\r\n     }\r\n  })\r\n}<\/code><\/pre>\n<\/li>\n<li>Deploy Logic App Consumption Using ARM Template\n<p>Example Logic App Arm Template<\/p>\n<pre><code class=\"language-json\">  {\r\n  \"$schema\": \"https:\/\/schema.management.azure.com\/schemas\/2019-04-01\/deploymentTemplate.json#\",\r\n  \"contentVersion\": \"1.0.0.0\",\r\n  \"parameters\": {\r\n     \"logic_app_name\": {\r\n           \"defaultValue\": \"logicapp-e2e-test-01\",\r\n           \"type\": \"String\"\r\n     },\r\n     \"location\": {\r\n           \"defaultValue\": \"westus\",\r\n           \"type\": \"String\"\r\n     },\r\n     \"managed_api_id\": {\r\n           \"defaultValue\": \"\",\r\n           \"type\": \"String\"\r\n     },\r\n     \"azurequeue_connection_id\": {\r\n           \"defaultValue\": \"\",\r\n           \"type\": \"String\"\r\n     },\r\n     \"storage_account_path\": {\r\n           \"defaultValue\": \"\",\r\n           \"type\": \"String\"\r\n     },\r\n     \"trigger_name\": {\r\n           \"defaultValue\": \"\",\r\n           \"type\": \"String\"\r\n     }\r\n  },\r\n  \"variables\": {},\r\n  \"resources\": [\r\n     {\r\n           \"type\": \"Microsoft.Logic\/workflows\",\r\n           \"apiVersion\": \"2017-07-01\",\r\n           \"name\": \"[parameters('logic_app_name')]\",\r\n           \"location\": \"[parameters('location')]\",\r\n           \"identity\": {\r\n              \"type\": \"SystemAssigned\"\r\n           },\r\n           \"properties\": {\r\n              \"state\": \"Enabled\",\r\n              \"definition\": {\r\n                 \"$schema\": \"https:\/\/schema.management.azure.com\/providers\/Microsoft.Logic\/schemas\/2016-06-01\/workflowdefinition.json#\",\r\n                 \"contentVersion\": \"1.0.0.0\",\r\n                 \"parameters\": {\r\n                       \"$connections\": {\r\n                          \"defaultValue\": {},\r\n                          \"type\": \"Object\"\r\n                       }\r\n                 },\r\n                 \"triggers\": {\r\n                       \"[parameters('trigger_name')]\": {\r\n                          \"type\": \"Request\",\r\n                          \"kind\": \"Http\",\r\n                          \"inputs\": {\r\n                             \"schema\": {\r\n                                   \"type\": \"object\",\r\n                                   \"properties\": {\r\n                                      \"id\": {\r\n                                         \"type\": \"string\"\r\n                                      },\r\n                                      \"source\": {\r\n                                         \"type\": \"string\"\r\n                                      },\r\n                                      \"specversion\": {\r\n                                         \"type\": \"string\"\r\n                                      },\r\n                                      \"type\": {\r\n                                         \"type\": \"string\"\r\n                                      },\r\n                                      \"subject\": {\r\n                                         \"type\": \"string\"\r\n                                      },\r\n                                      \"time\": {\r\n                                         \"type\": \"string\"\r\n                                      },\r\n                                      \"data\": {\r\n                                         \"type\": \"string\"\r\n                                      }\r\n                                   }\r\n                             }\r\n                          }\r\n                       }\r\n                 },\r\n                 \"actions\": {\r\n                       \"Condition\": {\r\n                          \"actions\": {\r\n                             \"For_each\": {\r\n                                   \"foreach\": \"@triggerBody()\",\r\n                                   \"actions\": {\r\n                                      \"HTTP_Webhook\": {\r\n                                         \"type\": \"HttpWebhook\",\r\n                                         \"inputs\": {\r\n                                               \"subscribe\": {\r\n                                                  \"method\": \"POST\",\r\n                                                  \"uri\": \"@items('For_each')?['data']?['validationUrl']\",\r\n                                                  \"body\": {\r\n                                                     \"validationResponse\": \"@items('For_each')?['data']?['validationCode']\"\r\n                                                  }\r\n                                               },\r\n                                               \"unsubscribe\": {}\r\n                                         }\r\n                                      }\r\n                                   },\r\n                                   \"type\": \"Foreach\"\r\n                             }\r\n                          },\r\n                          \"runAfter\": {},\r\n                          \"else\": {\r\n                             \"actions\": {\r\n                                   \"Put_a_message_on_a_queue_(V2)\": {\r\n                                      \"type\": \"ApiConnection\",\r\n                                      \"inputs\": {\r\n                                         \"host\": {\r\n                                               \"connection\": {\r\n                                                  \"name\": \"@parameters('$connections')['azurequeues-1']['connectionId']\"\r\n                                               }\r\n                                         },\r\n                                         \"method\": \"post\",\r\n                                         \"body\": \"@triggerBody()?['data']\",\r\n                                         \"path\": \"[parameters('storage_account_path')]\"\r\n                                      }\r\n                                   }\r\n                             }\r\n                          },\r\n                          \"expression\": {\r\n                             \"and\": [\r\n                                   {\r\n                                      \"equals\": [\r\n                                         \"@contains(triggerBody()?['data'],'validationUrl')\",\r\n                                         \"True\"\r\n                                      ]\r\n                                   }\r\n                             ]\r\n                          },\r\n                          \"type\": \"If\"\r\n                       }\r\n                 },\r\n                 \"outputs\": {}\r\n              },\r\n              \"parameters\": {\r\n                 \"$connections\": {\r\n                       \"value\": {\r\n                          \"azurequeues-1\": {\r\n                             \"id\": \"[parameters('managed_api_id')]\",\r\n                             \"connectionId\": \"[parameters('azurequeue_connection_id')]\",\r\n                             \"connectionName\": \"azurequeues-1\",\r\n                             \"connectionProperties\": {\r\n                                   \"authentication\": {\r\n                                      \"type\": \"ManagedServiceIdentity\"\r\n                                   }\r\n                             }\r\n                          }\r\n                       }\r\n                 }\r\n              }\r\n           }\r\n     }\r\n  ]\r\n}\r\n\r\ndata \"template_file\" \"workflow\" {\r\n  template = file(var.arm_file_path) # ARM template file path\r\n}\r\n\r\nresource \"azurerm_resource_group_template_deployment\" \"logic_app_workflow_deployment\" {\r\n  deployment_mode      = \"Incremental\"\r\n  name                 = \"workflow_deployment\"\r\n  resource_group_name  = azurerm_resource_group.rg.name\r\n  parameters_content   = jsonencode({\r\n     \"logic_app_name\"       = var.logic_app_name\r\n     \"location\"             = var.location\r\n     \"azurequeue_connection_id\" = \"\/subscriptions\/${var.subscription_id}\/resourceGroups\/${azurerm_resource_group.rg.name}\/providers\/Microsoft.Web\/connections\/storage-queue-connection\"\r\n     \"managed_api_id\"       = \"\/subscriptions\/${var.subscription_id}\/providers\/Microsoft.Web\/locations\/${azurerm_resource_group.rg.location}\/managedApis\/azurequeues\"\r\n  })\r\n  template_content     = data.template_file.workflow.template\r\n}<\/code><\/pre>\n<\/li>\n<li>Role Assignment for Managed Identity\n<pre><code class=\"language-terraform\">resource \"azurerm_role_assignment\" \"logic_app_contributor\" {\r\n  scope                = azurerm_storage_account.storage.id\r\n  role_definition_name = \"Storage Queue Data Contributor\"\r\n  principal_id         = data.azurerm_logic_app_workflow.logic_app.identity[0].principal_id\r\n}<\/code><\/pre>\n<\/li>\n<li>Extract the Callback URL for the Logic App Trigger (Optional)\n<p>When you need to integrate Logic App via URL, you will need <code>callback_url<\/code> that has unique path. As we are using <code>arm_template_deployment<\/code>, we need to extract it via <code>azapi_resource_action<\/code>. However, if you create Logic app trigger with Terraform, you can also use <a href=\"https:\/\/registry.terraform.io\/providers\/hashicorp\/azurerm\/latest\/docs\/resources\/logic_app_trigger_http_request#attributes-reference\">output<\/a> from trigger definition.<\/p>\n<pre><code class=\"language-terraform\">data \"azapi_resource_action\" \"callback_url_data\" {\r\n  type                   = \"Microsoft.Logic\/workflows\/triggers@2019-05-01\"\r\n  action                 = \"listCallbackUrl\"\r\n  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}\"\r\n}<\/code><\/pre>\n<\/li>\n<\/ol>\n<h2>Conclusion<\/h2>\n<p>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.<\/p>\n<p>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.<\/p>\n<p><em>Note: the picture that illustrates this article has been generated by AI on <a href=\"https:\/\/www.bing.com\/images\/create\">Bing Image Creator<\/a>.<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Deploy Azure Logic App Consumption with Managed Identity using Terraform by leveraging azapi_resource and ARM templates. This setup enables secure authentication without manual credential management.<\/p>\n","protected":false},"author":172176,"featured_media":16038,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[10,1],"tags":[3400],"class_list":["post-16037","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-azure-app-services","category-cse","tag-ise"],"acf":[],"blog_post_summary":"<p>Deploy Azure Logic App Consumption with Managed Identity using Terraform by leveraging azapi_resource and ARM templates. This setup enables secure authentication without manual credential management.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/posts\/16037","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/users\/172176"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/comments?post=16037"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/posts\/16037\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/media\/16038"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/media?parent=16037"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/categories?post=16037"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/tags?post=16037"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}