Bicep and ARM as 2 Infrastructure as Code solutions for Azure Deployment

Bicep and ARM as 2 Infrastructure as Code solutions for Azure Deployment

In this lab, we will use ARM template and Bicep as infrastructure as code solution to deploy, replicate and enforce our environment. After this lab, you will have a better understanding of Azure Deployment, infrastructure as code for Azure with native deployment tools. Enjoy!

Throughout the lab, you are asked to open and use the CloudShell. This is not mandatory. If you have the Azure CLI and PowerShell with the Az-Module installed on your local machine or Lab environment, you can also use the local tools.

You are a developer in a team, that is tasked to develop a new Storage Account Explorer solution, which use at least TLS 1.2 for communication encryption. You are tasked to develop and setup the infrastructure for dev, qa, preprod and prod environment using IaC methodologies (basically doing everything).

Exercise 1: IaC with ARM templates

Task 1: Deploying template

First thing, you need to do is creating a new storage account inside the dev environment so that your team can begin with the development of the Storage Account Explorer solution.

  1. Go to the Azure Portal.
  2. Hit Create a resource and type template in the search box.
  3. Select Template deployment from the list.
  4. Hit Create.
  5. Select Build your own template in the editor .
  6. You should see a basic ARM template, which you can edit in the browser now.
  7. Write the code to create a storage account using the ARM template documentation (See Storage Account ARM documentation). If you are uncomfortable with writing the template definition, please scroll to the full script. But it is strongly recommended to give it a try 🙂.
    1. Please mind that you only need to add the properties that are marked as Required in the list including name, type , apiVersion, sku, kind, location
    2. Use Standard_LRS for setting the name property of the sku object.
    3. Use StorageV2 for kind.
    4. Use the containing resource group’s location as the location of your storage account.
    5. Generate a unique name for your storage account using the resource group id (See resourceGroup, uniqueString, concat).
  8. Hit Save when your code is completed.
  9. Create a new resource group by clicking on Create new below the selection box of Resource group called azlab-<your-initial>-dev.
  10. Select West Europe as region and hit Review + create.
  11. Hit Create.
  12. The Azure Portal should redirect you to the Deployment progress page.
  13. Wait until deployment is done.

Your definition should look somewhat like this.

{     "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",     "contentVersion": "",     "variables": {         "sa-name": "[concat('draphony', uniqueString(resourceGroup().id))]"     },     "resources": [         {             "type": "Microsoft.Storage/storageAccounts",             "apiVersion": "2021-04-01",             "name": "[variables('sa-name')]",             "location": "[resourceGroup().location]",             "sku": {                 "name": "Standard_LRS"             },             "kind": "StorageV2"         }     ] }

Task 2: Adapting changes

After the deploy of your dev-environment is done, let us have a look at the result and confirm that your storage account has the minimum TLS version set to Version 1.2.

  1. Go to the storage account and click on the left side on Configuration.
  2. Notice that the „Minimum TLS version“ is set to Version 1.0. Let’s change this to Version 1.2 using ARM template.
  3. Open the resource group, that you just created. Click on Deployments and click the first succeeded item on the list.
  4. Click on Template and copy the template.
  5. Start a new ARM template deployment (basically repeat Task 1 / Step 2 – Step 6).
  6. Paste the template and add the property definition for TLS minimumTlsVersion. (See ARM Template docs). Below you will find the full ARM template.
  7. Deploy your template in the resource group azlab-<your-initial>-dev.
  8. Check the Configuration tab of your storage account again.
    1. It should show Version 1.2 as Minimum TLS version. If not, hit the refresh a couple of time until it does show it. Try to do it as often as possible in a minute. Pro Gamers have a APM of around 350. High score is noted with 818. You can beat that! (Click here to see some motivation speech on YouTube.)

Your definition should look somewhat like this

{     "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",     "contentVersion": "",     "parameters": {},     "variables": {         "sa-name": "[concat('draphony', uniqueString(resourceGroup().id))]"     },     "resources": [         {             "type": "Microsoft.Storage/storageAccounts",             "apiVersion": "2021-04-01",             "name": "[variables('sa-name')]",             "location": "[resourceGroup().location]",             "sku": {                 "name": "Standard_LRS"             },             "kind": "StorageV2",             "properties": {                 "minimumTlsVersion": "TLS1_2"             }         }     ] }

This is a common procedure when using IaC. We deploy a first version of our infrastructure. After evaluating or any kind of new insight, we make changes to it by updating our code and reapplying it (by redeploying it). Throughout the process, the actual data of the resources will not be destroyed or changed. If we need new resources, we just add them to the code again and redeploy. And at the end of the month we wonder why the money is gone.

Task 3: Duplicating environment

