DEV Community

Cover image for Things I wish I knew before working with Azure ARM Templates
M. Kipergil
M. Kipergil

Posted on • Edited on

Things I wish I knew before working with Azure ARM Templates

Hey dev.to members, this is my first post here.

So please be gentle in your comments and don't hesitate to ask any question and please share your feedbacks below

In my recent project, I had to use ARM templates in order to implement our CI/CD pipelines for our Azure resources.

I roughly knew what an ARM template is and how it works. But I had never written any ARM template from scratch.

When I had to deploy all of our Azure resources from scratch,
I hit the wall very frequently and found myself trying to tackle with variety of issues almost in every step.

During these times, I googled a lot, and came up with brilliant bloggers and content creators. Thanks to their contributions, I found most of the answers under different blogs, websites, forums etc.

Then, I decided to curate my first dev.to article, just to keep a reference for myself and other team members.

I structured this post with various questions and their answers, which you can refer to whenever you need. I also added the URLs original contents as a reference. All of them are worth to read to get more details on such topics.

You will find useful code snippets, markups, utility functions and lots of brilliant resources below in one place which i wish I knew before/during working with ARM Templates.

Hope it will be useful for all of us.
Thanks.

One last tip:
If you have just started learning ARM templates, I'd recommend you to take a look into Bicep which seems way much easier/better/stronger compared to ARM template syntax.
You can check this online playground tool to quickly understand what Bicep Lang is and and how it works.

https://aka.ms/bicepdemo
...

To give you a bit of context, let me briefly explain our release pipeline approach.

There are 5 environments :

DEV, SIT, UAT, PROD, DR

We have 1 arm template file for each resource and 1 parameter file per environment.

File structure for a resource looks like below :
template.json
template-sit.parameters.json
template-uat.parameters.json
template-prod.parameters.json
template-dr.parameters.json

For each environment, we created separate AzureDevops build&release pipelines, which are responsible to build and deploy the resources listed below. It shows the resources and the dependent resource numbers in parenthesis.

  • [1] ResourceGroup ( no dependency )
  • [2] KeyVault (1) (i.e Depends on Resource Group)
  • [3] Storage Accounts (1)
  • [4] Service Bus (1)
  • [5] Log analytics (1)
  • [6] Function App (1, 2, 3, 4, 5)
  • [7] Function App Code Deployment (6)
  • [8] Azure LogicApps (1, 2, 3, 4, 5, 6)
  • [9] Azure APIM (1, 2, 6)
  • [10] Log analytics ActionGroup (1, 5)
  • [11] Log analytics Alerts (1, 5, 10)
  • [12] File uploads to storage accounts (1, 3)

Since some of the values are depending on previously deployed resource properties, we needed to extract the required information dynamically in ARM templates.

So most questions below are more or less arouns how to expose a deployed azure resource properties ( i.e : key, connectionstring, trigger url, secret etc) via ARM Template Output Variables, in order to consume them in the upcoming pipeline steps.
...

What are the must have VS-Code extensions for ARM Templates ?

https://marketplace.visualstudio.com/items?itemName=msazurermtools.azurerm-vscode-tools
https://marketplace.visualstudio.com/items?itemName=samcogan.arm-snippets
https://marketplace.visualstudio.com/items?itemName=bencoleman.armview
https://marketplace.visualstudio.com/items?itemName=wilfriedwoivre.arm-params-generator
https://marketplace.visualstudio.com/items?itemName=bencoleman.armview
http://armviz.io/editor

...

How to deploy/validate ARM Template with AzureCLI ?

az login
az account set --subscription $(subsId)

az group deployment validate 
--resource-group $(resgroupName) 
--template-file $(templateFile).json 
--parameters $(templateFile).parameters.json

az group deployment create   
--name ExampleDeploymentName 
--resource-group $(resgroupName) 
--template-file  $(templateFile).json 
--parameters $(templateFile).parameters.json
Enter fullscreen mode Exit fullscreen mode

https://docs.microsoft.com/en-us/cli/azure/group/deployment?view=azure-cli-latest#az-group-deployment-validate

...

How to deploy/validate ARM Template with PowerShell ?

New-AzResourceGroupDeployment 
-ResourceGroupName $(resgroupName) 
-TemplateFile $(templateFile).json  
-TemplateParameterFile $(templateFile).parameters.json
Enter fullscreen mode Exit fullscreen mode

Change $(templateFile) and $(resgroupName) variables in the snippets according to your values

...

How to get LogicApp callback url via ARM output variables ?

