Terraform is a great Infrastructure as Code tool, but it does have its limitations. Sometimes we want to deploy a resource in Azure that doesn’t have a written provider for it. This could be due to a product currently in preview, no one has yet to write that provider, or maybe there is a provider but there are other outlying issues.
The Problem…
What happens when we want to deploy a resource that cannot be entirely managed by Terraform? Maybe the Terraform provider doesn’t exist, or the provider doesn’t allow the full configuration of the resource? When you’re trying to deploy a full end to end, automated system, this disrupts the CI/CD process in what we’re trying to achieve, but maybe…there is a way!
Logic Apps are awesome, they’re great for creating a mechanism to transact a workflow or provide a light orchestration between systems. They’re easy to use and get started with. The complexity comes in when you attempt to go a bit further with that Logic App…
A Logic App can be configured from the portal using the designer:

You can also use the extension in VSCode:

Requirements
- Deploy Logic Apps using Terraform to maintain the consistency of Infrastructre as Code for our deployments
- Make the solution easy to design and maintain
- Pass Terraform variables into Logic App parameters
- Deploy the solution using Azure DevOps pipelines – CI/CD
Solution
For the project that I just completed the designer was the best way for us to deploy our Logic Apps, it was visually friendly for the customer (which led to better long-term maintenance of the solution), and there were issues with using the Logic Apps extension in VSCode using devcontainers. While there were other constraints in the project around security and data residency, we’re just going to focus on getting the Logic App deployed.
Terraform allowed the project team to utilize IaC (Infrastructure as Code) to deploy all the project resources to Azure. This also enabled the team to script out all changes, create and implement better testing capability, and allow for an automated deployment where possible. This also removes the developer from having to directly deploy or modify resources in the project that could break the system or even cause a security breach. All deployments of the Logic Apps into the environments were done using Azure DevOps and a configured Azure Service Principal.
We had to do all Logic App configuration directly from the portal in designer view. We used an HTTP trigger to initiate the workflow, adding in the additional items that were needed to process our workflow. Once we had created the workflow, we then needed to export it (note: export the template, not the workflow definition). The exported JSON template then needs to be validated using an IDE (VSCode was our IDE of choice). The export was not entirely seamless, it required a bit of manipulation to the data output to become a viable ARM (Azure Resource Manager) template.
The template required correction of any validation errors, which became critical to being able to utilize the template in our deployment pipeline. Once the validation errors are resolved and all other changes were configured, the JSON template file was migrated into the codebase. The Logic App JSON files sat in a separate folder structure in the repo to be referenced during deployment. As shown below, the top red box is showing the Terraform file structure for the infrastructure deployment. The second box is the separate folder for the Logic App json files.

Once the Logic App was in the code base, it was then ready to be deployed.
Deployment of the Logic App was done using Terraform and the trigger of an Azure DevOps pipeline.
The steps of how this was executed can be found down below.
Terraform Code
Note: The repository containing the full end to end code can be found here.
- Create the Logic App workflow from either the portal or from VSCode using the extension
- Export the template (if using the portal) and modify and validate the Logic App.
- Save the JSON file to your repo (or saved file location). It is recommended to save your Logic App files away from the Terraform files as shown below.
- Write your Terraform code calling the JSON workflow file. This can be done using a flat file (call the resource) or using modules (call the module). The code snippet below deploys the Logic App workflow using the ARM JSON template.
// Create an instance of logic app and configure the tags
resource "azurerm_logic_app_workflow" "logicapp" {
location = "westeurope"
resource_group_name = var.shared_env.rg.name
tags = var.shared_env.tags
}
// Deploy the ARM template to configure the workflow in the Logic App
data "template_file" "workflow" {
template = file(local.arm_file_path)
}
// Deploy the ARM template workflow
resource "azurerm_template_deployment" "workflow" {
depends_on = [azurerm_logic_app_workflow.logicapp]
resource_group_name = var.shared_env.rg.name
parameters = merge({
"workflowName" = var.workflow_name,
"location" = "westeurope"
}, var.parameters)
template_body = data.template_file.workflow.template
}
5. Alternative step: you can use the updated provider capability to deploy the actions (we didn’t attempt this as the customer preferred the visual designer). You can reference the customs actions and try building out your workflow from there. As we had some fairly complex workflows, we stuck to using the designer.
6. Deploy your code!
Sample Code
To access the full Terraform code that was used during this project, you can access it here.
Deployment with Azure DevOps
Following the steps above and going a bit further, we can implement this deployment into a CI/CD pipeline. Our code is already sitting in our repo, so we can create a deployment pipeline that allows us to execute and deploy our code. We created our deployment pipeline using YAML, using ‘tfdeploy’ to initiate our Terraform deployment:
jobs:
- deployment: tfdeploy
displayName: Deploy Terraform to Test
environment: Test
Viola!
To look at further securing your Logic App, read my blog post here.
[…] If you want to read how we deployed the Logic Apps using Terraform read this. […]
LikeLike
Great work and explanation.
Did you manage to include automated tests for the logic app itself? Meaning all the possible paths of it are tested?
LikeLike
I see there’s some integration tests in the project. Is it possible to mock the answer to, for example, to some HTTP requests? Do you know where I can find more information about this topic?
Thanks a lot.
LikeLike
For Apple Silicon users, you may want to switch the use of `template_file` for the `templatefile` function – using the former results in Terraform being unable to install the ‘template’ dependency on M1 machines. If you see this error:
Provider registry.terraform.io/hashicorp/template v2.2.0 does not have a package available for your current platform, darwin_arm64.
then you’ll want to switch the usage as above 🙂
Refs: https://registry.terraform.io/providers/hashicorp/template/latest/docs/data-sources/file and https://www.terraform.io/language/functions/templatefile
LikeLike
For Apple Silicon users, you may want to switch the use of `template_file` for the `templatefile` function – using the former results in Terraform being unable to install the ‘template’ dependency on M1 machines. If you see this error:
Provider registry.terraform.io/hashicorp/template v2.2.0 does not have a package available for your current platform, darwin_arm64.
then you’ll want to switch the usage as above 🙂
Refs: https://registry.terraform.io/providers/hashicorp/template/latest/docs/data-sources/file and https://www.terraform.io/language/functions/templatefile
LikeLiked by 1 person
You now have a Terraform state file that is aware of the Logic App, but unaware of / disconnected from changes made to that resource by deploying the workflow using an ARM template. Are you concerned this will create problems down the road as Terraform will always view the Logic App as having drifted and want to re-deploy?
Also, curious why you took the two-step approach instead of allowing the ARM template to both create the Logic App and populate the workflow. What were the advantages?
LikeLike
That is the number 1 issue with embedding an ARM template into Terraform, if you change the resource TF could potentially throw a fit. I usually try to avoid it. In this specific use case we had to use Terraform for the project, there was not a way to deploy a Logic App with the Terraform provider inherently, enter in deploying the ARM template. In our case, if there was any change to the code or the Logic App (or any other infrastructure element), there was an infra check and everything would re-deploy from our pipelines. It was full CI/CD end to end and everything was automated and repeatedly. You have to remember, TF just monitors the state file and will check if the resources exists, it won’t re-deploy unless there was a distinct change in infrastructure config. It won’t look to inspect the config of the Logic App, same as if you changed the OS on a VM. Unless you started changing networking, disks, etc, TF won’t change the resource.
Many people want to use TF and not ARM or Bicep. For the use case at the time, it was down to the customer’s skill sets and preferences. Having to then skill them up on ARM was not part of the project scope.
LikeLike
[…] Deploying a LogicApp with Terraform […]
LikeLike