After years of frustration and copying random fragments from Stack Overflow, your team and you believe that the Storage Account Explorer is done as it finally compiles (for the first time). The moment has come for YOU to duplicate dev-environment and create qa, preprod and prod-environment.

Basically, you just need to deploy the same ARM template to 3 addition resource groups, which embody the environments QA, Pre-Prod and Prod.

  1. Create the following additional resource groups azlab-<your-initial>-qa, azlab-<your-initial>-pre, azlab-<your-initial>-prod:
    1. Region does not matter, you can select any location that you like.
    2. You can use the Azure Portal to create the resource groups
    3. OR you can also leverage tools such as PowerShell "qa","pre","prod" | New-AzResourceGroup -Name { "azlab-<your-initial>-" + $_ } -Location "westeurope"
  2. Open CloudShell
    1. Follow the step to create your CloudShell image if this is the first time you open the CloudShell.
    2. Switch PowerShell if not already selected.
  3. Type code template.json in the PowerShell.
  4. Paste the template from the previous exercise.
  5. Save your file.
  6. Close Visual Studio Code.
  7. Run the following command, which will find all the resource groups starting with azlab-<your-initial>- and use it as the target for our ARM template deployment.
    Get-AzResourceGroup -Name "azlab-<your-initial>-*" | New-AzResourceGroupDeployment `
     -ResourceGroupName {$_.ResourceGroupName } `
     -Name { "Draphony.Template-" + (Get-Date -Format FileDateTimeUniversal) } `
     -TemplateFile template.json `
     -AsJob `
  8. You won’t get any hints on the PowerShell as the deployment runs in parallel. Wait for a few minutes and run the following comment to get the current status Get-Job | Receive-Job
  9. You should see that the deployment was successful for all resource groups. Otherwise wait for a few more minutes and rerun. You can also go to the Azure Portal and open the Deployment section of the resource groups to see the status.
  10. Go to the Azure Portal and check that each resource group should have exactly one storage account (azlab-<your-initial>-dev, azlab-<your-initial>-qa, azlab-<your-initial>-pre, azlab-<your-initial>-prod).

You have replicated the environment more or less manually. In a real world setup, you could and would incorporate the IaC in a CI/CD pipeline, so that each change is automatically propagate through the environments. But what happens if someone changes the infrastructure outside (e.g. manually in the Azure Portal) without following your procedure (updating the code and redeploy)?

Exercise 2: Enforcing environments with IaC

At some point, you notice, that the different environments do differs from each other. E.g. some QA team members are adding additional resources to implement their custom procedure of test data generation although a unified procedure has been agreed or dev team members temporary increase the SKU of virtual machines.

In this exercise, we will use the complete mode to enforce environment consistency. Please also consider the public shaming of the particular team mates – people loves that – which we will not demonstrate here.

  1. Open the Azure Portal (https://portal.azure.com).
  2. Add any resource in azlab-<your-initial>-qa manually. E.g. an virtual network. You can but don’t need to use a ARM template for this. You can just click it together in the portal. The resource type itself does not matter as this is just a simulation of the environment derivation.
  3. Deploy your template using Complete mode into all the resource groups azlab-<your-initial>-dev, azlab-<your-initial>-qa, azlab-<your-initial>-pre, azlab-<your-initial>-prod using the PowerShell
    1. Open CloudShell.
    2. Run the following command on PowerShell
      Get-AzResourceGroup -Name "azlab-<your-initial>-*" | New-AzResourceGroupDeployment `
       -ResourceGroupName {$_.ResourceGroupName } `
       -Name { "Draphony.Template-" + (Get-Date -Format FileDateTimeUniversal) } `
       -Mode Complete `
       -TemplateFile template.json`
       -AsJob `
       -Verbose `
  4. Wait for a few minutes and runGet-Job | Receive-Job
  5. You should see that the deployment was successful for all resource groups. Otherwise wait for a few more minutes and rerun. You can also go to the portal and open the Deployment section of the resource groups to see the status.
  6. Open the resource group azlab-<your-initial>-qa, the extra resource from step 2 should be deleted.
  7. The other resource groups should have a storage account inside.

Bonus 1: Deployment History

  1. Open the Portal, go to the Deployment section of your azlab-<your-initial>-qa resource group.
  2. Note down the number of deployments.
  3. Deploy your template from exercise 2 again by repeating step number 3 and number 4 from exercise 2 („Deploy your template using […]“).
  4. Open the Portal, go to the Deployment section of your azlab-<your-initial>-qa resource group.
  5. Note down the number of deployments.
  6. Repeat step number 3 but omit the line -Name { "Draphony.Template-" + (Get-Date -Format FileDateTimeUniversal) } and number 4.
  7. Open the Portal, go to the Deployment section of your azlab-<your-initial>-qa resource group.
    1. What do you observe? And what is the cause of it?
  8. Copy the deployment name of the last item in the deployment list. Let’s assume it is Draphony.Template-20220829T1032175252Z
  9. Repeat step number 3 but change the you just removed to -Name "Draphony.Template-20220829T1032175252Z" and number 4.
    1. Please make sure, that you have copy the name in your deployment list not from this instruction! This is just an example.
    2. What do you observe? Please explain.