"outputs": { 
    "logicAppUrl": {
      "type": "string",
      "value": "[listCallbackURL(concat(resourceId('Microsoft.Logic/workflows/', variables('logicAppName')), '/triggers/request'), '2016-06-01').value]"
   }
}
Enter fullscreen mode Exit fullscreen mode

https://platform.deloitte.com.au/articles/list-of-access-keys-from-output-values-after-arm-template-deployment#logic-apps

...

How to get LogicApp querystrings and sasToken with ARM Template ?

"outputs": {
    "endpointUrl": {
        "type": "string",
        "value": "[listCallbackUrl(variables('resourceId'), variables('apiVersion')).value]"
    },
    "path": {
        "type": "string",
        "value": "[listCallbackUrl(variables('resourceId'), variables('apiVersion')).basePath]"
    },
    "querystring": {
        "type": "string",
        "value": "[concat('api-version=', variables('apiVersion'), '&sp=', uriComponent(listCallbackUrl(variables('resourceId'), variables('apiVersion')).queries.sp), '&sv=', listCallbackUrl(variables('resourceId'), variables('apiVersion')).queries.sv, '&sig=', listCallbackUrl(variables('resourceId'), variables('apiVersion')).queries.sig)]"
    },
    "sasToken": {
        "type": "string",
        "value": "[concat('sp=', uriComponent(listCallbackUrl(variables('resourceId'), variables('apiVersion')).queries.sp), '&sv=', listCallbackUrl(variables('resourceId'), variables('apiVersion')).queries.sv, '&sig=', listCallbackUrl(variables('resourceId'), variables('apiVersion')).queries.sig)]"
    }
}
Enter fullscreen mode Exit fullscreen mode

https://gist.github.com/justinyoo/2196cf52cc28b7d16726465be1db4c02

...

How to get Storage Account properties via ARM outputs variables ?

"outputs": {
    "blobStorageAccountName": {
      "type": "string",
      "value": "[parameters('storageAccountName')]"
    },
    "blobStorageConnectionString": {
      "type": "string",
      "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', parameters('storageAccountName'), ';AccountKey=', listKeys(resourceId(resourceGroup().name,'Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2019-04-01').keys[0].value,';EndpointSuffix=core.windows.net')]"
    },
    "blobStorageSharedKey": {
      "type": "string",
      "value": "[listKeys(resourceId(resourceGroup().name,'Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2019-04-01').keys[0].value]"
    },
 "blobStorageAccountConnectionStringWithSAS": {              
      "type": "string",              
      "value": "[concat('BlobEndpoint=',variables('blobEndPoint'),';SharedAccessSignature=', listAccountSas(variables('storageAccountName'), '2019-04-01'), parameters('accountSasProperties')).accountSasToken"
  }
}
Enter fullscreen mode Exit fullscreen mode

https://platform.deloitte.com.au/articles/list-of-access-keys-from-output-values-after-arm-template-deployment#storage-accounts

...

How to get FunctionApp properties via ARM outputs variables ?

"outputs": { 
    "FuncAppName": {
      "value": "[parameters('funcAppName')]",
      "type": "string"
    },
    "FuncAppUrl": {
      "value": "[concat('https://', parameters('funcAppName') ,'.azurewebsites.net')]",
      "type": "string"
    },
    "FuncAppId": {
      "value": "[concat('/subscriptions/',subscription().subscriptionId,'/resourceGroups/',resourceGroup().name,'/providers/Microsoft.Web/sites/',parameters('funcAppName'))]",
      "type": "string"
    },
    "FuncApp_SampleFuncName_Url_With_FunctionKey": {
      "value": "[listsecrets(resourceId('Microsoft.Web/sites/functions', parameters('funcAppName'), 'SampleFuncName'),'2015-08-01').trigger_url]",
      "type": "string"
    },
    "FuncApp_SampleFuncName_Url_With_MasterKey": {
    "value": "[concat('https://', parameters('funcAppName'), '.azurewebsites.net/api/samplefuncname', '?code=', listkeys(concat(resourceId('Microsoft.Web/sites', parameters('funcAppName')), '/host/default'), '2015-08-01').masterKey)]",
    "type": "string"
    }
}
Enter fullscreen mode Exit fullscreen mode

https://platform.deloitte.com.au/articles/list-of-access-keys-from-output-values-after-arm-template-deployment#functions

...

How to set AppInsight InstrumentationKey and ConnectionString in SiteConfig ?

"properties": {
    "siteConfig": {
        "appSettings": [
            {
            "name": "APPINSIGHTS_INSTRUMENTATIONKEY",
            "value": "[reference(resourceId('microsoft.insights/components/', variables('applicationInsightsName')), '2015-05-01').InstrumentationKey]"
            },
            {
            "name": "APPLICATIONINSIGHTS_CONNECTION_STRING",
            "value": "[reference(resourceId('microsoft.insights/components/', variables('applicationInsightsName')), '2015-05-01').ConnectionString]"
            }
        ]
    }
}
Enter fullscreen mode Exit fullscreen mode

