Infrastructure As Code: How you can use ARM-templates and Policies to control your Azure environment
By: Emil Antoni Brasø
Tags: Entry Level, Iac, Azure Policies, Arm Templates, Azure

What's needed for this demo:

An Editor, such as Visual Studio Code

Access to an Azure subscription

We will be writing some code, so a code editor is necessary. This can be any tool you see fit, such as Atom or Notepad++. Visual Studio Code is a good choice regardless, due to some extensions that will help us along. This extension is recommended:

Azure Resource Manager (ARM) Tools — Provided by Microsoft

The extension makes Editing and creating ARM-templates easier by providing a language server and snippets.

For actually testing what is showcased here access to an Azure environment is needed. Microsoft offers free Azure accounts for students here.

Let's get to it

I have created a Github repo here for this article, in which the files used in this demo are stored. There is not anything fancy there, but it might be useful to have the actual files at hand while following along.

A good starting point is looking at an already existing template. Let's start by looking at creating a resource group.

When creating a resource in azure a template for automation can be downloaded

A template can be downloaded for most resources in Azure, even for already existing ones. Using new resources will be the tidiest for this demo since no post-deployment configuration has been done(Which can also be done with templates). Following the “Download a template for automation” link will show the template code inline, also giving the option to download it. The preferred option is to download the files and open them in an editor, in this case, VSCode:

Essential parts of a template

The three most important building blocks of an ARM template have been highlighted. Let's look at the resources block (blue) first.

Resources

Resources in Azure Templates are what is to be created.

These elements are somewhat self-explanatory. Firstly the “type”-property declares what kind of resource is to be deployed. “Microsoft.Resources” means it is a Microsoft-provided resource of the grouping “Resources”, and “/resourceGroups” means that a Resource Group is being created.

If a Virtual Machine were to be created instead, the property would look like this:

"type": "Microsoft.Compute/virtualMachines"

Notice that “Microsoft.Resources” is replaced with “Microsoft.Compute”.

One thing to note is that one can easily create multiple resources in one template, in most cases it can be as easy as adding a block enclosed in curly brackets (these guys: {}) and separated with a comma. Just like this excerpt:

Parameters

Now, for the parameters block (red). Parameters are for handling the input to be used within the template, such as which location to deploy the Resource Group into.

Note that the parameters themselves are referred to with “[parameters(‘parameterName’)]” at the corresponding properties.

Parameter-files

The parameter-values can be hardcoded directly into the templates JSON-file, but the better approach is to include a separate parameters.json file for this:

a parameters.json file

By using separate parameter-files one can deploy resources just by updating them instead of updating the main template.json file. This promotes reuse and efficiency and allows for better integration with CI/CD.

Say we need another VM, but we need to deploy it to another resource group. We could reuse the template by only changing the necessary parameters.

Variables

The variables (green) are for containing complicated expressions to be used through the template. No variables are used in this demo, but a common use case is to generate a unique ID for a resource, based on the parameters supplied. Like this very simple example:

"variables": { "storageName": "uniqueString(resourceGroup().id)" },

Similar to how the parameters are referenced later, the variables are referenced like this: “name”: “[variables(‘storageName’)]”

Deploying a template

To recap, there is at this point two separate files:

A template.json file that contains the template for what is being created.

A parameters.json file that contains parameters to be used in the template.

The product of these two files will be a Resouce Group with the following properties:

rgName: LearningByDoing

rgLocation: norwayeast

the tag CostCenter: Oslo

To deploy a template either Azure CLI, Azure Powershell, or The Azure Portal can be used. Here is how to do it with PowerShell.

Install Azure Powershell:

Install-Module -Name Az -AllowClobber -Scope CurrentUser

2. Sign in to Azure

Connect-AzAccount

3. When authentication is done, deploy the template and parameter-file with this command:

New-AzSubscriptionDeployment -Location <location> -TemplateFile <path-to-template> -TemplateParameterFile <path-to-parameter-file>

The previous command is for deploying to the Subscription-scope and is useful for resource groups or other resources that are not contained in a resource group. For deploying inside of a resource group, use the following command instead:

New-AzResourceGroupDeployment -ResourceGroupName <resource-group-name> -TemplateFile <path-to-template>

For this part of the demo, the command would look like this:

New-AzSubscriptionDeployment -Location northeurope -TemplateFile .\template.json -TemplateParameterFile .\parameters.json

After deploying

After the template has been deployed via the tool of your choice, the deployment can be tracked through the deployments tab whichever scope the deployment is made to, in this case, a Resource Group.

the deployment named “template” succeeded

Luckily, the Resource Group “LearningByDoing” was deployed correctly!

The resource group “LearningByDoing” was deployed with the tag: CostCenter: Oslo

To top things off — A Policy

To administer the new resource group one may wish to use Azure Policies to restrict what can and cannot be done inside of it. For this demo, let's say it should be mandatory to set the tag “CostCenter: Oslo” on all resources, so costs can be administered easier.

These policies also use a JSON-file format:

An azure policy that requires a tag to be set on resources.

And this allows for the creation of custom definitions if need be.

The use-case mentioned happens to be a prebuilt definition in Azure. This demo will utilize this definition. For deploying this, another template (policyTemplate.json) and parameter-file (policyParameterFile.json) is created:

policyTemplate.json will assign a built-in policy

policyParameterFile.json supplies the parameters. PolicyDefinitionID is the ID of the policy we want to assign

Note that the policyDefinitionID parameter is for specifying the policy definition that is to be assigned. The ID in this example is for the built-in policy as previously mentioned. One needs to have the ID beforehand or we can get the ID with a function.

The creation of policyTemplate.json doesn't differ much from the first template showed, but a key difference is that the parameters- part of the resources block is an object here.