Logic Apps Standard simplifies deployment tasks by separating infrastructure and code deployments. If you are interested in setting up the full end-to-end CI/CD pipeline for Logic Apps n Azure DeveOps, you can find detailed description of these steps in the blog Deploying Logic App Standard resource through DevOps pipeline - Microsoft Community Hub
In this blog, we will explore the creation of Logic app infrastructure components using Azure Biceps template.
Bicep is a domain-specific language (DSL) that uses a declarative syntax to deploy Azure resources. In a Bicep file, you define the infrastructure you want to deploy to Azure, and then use that file throughout the development lifecycle to deploy your infrastructure repeatedly.
The Bicep VS Code extension helps to decompile ARM JSON template into Bicep template and also provides intellisense for writing the Bicep code.
In this example, I am using an existing ARM template for Logic App standard and decompiling it into Bicep template.
Alternatively, you can export the logic app template from the logic app in the Azure portal.
If you are exporting the template from Azure portal, make sure to follow the following steps:
If it isn’t removed, the deployment would fail with the error "'Runtime Scale Monitoring is not supported for this Functions version"
I am using the ARM template for Logic App Standard deployment from the repository- LogicAppStandard/logicapp-template.json at master · ShreeDivyaMV/LogicAppStandard (github.com)
Install Bicep VS Code extension on VS Code and open this file. Right-click on the ARM template and select “Decompile into Bicep”
It would create a Bicep file in the same folder with the same name (e.g. template.bicep). The resulting Bicep template would look like the one below.
param sites_shmvlastandarddemo1_name string = 'shmvlastandarddemo1'
param serverfarms_LAStandardDeploymentASPdemo1_externalid string = '/subscriptions/ea3e783f-6b4a-4e74-b379-9fa512da2b7f/resourceGroups/TriageDemo/providers/Microsoft.Web/serverfarms/LAStandardDeploymentASPdemo1'
param virtualNetworks_LAV2VNET_externalid string = '/subscriptions/<subscriptionID>/resourceGroups/PrivateEndpointVeeraTemplate/providers/Microsoft.Network/virtualNetworks/LAV2VNET'
resource sites_shmvlastandarddemo1_name_resource 'Microsoft.Web/sites@2022-03-01' = {
name: sites_shmvlastandarddemo1_name
location: 'East US'
tags: {
Environment: 'dev'
Project: 'logicappsample'
}
kind: 'functionapp,workflowapp'
identity: {
type: 'SystemAssigned'
}
properties: {
enabled: true
hostNameSslStates: [
{
name: '${sites_shmvlastandarddemo1_name}.azurewebsites.net'
sslState: 'Disabled'
hostType: 'Standard'
}
{
name: '${sites_shmvlastandarddemo1_name}.scm.azurewebsites.net'
sslState: 'Disabled'
hostType: 'Repository'
}
]
serverFarmId: serverfarms_LAStandardDeploymentASPdemo1_externalid
reserved: false
isXenon: false
hyperV: false
vnetRouteAllEnabled: true
vnetImagePullEnabled: false
vnetContentShareEnabled: false
scmSiteAlsoStopped: false
clientAffinityEnabled: false
clientCertEnabled: false
clientCertMode: 'Required'
hostNamesDisabled: false
customDomainVerificationId: '75E6CA55AA209D7CA6DAD86D9D0FC9A27D1EA10B12483E62DF91E9605058419C'
containerSize: 1536
dailyMemoryTimeQuota: 0
httpsOnly: true
redundancyMode: 'None'
storageAccountRequired: false
virtualNetworkSubnetId: '${virtualNetworks_LAV2VNET_externalid}/subnets/Subnet1'
keyVaultReferenceIdentity: 'SystemAssigned'
}
}
resource sites_shmvlastandarddemo1_name_ftp 'Microsoft.Web/sites/basicPublishingCredentialsPolicies@2022-03-01' = {
parent: sites_shmvlastandarddemo1_name_resource
name: 'ftp'
location: 'East US'
tags: {
Environment: 'dev'
Project: 'logicappsample'
}
properties: {
allow: true
}
}
resource sites_shmvlastandarddemo1_name_scm 'Microsoft.Web/sites/basicPublishingCredentialsPolicies@2022-03-01' = {
parent: sites_shmvlastandarddemo1_name_resource
name: 'scm'
location: 'East US'
tags: {
Environment: 'dev'
Project: 'logicappsample'
}
properties: {
allow: true
}
}
resource sites_shmvlastandarddemo1_name_web 'Microsoft.Web/sites/config@2022-03-01' = {
parent: sites_shmvlastandarddemo1_name_resource
name: 'web'
location: 'East US'
tags: {
Environment: 'dev'
Project: 'logicappsample'
}
properties: {
numberOfWorkers: 1
defaultDocuments: [
'Default.htm'
'Default.html'
'Default.asp'
'index.htm'
'index.html'
'iisstart.htm'
'default.aspx'
'index.php'
]
netFrameworkVersion: 'v4.0'
requestTracingEnabled: false
remoteDebuggingEnabled: false
remoteDebuggingVersion: 'VS2019'
httpLoggingEnabled: false
acrUseManagedIdentityCreds: false
logsDirectorySizeLimit: 35
detailedErrorLoggingEnabled: false
publishingUsername: '$shmvlastandarddemo1'
scmType: 'VSTSRM'
use32BitWorkerProcess: true
webSocketsEnabled: false
alwaysOn: false
managedPipelineMode: 'Integrated'
virtualApplications: [
{
virtualPath: '/'
physicalPath: 'site\\wwwroot'
preloadEnabled: false
}
]
loadBalancing: 'LeastRequests'
experiments: {
rampUpRules: []
}
autoHealEnabled: false
vnetName: 'aaf431f7-0911-45ac-8b14-c4b0020cfbd2_Subnet1'
vnetRouteAllEnabled: true
vnetPrivatePortsCount: 0
localMySqlEnabled: false
managedServiceIdentityId: 31238
ipSecurityRestrictions: [
{
ipAddress: 'Any'
action: 'Allow'
priority: 2147483647
name: 'Allow all'
description: 'Allow all access'
}
]
scmIpSecurityRestrictions: [
{
ipAddress: 'Any'
action: 'Allow'
priority: 2147483647
name: 'Allow all'
description: 'Allow all access'
}
]
scmIpSecurityRestrictionsUseMain: false
http20Enabled: false
minTlsVersion: '1.2'
scmMinTlsVersion: '1.2'
ftpsState: 'AllAllowed'
preWarmedInstanceCount: 1
functionAppScaleLimit: 0
minimumElasticInstanceCount: 1
azureStorageAccounts: {
}
}
}
resource sites_shmvlastandarddemo1_name_sites_shmvlastandarddemo1_name_azurewebsites_net 'Microsoft.Web/sites/hostNameBindings@2022-03-01' = {
parent: sites_shmvlastandarddemo1_name_resource
name: '${sites_shmvlastandarddemo1_name}.azurewebsites.net'
location: 'East US'
properties: {
siteName: 'shmvlastandarddemo1'
hostNameType: 'Verified'
}
}
resource sites_shmvlastandarddemo1_name_aaf431f7_0911_45ac_8b14_c4b0020cfbd2_Subnet1 'Microsoft.Web/sites/virtualNetworkConnections@2022-03-01' = {
parent: sites_shmvlastandarddemo1_name_resource
name: 'aaf431f7-0911-45ac-8b14-c4b0020cfbd2_Subnet1'
location: 'East US'
properties: {
vnetResourceId: '${virtualNetworks_LAV2VNET_externalid}/subnets/Subnet1'
isSwift: true
}
}
output logicAppSystemAssignedIdentityTenantId string = subscription().tenantId
output logicAppSystemAssignedIdentityObjectId string = reference(sites_shmvlastandarddemo1_name_resource.id, '2019-08-01', 'full').identity.principalId
output LAname string = sites_shmvlastandarddemo1_name
Right click on the Bicep file and click on “Deploy Bicep file”. It would ask for few details like resource group name and parameter values. Once you provide the parameter values, you can choose to save them as a parameter file too.
As part of the infrastructure pipeline, we would deploy the API connections, add access policy to the logic app’s managed identity, and export the connection runtime URL as an app setting.
For this example, I have taken the connections ARM template from this repository - LogicAppStandard/connectors-template.json at master · ShreeDivyaMV/LogicAppStandard (github.com)
Right-click on the connections ARM template and select “Decompile into Bicep”. The resulting bicep would look like the below snippet.
VS Code IntelliSense might show some warnings on the access policy section, But it doesn’t throw any errors during deployment.
@description('The datacenter to use for the deployment.')
param location string
param logicAppSystemAssignedIdentityTenantId string
param logicAppSystemAssignedIdentityObjectId string
param sa_name string = 'sa'
param connections_azureblob_name string = 'azureblob'
var sa_var = concat(toLower(sa_name), uniqueString(resourceGroup().id))
resource sa 'Microsoft.Storage/storageAccounts@2020-08-01-preview' = {
name: sa_var
location: location
sku: {
name: 'Standard_LRS'
tier: 'Standard'
}
kind: 'Storage'
properties: {
networkAcls: {
bypass: 'AzureServices'
virtualNetworkRules: []
ipRules: []
defaultAction: 'Allow'
}
supportsHttpsTrafficOnly: true
encryption: {
services: {
file: {
keyType: 'Account'
enabled: true
}
blob: {
keyType: 'Account'
enabled: true
}
}
keySource: 'Microsoft.Storage'
}
}
}
resource sa_default_blobs 'Microsoft.Storage/storageAccounts/blobServices/containers@2018-02-01' = {
name: '${sa_var}/default/blobs'
properties: {
defaultEncryptionScope: '$account-encryption-key'
denyEncryptionScopeOverride: false
publicAccess: 'Container'
}
dependsOn: [
sa
]
}
resource connections_azureblob_name_resource 'Microsoft.Web/connections@2016-06-01' = {
name: connections_azureblob_name
location: location
kind: 'V2'
properties: {
displayName: 'privatestorage'
parameterValues: {
accountName: sa_var
accessKey: concat(listKeys('${resourceGroup().id}/providers/Microsoft.Storage/storageAccounts/${sa_var}', '2019-06-01').keys[0].value)
}
api: {
id: '/subscriptions/${subscription().subscriptionId}/providers/Microsoft.Web/locations/${location}/managedApis/azureblob'
}
}
dependsOn: [
sa
]
}
resource connections_azureblob_name_logicAppSystemAssignedIdentityObjectId 'Microsoft.Web/connections/accessPolicies@2016-06-01' = {
parent: connections_azureblob_name_resource
name: '${logicAppSystemAssignedIdentityObjectId}'
location: location
properties: {
principal: {
type: 'ActiveDirectory'
identity: {
tenantId: logicAppSystemAssignedIdentityTenantId
objectId: logicAppSystemAssignedIdentityObjectId
}
}
}
}
output blobendpointurl string = reference(connections_azureblob_name_resource.id, '2016-06-01', 'full').properties.connectionRuntimeUrl
This template can also be deployed from VSCode- Right-click on the Bicep file and click on “Deploy Bicep file”
Steps to export the API connection from portal as a Bicep template:
Instead of the above sample, you can directly export the managed API connection as an ARM template from Azure portal using the “Export template” option and then decompile it into a Bicep template.
Once decompiled, add the below details:
1. Add Logic App’s managed identity as an input parameter.
param logicAppSystemAssignedIdentityTenantId string
param logicAppSystemAssignedIdentityObjectId string
2. Add the Access policy resource:
resource connections_azureblob_name_logicAppSystemAssignedIdentityObjectId 'Microsoft.Web/connections/accessPolicies@2016-06-01' = {
parent: connections_azureblob_name_resource
name: '${logicAppSystemAssignedIdentityObjectId}'
location: location
properties: {
principal: {
type: 'ActiveDirectory'
identity: {
tenantId: logicAppSystemAssignedIdentityTenantId
objectId: logicAppSystemAssignedIdentityObjectId
}
}
}
}
3. Output the connection runtime URL
output blobendpointurl string = reference(connections_azureblob_name_resource.id, '2016-06-01', 'full').properties.connectionRuntimeUrl
resource <connections_resource_name> 'Microsoft.Web/connections@2016-06-01' = {
name: <name>
location: <location>
kind: 'V2'
properties: {
"displayName": "<name>",
"parameterValues": {
},
"api": {
"id": <connection_api>
}
}
dependsOn: {}
}
resource <resource_name> 'Microsoft.Web/connections/accessPolicies@2016-06-01' = {
parent: connections_resource_name>
name: <name>
location: <location>
properties: {
principal: {
type: 'ActiveDirectory'
identity: {
tenantId: <logicAppSystemAssignedIdentityTenantId>
objectId: <logicAppSystemAssignedIdentityObjectId>
}
}
}
}
For more details on DevOps project creation and adding the service connection, please refer Deploying Logic App Standard resource through DevOps pipeline - Microsoft Community Hub
In the pipeline creation, I choose GitHub as the file source. You can use any other source control option as well.
In this example, I show the pipeline creation through DevOps UI, you can alternatively use yaml file as well.
This task deploys the Logic App Bicep template. I have provided template file path and parameter file path. We can override the parameters if required.
This task is used to output the managed identity object ID and tenant ID parameters from the previous step.
This task deploys the API connections Bicep template. I provide a template file path and parameter file path. In the override section, I pass the output from ARM output task.
This task is used to output the Connection runtime URL generated from the previous step.
This task is used to export the connection runtime URL as an app setting:
The resulting YAML file looks like below:
pool:
name: Azure Pipelines
variables:
resourceGroupName: 'TriageDemo'
steps:
- task: AzureResourceManagerTemplateDeployment@3
displayName: 'ARM Template deployment: Resource Group scope'
inputs:
azureResourceManagerConnection: '<azureSubscription>'
subscriptionId: '<subscriptionID>'
resourceGroupName: TriageDemo
location: 'North Central US'
csmFile: template.bicep
csmParametersFile: template.parameters.json
overrideParameters: '-sites_shmvlastandarddemo1_name shmvlastandarddemo-Bicep'
deploymentName: test
- task: keesschollaart.arm-outputs.arm-outputs.ARM Outputs@6
displayName: 'ARM Outputs'
inputs:
ConnectedServiceNameARM: '<azureSubscription>'
resourceGroupName: TriageDemo
- task: AzureResourceManagerTemplateDeployment@3
displayName: 'ARM Template deployment: Resource Group scope'
inputs:
azureResourceManagerConnection: '<azureSubscription>'
subscriptionId: '<subscriptionID>'
resourceGroupName: TriageDemo
location: 'North Central US'
csmFile: Connector.bicep
csmParametersFile: Connector.parameters.json
overrideParameters: '-location "North Central US" -logicAppSystemAssignedIdentityTenantId $(logicAppSystemAssignedIdentityTenantId) -logicAppSystemAssignedIdentityObjectId $(logi-cAppSystemAssignedIdentityObjectId) -sa_name "sabicep" -connections_azureblob_name "az-ureblobdemo"'
- task: keesschollaart.arm-outputs.arm-outputs.ARM Outputs@6
displayName: 'ARM Outputs'
inputs:
ConnectedServiceNameARM: '<azureSubscription>'
resourceGroupName: TriageDemo
- task: AzureCLI@2
displayName: 'Azure CLI '
inputs:
azureSubscription: '<azureSubscription>'
scriptType: ps
scriptLocation: inlineScript
inlineScript: |
az functionapp config appsettings set --name $(LAname) --resource-group $(resourceGroup-Name) --settings "BLOB_CONNECTION_RUNTIMEURL=$(blobendpointurl)"
az functionapp config appsettings set --name $(LAname) --resource-group $(resourceGroup-Name) --settings "WORKFLOWS_RESOURCE_GROUP_NAME=$(resourceGroupName)"
Deploying Logic App Standard resource through DevOps pipeline - Microsoft Community Hub
ShreeDivyaMV/ExportedTemplate-TriageDemo (github.com)- Bicep samples used in the demo
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.