Step-by-Step Guide: Building Custom Azure Images with Packer

This step-by-step guide walks you through steps to create an Azure Image using Packer

Step-by-Step Guide: Building Custom Azure Images with Packer


  • The version used in this example: Packer v1.11.0


  • You have created a resource group for the resource to be created in
  • You have created an Azure Credential (App Registration) used to create the image

Install Packer

If you haven't already, install Packer on your machine.

    1. If using Chocolately use the command: choco install packer

Set up Azure credentials

Packer needs to authenticate with Azure. You can do this by setting the following environment variables:

export ARM_CLIENT_ID="your_azure_client_id"
export ARM_CLIENT_SECRET="your_azure_client_secret"
export ARM_TENANT_ID="your_azure_tenant_id"
export ARM_SUBSCRIPTION_ID="your_azure_subscription_id"

Replace the placeholders with your actual Azure credentials. Alternatively, you can define this in the variables file in the steps below.

Create Packer template

Create a file called azure-packer-template.pkr.hcl and copy the below code block

packer {
  required_plugins {
    azure = {
      source  = ""
      version = "~> 2"

variable "client_id" {}
variable "client_secret" {}
variable "tenant_id" {}
variable "subscription_id" {}
variable "resource_group" {}
variable "image_name" {}
variable "location" {}

locals {
  virtual_network_name                = "syd-prd-net-vnetphip-001"
  virtual_network_subnet_name         = "syd-prd-net-subnetappphip-001"
  virtual_network_resource_group_name = "syd-prd-cldfoud-netrgphip-001"
  resource_group_name                 = "syd-prd-cldfoud-apprgphip-001"

source "azure-arm" "example" {
  client_id       = var.client_id
  client_secret   = var.client_secret
  tenant_id       = var.tenant_id
  subscription_id = var.subscription_id

  # build_resource_group_name         = local.resource_group_name
  managed_image_resource_group_name = local.resource_group_name
  managed_image_name                = var.image_name
  os_type                           = "Windows"
  image_publisher                   = "MicrosoftWindowsServer"
  image_offer                       = "WindowsServer"
  image_sku                         = "2022-datacenter-azure-edition"
  location                          = var.location
  vm_size                           = "Standard_DS2_v2"
  communicator                      = "winrm"
  winrm_username                    = "Packer_admin!2"
  winrm_password                    = "p@cker551^%22"
  winrm_timeout                     = "2h"
  winrm_insecure                    = true
  winrm_use_ssl                     = true

  # virtual_network_name                = local.virtual_network_name
  # virtual_network_subnet_name         = local.virtual_network_subnet_name
  # virtual_network_resource_group_name = local.virtual_network_resource_group_name

The above values are explained below

The source block in a Packer template defines the base configuration for the virtual machine that Packer will create. The "azure-arm" part specifies that the source should be an Azure Resource Manager image and the "example" part is just a name that you can choose.

  • client_idclient_secrettenant_idsubscription_id: These fields are used for Azure authentication. You should replace the placeholders with your actual Azure credentials.
  • os_type: This field specifies the type of operating system. It can be either "Windows" or "Linux".
  • image_publisherimage_offerimage_sku: These fields specify the base image that Packer will use to create the VM. You can find the values for these fields in the Azure Marketplace.
  • location: This field specifies the Azure location where the VM will be created.
  • vm_size: This field specifies the size of the VM.
  • communicatorwinrm_usernamewinrm_passwordwinrm_timeoutwinrm_insecurewinrm_use_ssl: These fields are used to configure the WinRM communicator, which Packer uses to connect to the VM.


  • virtual_network_name: This is the name of the virtual network in Azure where you want to create the VM.
  • virtual_network_subnet_name: This is the name of the subnet within the specified virtual network where you want to create the VM.
  • virtual_network_resource_group_name: This is the name of the resource group that contains the virtual network.

I am using winrm to connect to the machine in this case. The last 3 lines in the source are optional. This is intended for working within a private network. By default, if you don't specify the network, then it will create a public IP associated with the packer image along with a temporary resource group and virtual network.

Important: You will also need to ensure you create an NSG rule to allow winrm port, otherwise it will timeout.

Create a variables file

Create a file named variables.hcl in the same directory as your Packer template with the following content:

client_id       = "your_azure_client_id"
client_secret   = "your_azure_client_secret"
tenant_id       = "your_azure_tenant_id"
subscription_id = "your_azure_subscription_id"
resource_group  = "your_resource_group"
image_name      = "your_image_name"
location        = "your_azure_location"

Replace the placeholders with your actual Azure credentials, resource group, image name, and location.

Validate the Packer template

Run the following command to validate your Packer template:

packer validate -var-file .\packer.hcl .\azure-packer-template.pkr.hcl    
You should get this after validation

Build the Packer image

If the validation is successful, run the following command to build the Packer image:

packer build -var-file .\packer.hcl .\azure-packer-template.pkr.hcl

This command will start the image-building process. Packer will create a temporary resource group and virtual machine in Azure, perform all the provisioning steps defined in your template, capture an image of the virtual machine, and then delete the temporary resources.

If all goes well, it will look like the below

Output Example
Output Complete

Validate in the Portal to confirm


Full code found here

phiptechblog/packer at main · phipcode/phiptechblog
Contribute to phipcode/phiptechblog development by creating an account on GitHub.

PowerShell - How to create VM Images with Packer - Azure Virtual Machines
Learn how to use Packer and PowerShell to create images of virtual machines in Azure