Azure Image Builder is a virtual machine image provisioning service on Microsoft Azure based on HashiCorp Packer. It has been designed to integrate natively with Microsoft Azure to allow customers to easily create and maintain virtual machine images for consistent deployments. This post is the first of a series to introduce the Azure Image Builder and its benefits by means of showing real-world examples.

This is a multi part series for Azure Image Builder with the following articles:

Table of Contents

  1. Introduction
  2. What is Azure Image Builder
  3. Core features
  4. Differences between Azure Image Builder and HashiCorp Packer
  5. Setup Azure Image Builder (Preview) in your Azure Subscription
    1. Register provider
    2. Setup Identity
  6. Create first custom image
  7. Summary

Introduction

In May 2019 Microsoft announced the public preview of the Azure Image Builder as a service “[…] that makes building Windows and Linux virtual machine (VM) images easy in Azure […]”. The main goals Azure Imager Builder should help achieve are:

  • fulfilling security needs
  • meeting corporate and regulatory compliance rules
  • preconfiguring VMs with apps for faster deployment

Since the documentation about the Azure Image Builder is currently thin and mostly integrated in the Azure VM documentation, I will cover a few real-world scenarios of the Azure Image Builder in this series starting with this introduction post.

What is Azure Image Builder

Standardized VM images provide an easy way to ensure consistent deployments in the cloud. They can include security hardenings, custom files like certificates and ssh public keys, software configurations and custom software installations like company applications or other custom applications. All these modifications are performed using a single configuration file and submitted to the service which then build’s the custom image.

Azure Image Builder Work FlowAzure Image Builder Work Flow

Users who are used to working with HashiCorp Packer will notice the similarities pretty fast and can use existing Packer scripts with Azure Image Builder. Although Azure Image Builder is based on Packer, it features some distinct differences which this blog post series will focus on. All those features are integrated into Azure Image Builder to help existing Azure customers adopting the solution with minimal effort.

Azure Image Builder is currently still in public preview with the expectation of general availability (GA) in Q3 2020.

Core features

The following features are available during the public preview according to Microsoft:

  • Creation of images providing a single source of configuration
  • Easy integration into pipelines since Azure Image Builder can be called directly
  • Integration Azure DevOps (Preview Image Builder Azure DevOps Task)
  • Integration into Azure Shared Image Gallery
  • Integration into Azure Virtual Networks
  • Output of the images VHD to support further processing outside of the Public Cloud (e.g. Azure Stack)

Most of these features outline the main purpose of the Azure Image Builder service. Offer Azure customers an easy-to-use and easy-to-integrate custom image builder service on Azure.

Differences between Azure Image Builder and HashiCorp Packer

The main distinction between Azure Image Builder and HashiCorp Packer is that Azure Image Builder is a service offering where you don’t configure any computing resources that processes the templates and the image building. HashiCorp Packer, on the contrary, must be setup on your client or deployment pipeline before its ready to use.

While Azure Image Builder and HashiCorp Packer share the same foundation, Azure Image Builder introduced Azure cloud platform related features which enhance the integration into Azure. The first and very important of those features is the integration of a dependency on an Azure user assigned identity. This feature was introduced in the May 2020 update of Azure Image Builder and moves authentication and authorization from Azure service principals to Azure user assigned identities. I will explain how to setup this Identity in the next section.

Another important distinction between Azure Image Builder and HashiCorp Packer is that Azure Image Builder added a “Template Storage Layer”. This change derives from the service nature of Azure Image Builder and provides the service with a possibility to access all resources that are required to create the image independent from any client files. It will download the source image and any necessary files and scripts for the build process but doesn’t start the process of building the image automatically. All resources are stored in a storage account in a separate resource group, which is created automatically.

The storage of the source image, files and scripts on the automatically created Azure Storage account generates costs! If you want to minimize cost footprint using Azure Image Builder you should delete the image template after the build!

Setup Azure Image Builder (Preview) in your Azure Subscription

This section highlights the steps that have to be taken to enable the use of Azure Image Builder in your Azure subscription. These steps are necessary to follow along with the next posts in this series.

