Deploying Azure Logic Apps + Managed Identity with Bicep

Today I needed to migrate an Azure Logic App from a test environment into our project’s Ressource Group and connect it to the Blob Storage using Managed Identity. Since we already have pipelines in place with a nice little Bicep script for all the infrastructure I wanted it also to be part of this deployment process.

Here are the things that needed solving:

  • Deploying the Logic App with environment-specific parameters
  • Makeing it easy to update the Logic App definition without having to touch the Bicep file
  • Connecting Logic App to Azure Blob Storage using an Azure Managed Identity

To have the Logic App definition separate from the Bicep template this StackOverflow post helped a lot. Long story short, you can simply export the definition in the Azure Portal as a JSON document and then load it into Bicep through the json(loadTextContent(‘file.json’)) commands. Just be aware that if the JSON file becomes too big you might need to pass it as a parameter instead.

While the JSON also includes all information regarding the parameters for the Logic App, this part we’ll translate into Bicep manually so we can pass our environment-aware values like the name of our Azure Storage account.

With this idea in place the Bicep file itself is pretty straight forward. But there were a few pitfalls along the way I want to point out beforehand:

  • The API Connection for Azure BLOB Storage needs to be created through the “Microsoft.Web/connections@2018-07-01-preview” version which at the time of writing Bicep didn’t recognize and therefore issued a warning. All older versions failed for me, though.
  • Both the API Connection and the Logic App need to be configured for using Managed Identity for authentication.
  • Since we’re adding the Logic App’s Managed Identity as a Role Assignment to Azure Storage, the user / service principal running the deployment script needs either Owner permissions or an appropriate Security Group membership for the Ressource Group. Being a Contributor unfortunately is not enough.

So here it is, the Bicep script containing the Storage Account + Role Assignment, the Logic App with definition stored as separate JSON document and the API Connector so we can work with our BLOB Storage.

param location string = resourceGroup().location
param roleDefinitionId string = 'ba92f5b4-2d11-453d-a403-e96b0029c9fe' //Default as Storage Blob Data Contributor role
var storageAccountName = 'mystorageaccountname'
var logicAppDefinition = json(loadTextContent('definition.json'))
resource storageAccount 'Microsoft.Storage/storageAccounts@2021-04-01' = {
name: storageAccountName
location: location
sku: {
name: 'Standard_LRS'
}
kind: 'StorageV2'
properties: {
accessTier: 'Hot'
allowBlobPublicAccess: true
supportsHttpsTrafficOnly: true
minimumTlsVersion: 'TLS1_2'
}
}
resource blobConnection 'Microsoft.Web/connections@2018-07-01-preview' = {
name: 'blobConnectionName'
location: location
kind: 'V1'
properties: {
alternativeParameterValues: {}
api: {
id: 'subscriptions/${subscription().subscriptionId}/providers/Microsoft.Web/locations/${location}/managedApis/azureblob'
}
customParameterValues: {}
displayName: defaultName
parameterValueSet: {
name: 'managedIdentityAuth'
values: {}
}
}
}
resource logicapp 'Microsoft.Logic/workflows@2019-05-01' = {
name: 'logicAppName'
location: location
identity: {
type: 'SystemAssigned'
}
properties: {
state: 'Enabled'
definition: logicAppDefinition.definition
parameters: {
'$connections': {
value: {
azureblob: {
connectionId: blobConnection.id
connectionName: 'azureblob'
id: 'subscriptions/${subscription().subscriptionId}/providers/Microsoft.Web/locations/${location}/managedApis/azureblob'
connectionProperties: {
authentication: {
type: 'ManagedServiceIdentity'
}
}
}
}
}
'storageAccount': {
value: storageAccountName
}
}
}
}
resource logicAppStorageAccountRoleAssignment 'Microsoft.Authorization/roleAssignments@2020-10-01-preview' = {
scope: storageAccount
name: guid('ra-logicapp-${roleDefinitionId}')
properties: {
principalType: 'ServicePrincipal'
roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitionId)
principalId: logicapp.identity.principalId
}
}
view raw logicapp.bicep hosted with ❤ by GitHub

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.