Infrastructure As Code: How you can use ARM-templates and Policies to control your Azure environment
Avoid time-consuming exercises in administering your resources.
Managing an Azure environment can at times get challenging or time-consuming, especially if it contains many users, resources, or special administrative concerns to factor in. An easy example of this might be associating resources with an appropriate cost center or restricting what the common user can or cannot do in the environment.
Azure Policies and ARM templates can help.
ARM Templates are a way to do Infrastructure as Code in Azure. For the uninitiated, Infrastructure as Code (IaC) is a way to declaratively prepare and deploy resources with the help of code. Benefits include faster and more consistent deployments, but also idempotence — which means that the output is expected to be the same regardless of how many times the same operation is done.
To make things clear it is useful to look at the differences between the Imperative and Declarative methods of resource creation:
- Imperative means to explicitly state what commands and actions are to be taken to accomplish the desired configuration. This is like traditional scripting — a set of commands to run in sequence for accomplishing the results. As an example, this could be a lengthy PowerShell-script. To simplify it, one could say it says how to create the resources
- Declaratively means to declare what the end-state should look like, and leaves it up to the underlying infrastructure or services to handle how it should be done. A prominent example is what is being showcased here, IaC with ARM templates.
The full list of benefits with IaC is far too long to go through in length, but take a look at Microsofts own Docs, here.
The other topic being discussed, Azure Policies, is a service in Azure for enforcing standards and compliance. These policies can evaluate new or existing resources by examining the properties tied to them, and an example is to prevent chosen sizes of VMs from being created.
Two things should be noted:
- ARM templates as a tool for IaC are not necessarily the one-size-fits-all solution that every team can use to full effect. Different teams have different needs and therefore need different tools.
- And secondly — ARM templates can be seen as having a complex syntax, which is especially true if one has no prior experience in Programming.
This article will guide you through basic steps to get started with ARM-templates and Azure Policies. In no way is this exhaustive, but it will, hopefully, give a better understanding of the benefits of these methods and how to get started with IaC.
What exactly is ARM?
ARM stands for Azure Resource Manager. It is the service in charge of deploying and managing resources in Azure. When someone wishes to create a resource in Azure, the request to do so is sent to Azure Resource Manager. ARM then sends the request to the appropriate Azure resource.
And ARM templates?
These are JSON-files used to define the resources we need, and the configuration of them. By using IaC and the declarative method of deploying our resources, we can be more sure we get what we want, in addition to promoting reuse, version-control, and general automatization.
How about Azure Policies?
When it comes to policies, we need a definition and a scope for them to be applied. The definition will be the conditions for evaluation and what to do if these are not met, while the scope will be what is up for evaluation. For example, we can choose to apply the policy definition on a specific resource group, or at a subscription if we want to do it on a higher level.
So, an Azure policy is used to verify or enforce that certain conditions are met. As an example, we can require that all resources in a resource group are created in Europe, if it's not, it simply can't be created.
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:
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.
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:
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:
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.
Luckily, the Resource Group “LearningByDoing” was deployed correctly!
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:
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:
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.
Deploying the Policy
The policy can be deployed in the almost same way as the resource group earlier! Both of the resources showcased could also be deployed as part of the same template, but for demonstration purposes, the two resources were separated into different deployments. The command for deploying this policy would be:
New-AzResourceGroupDeployment -Templatefile <path-to-template> -TemplateParameterFile <path-to-parameter-file> -ResourceGroupName <Name of resource group>
Make sure to deploy the policy to the correct scope, here it is intended to only function on the resources within the resource group that was created earlier — Applying a policy to the incorrect scope could and would create a mess :)
After the policy have been deployed, the creation of a Virtual Machine without the correct tags will be blocked under validation, like this:
Alternative Medicine
ARM Templates probably won't be the be-all-end-all solution for every team out there. It is in any case a great tool, and a good start to begin learning what IaC is all about. If you or your team are considering using IaC in production, I would strongly suggest researching multiple different tools in addition to looking at the insights or experiences others have had. I would especially like to point out this video from Vipps, which points out how Vipps’s teams explored different solutions for IaC.
Here are some alternate tools for IaC:
For further reading about IaC, my colleague Tore Sæterdal’s post about Ansible and GitLab is recommended: https://medium.com/sopra-steria-norge/managing-your-infrastructure-with-ansible-and-gitlab-ci-cd-c820188270d6
Links
- https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/overview#why-choose-arm-templates
- https://azure.microsoft.com/en-us/offers/ms-azr-0144p/
- https://github.com/emilbra/LearnByDoing
- https://medium.com/sopra-steria-norge/managing-your-infrastructure-with-ansible-and-gitlab-ci-cd-c820188270d6