Bonus 2: ARM Output (This bonus is quite challenging)

  1. Modify the ARM template so that it output the storage account keys after each deployment
    1. You may want to use listkeys. Please mind: listKeys just needs the resourceName and the API Version, which you can find at the REST API documentation for Storage Accounts – List Keys
    2. ARM Template supports various types, which you can find in the documentation (click here). You may want to check the Sample Response of the Storage Account – List Keys. This should give you an indication for the output type, that you need to specify.
  2. Modify the ARM template so that it just output the first key as a string.
    1. See List Keys REST API Documentation
    2. If a function returns a JSON, you can access its properties the same way you do in JavaScript. e.g. "[listKeys(...).prop1[0].value]"

Exercise 3: IaC with Bicep

After a while, your team mates are complaining, that the ARM template is getting bigger and bigger as it continue to grow. And as we know, more code means more potential bugs. Your desperate attempts to calm everyone down with statements like „I don’t care“, „Write no code then it stays short“ and „MOO“ failed. You are tasked to improve the procedure!

Luckily Microsoft offers Bicep, which creates shorter code. Bicep even offers a way to convert existing ARM templates to Bicep template and is supported natively by the common used tools PowerShell, Azure CLI and Azure DevOps( see AzureResourceManagerTemplateDeployment). You believe transition should be smooth and give it a try:

  1. Open the Azure Portal.
  2. Open the CloudShell.
    1. Switch to PowerShell if not already the case.
  3. Run the following command on PowerShellOn your local machine, you may need to install the bicep extension before you can use it. This depends on your OSS and also on the currently installed Azure CLI version of your machine. On Windows machine with the latest Azure CLI, there is no need to install it explicitly. (See Installation Guide)
    az bicep decompile -f template.json
  4. This should convert your ARM template into a Bicep template. It generate a file name template.bicep You may want to open the file and inspect the result by running code template.bicep. Notice that the file is shorter as it drops all the brackets required by JSON. In real scenarios with many resources, the saving is usually huge.
  5. Run the following command on PowerShell
    Get-AzResourceGroup -Name "azlab-<your-initial>-*" | New-AzResourceGroupDeployment `
    -ResourceGroupName {$_.ResourceGroupName } `
    -Name { "Draphony.Template-" + (Get-Date -Format FileDateTimeUniversal) } `
    -Mode Complete `
    -TemplateFile template.bicep`
    -AsJob `
    -Verbose `
  6. Wait for a few minutes and run Get-Job | Receive-Job
  7. You should see that the deployment was successful for all resource groups. Otherwise wait for a few more minutes and rerun. You can also go to the portal and open the Deployment section of the resource groups to see the status.
  8. Everything should be the same.
  9. Open the Deployment-Tab of your azlab-<your-initial>-qa resource group.
  10. Open the last deployment that you just did with the Bicep template.
  11. On the left, click Template.
  12. Notice that it is showing a ARM template as Bicep is internally converted to ARM.

Your team loves the new Bicep as they can split logic into modules unlike in ARM templates for better maintenance and reuse. Support for loops and condition render code shorter.

After a short moment, you notice something strange. You recall, that you just returned to your sit after you had handed-in the form to request a new server with 2 approval levels and expected 6 months waiting period… what is happening now? A Total Recall?

Further reading

The tools used in this lab are quite powerful when you solely work with Azure. But most of the time, this is not enough even if your company’s strategy is the Microsoft eco system. Because ARM / Bicep only works for the Azure Cloud itself. For development, you will need to setup your Azure DevOps project such as Azure Repo, Azure Pipeline, Azure Artifacts and so on or similiar solution like GitHub, GitLabs etc. Furthermore your company may also want to use multiple cloud provider to mitigate its dependency on a single cloud provider and leverage the best offers and features set from various providers such as Azure, AWS, Google Cloud and many more.

In such case, you would need a solution that supports multiple cloud providers. At best, it should be vendor agnostic. Terraform is one of such. It is easy to use, it does support multiple cloud providers in the same project and even in the same code file. It has many nice syntax sugar, configuration options and great support by the community.

Checkout other labs from Draphony to learn more about Terraform:

  1. Deploying to multiple cloud providers using Terraform
  2. Deploy Hub-Spoke network topology using Terraform (coming soon)

If you enjoyed the lab or have any questions / feedback, please leave us a comment.

Tác giả

  • Azure

Newsletter zu Aktionen

Trage dich ein um keine Aktionen von uns zu verpassen.
Wir senden 1-2 E-Mails pro Quartal.