...

How to get Log Analytics Workspace properties via ARM outputs variables ?

"outputs": {
    "LogAnalyticsWorkspaceCustomerId": {
      "value": "[reference(parameters('LogWorkspaceName'), '2015-11-01-preview').customerId]",
      "type": "string"
    },
    "LogAnalyticsWorkspacePrimarySharedKey": {
      "value": "[listKeys(parameters('LogWorkspaceName'), '2015-11-01-preview').primarySharedKey]",
      "type": "string"
    }
  }
Enter fullscreen mode Exit fullscreen mode

...

How to set webhook url for ActionGroups with ARM Template ?

 "webhookReceivers": [
            {
              "name": "logicapp_webhook",
              "serviceUri": "[listCallbackURL(concat(resourceId('Microsoft.Logic/workflows', parameters('workflowName')), '/triggers/manual'), '2016-06-01').value]"     
             }
          ],
Enter fullscreen mode Exit fullscreen mode

https://mindbyte.nl/2019/02/13/Retrieve-the-callback-url-of-a-logic-app-inside-your-ARM-template.html

...

How to override parameters with KeyVault Value ?

"value": "[concat('@Microsoft.KeyVault(SecretUri=', 'https://',parameters('keyVaultName'),'.vault.azure.net/secrets/',parameters('keyVaultSecretName'))')]"
Enter fullscreen mode Exit fullscreen mode

...

How to export Azure Devops variable group key/value pairs via Azure CLI ?

az pipelines variable-group variable list --org https://dev.azure.com/{orgName} --project {projectName} --group-id {groupId} --output json>{fileName}.json

az pipelines variable-group show --org https://dev.azure.com/{orgName} --project {projectName} --group-id {groupId} -o json >{fileName}.json
Enter fullscreen mode Exit fullscreen mode
  • {orgName} : Devops org name
  • {projectName} : Devops project name
  • {groupId} : VariableGroupId
  • {fileName} : fileName to save the json export

Hint : You can use the url of the variable group to get the > variableGroupId
Ex: ?itemType=VariableGroups&view=VariableGroupView&variableGroupId=12 )

...

How to learn basic syntax for ARM templates ?

https://dev.to/fboucheros/series/8490
https://adamtheautomator.com/arm-templates-in-azure/
https://ravichaganti.com/categories/arm-template/

...

How to use variables in ARM templates ?

https://www.timmerman.it/index.php/author/kevint/

...

How to use output variables in ARM templates ?

https://adamtheautomator.com/arm-templates-in-azure/#Capturing_ARM_Outputs_for_the_Azure_Pipeline
https://www.timmerman.it/index.php/using-values-from-your-arm-template-across-your-azure-devops-pipeline-with-powershell/

...

How to learn functions in ARM templates ?

https://ravichaganti.com/blog/azure-resource-manager-using-functions-in-arm-templates/
https://erwinstaal.nl/posts/functions-in-arm-templates

...

How to learn template functions in ARM Templates ?

https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/template-functions
https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/template-functions-resource#reference
https://ochzhen.com/blog/reference-function-arm-template#examples-of-reference-function
...

How to pass secrets in ARM Templates ?

https://platform.deloitte.com.au/articles/6-ways-passing-secrets-to-arm-templates

...

How to solve common errors in ARM Templates ?

https://www.devdummy.com/2020/10/resolved-azure-devops-pipeline-variable.html
https://docs.microsoft.com/en-us/answers/questions/259204/an-error-while-overriding-3939-parameter-because-o.html
https://github.com/Azure/azure-functions-host/wiki/Changes-to-Key-Management-in-Functions-V2

...

How to solve LogicApp API Connection errors?

https://www.koskila.net/how-to-fix-a-logic-app-deployment-that-failed-with-error-apinotfound/
https://docs.microsoft.com/en-us/azure/azure-resource-manager/troubleshooting/error-invalid-template?tabs=bicep#solution-3---parameter-is-not-valid
https://docs.microsoft.com/en-us/azure/azure-resource-manager/troubleshooting/common-deployment-errors

...

Which roles should be given to service principal user for copying Azure Blob files with ARM Template ?

https://medium.com/datadigest/resolving-an-authorizationpermissionmismatch-from-the-azure-file-copy-task-v4-in-azure-pipelines-654536fe3af5

These 2 roles should be given to service principal to upload files
Storage Blob Contributor
Storage Blob Data Contributor

Top comments (0)