Each time I need to automate the creation of Azure resources through Azure Resource Manager templates, I end up consulting the Microsoft documentation pages for the same concepts. This blog post serves as a little cheat sheet for common ARM deployment stuff.
Parameters
Parameters are passed as an input to your ARM template. One of my most used parameters, is the environmentName. Because all resource names include the environment name, I tend to configure an enumeration with the allowed values:
"parameters": { "environmentName": { "type": "string", "allowedValues": [ "dev", "test", "prod" ] } }
Variables
Resource names are often used more than once in the ARM template. That’s why I always declare them as variables, that include the environmentName parameter. Some examples:
"variables": { "appServicePlanName": "[concat('tvh-', parameters('environmentName'), '-appsvcplan')]", "keyVaultname": "[concat('tvh-', parameters('environmentName'), '-keyvault')]", "storageAccountName": "[concat('tvh', parameters('environmentName'), 'storage')]" }
Environment specific settings
For many Azure resources, you want to specify different values, depending on the environment you’re deploying to. A common example is the desired SKU of a certain Azure service.
To achieve this, I use nested variables that declare the environment settings for each environment. Next to that, I specify the currentEnvironmentSettings variable that points already to the right environment.
"variables": { "environmentSettings": { "dev": { "appSvcPlanSku": "F1", "storageAccountSku": "Standard_LRS" }, "test": { "appSvcPlanSku": "F1", "storageAccountSku": "Standard_LRS" }, "prod": { "appSvcPlanSku": "B1", "storageAccountSku": "Standard_ZRS" } } "currentEnvironmentSettings": "[variables('environmentSettings')[parameters('environmentName')]]" }
Within the ARM template, you can access these environment specific settings with the following syntax:
"sku": { "name": "[variables('currentEnvironmentSettings').storageAccountSku]" }
Template Resource Functions
There are many ARM template functions available, of which the resource functions are quite powerful and often required. Here you can find some functions I often use. They can serve as a starting point to be used in other scenarios.
- Get the location of the resouce group you’re deploying to
[resourceGroup().location]
- Get the subscription id
[subscription().subscriptionId]
- Get the tenant id
[subscription().tenantId]
- Get the vault URI of a just created KeyVault instance
[reference(resourceId('Microsoft.KeyVault/vaults/', variables('keyVaultName'))).vaultUri]
- Get the access key of a just created Storage account
[listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), providers('Microsoft.Storage', 'storageAccounts').apiVersions[0]).keys[0].value]
Conditional deployments
Another requirement is having conditions within your deployment. For example, you only want to add AD authorization to your API App in production. Or you want to add resource locks only in the production environment.
One way to achieve this, is by adding a condition to your Azure resource. These conditions can use a comparison function. This is demonstrated in the next sample:
"resources": [ { "name": "[concat(variables('storageAccountName'), '/Microsoft.Authorization/CriticalStorageLock')]", "type": "Microsoft.Storage/storageAccounts/providers/locks", "apiVersion": "2015-01-01", "condition": "[equals(parameters('environmentName'),'prod')]", "dependsOn": [ "[concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName'))]" ], "properties": { "level": "CannotDelete", "notes": "Prevent accidental deletion of the storage account." } } ]
I hope this cheat sheet can give you a headstart for ARM deployments.