Register provider

The first step is to check whether the feature has already been enabled for your Subscription:

1
az feature show --namespace Microsoft.VirtualMachineImages --name VirtualMachineTemplatePreview | grep state

If the command returns “state”: “NotRegistered” run the following command the register the feature:

1
az feature register --namespace Microsoft.VirtualMachineImages --name VirtualMachineTemplatePreview

A feature/provider registration can take up to 20 minutes!

Setup Identity

To setup a user assigned identity with basic permissions run the following commands in order. Modify values as you see fit.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
### enter your details
subscriptionId="8ee61158-0fe6-4c8f-8968-a811fa118a76"
rg="aibSeriesRg"
identityName=aibSeriesIdentity

## user assigned identity with permissions to acces rg where image will be created
az identity create -g $rg -n $identityName

## get identity id
aibIdentityId=$(az identity show -g $rg -n $identityName | grep "clientId" | cut -c16- | tr -d '",')

# build identity URI; necessary for the template
imgBuilderUri=/subscriptions/$subscriptionId/resourcegroups/$rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/$identityName

# download basic aib role
curl https://gist.githubusercontent.com/rooftop90/842e8291e46eade95ffae10e91ff3da1/raw/3b51572c569c1b3a984e931b11bcf28f962b8256/aibRoleBasic.json -o aibBasicRole.json

imageRoleDefName="Azure Image Builder Basic Role - "$(date +'%s')

## update the definition
sed -i -e "s/<subscriptionId>/$subscriptionId/g" aibBasicRole.json
sed -i -e "s/<rg>/$rg/g" aibBasicRole.json
sed -i -e "s/AIB Custom Role/$imageRoleDefName/g" aibBasicRole.json

## create role definitions
az role definition create --role-definition ./aibBasicRole.json

## grant role definition to the user assigned identity
az role assignment create \
--assignee $aibIdentityId \
--role "$imageRoleDefName" \
--scope /subscriptions/$subscriptionId/resourceGroups/$rg

With this setup you’re ready to create your first managed image in the specified resource group.

Create first custom image

The previous setup now enables us to create the first custom image. The first example in this series is a basic customization where the Ubuntu Linux system will be updated to the latest packages.


Prepare the following variables:

1
2
3
location=westeurope
imgName=UbuntuImageOne
outputName=ubuntuLinuxMngImg

Next step is download the basic image template and modify it with your values:

1
2
3
4
5
6
7
8
curl https://gist.githubusercontent.com/rooftop90/fde35f56338ba0fac2f26370b0de9365/raw/ce938cd5a14647df87e54e5ba7990a7b345aa951/mngImgLinux.json -o mngImgLinux.json

sed -i -e "s/<subscriptionId>/$subscriptionId/g" mngImgLinux.json
sed -i -e "s/<rg>/$rg/g" mngImgLinux.json
sed -i -e "s/<location>/$location/g" mngImgLinux.json
sed -i -e "s/<imgName>/$imgName/g" mngImgLinux.json
sed -i -e "s/<outputName>/$outputName/g" mngImgLinux.json
sed -i -e "s%<imgBuilderUri>%$imgBuilderUri%g" mngImgLinux.json

Two more steps are now needed to create the image, first create the template:

1
az resource create --resource-group $rg --properties @mngImgLinux.json --is-full-object --resource-type Microsoft.VirtualMachineImages/imageTemplates -n UbuntuImageTemplate

And the last step is to run the image build:

1
az resource invoke-action --resource-group $rg --resource-type  Microsoft.VirtualMachineImages/imageTemplates -n UbuntuImageTemplate --action Run

The image build process time is dependent on the size of the vmProfile section of the template. If your customizing tasks need more computing power, consider changing the size to a bigger one to meet your performance requirements.


Summary

I hope this post gives a basic understanding of what Azure image builder is, tries to achieve and how it differs in its approach from HashiCorp Packer. The next post in this series will cover a real-world scenario where we will create a set of custom Azure images based on CentOS and deployed to a Azure Shared Image Gallery. The configurations will comprise service configurations and security hardening. Stay tuned for the next post in this series!