Last Updated on May 18, 2024 by Arnav Sharma
Packer is an open-source tool that enables you to create identical machine images for multiple platforms from a single source template. A common use case is creating “golden images” that teams across an organization can use in cloud infrastructure.
Ref. : Packer by HashiCorp
For customization of Azure, refer: Azure arm – Builders | Packer by HashiCorp
Getting Started:
Download Packer: Downloads | Packer by HashiCorp
Packer has used a JSON template for its configuration in past, but now Packer is transitioning to a new format that uses HCL2. HCL is the same language that is used in Terraform.
Packer Template
- Source Block: This contains the source (azure, AWS, GCP, VMWare etc) , configuration block and plugins.
There are 50-100 different settings to customize the image and process which are documented here:
Azure arm – Builders | Packer by HashiCorp

2. Build block: Contains builders, provisioners, and post-processors used to create a specific image artifact. There are builders specific to the image being built as well as the target environment.

3. Variable block: Similar to terraform, these are the variable to be used and can be specified in a different file.

In the above example, I have placed the code on the .pkl.hcl file and then have two more files – one PowerShell script and the second one to pass values for variables.

Some common commands:
- packer version : Output of packer version
- packer fmt tmpl.pkr.hcl: Template file formatting
- packer validate tmpl.pkr.hcl : Template file validation
- packer build tmpl.pkr.hcl: Build image
- packer build -debug tmpl.pkr.hcl: Build & debug
Running/building the image:
Command:

Packer creates a temp resource group, a VM with required resources (IP, NIC, vNET etc etc) and then captures the image for it.

Resource Group (temp) with resources:

Once the image is created, the image is placed in the RG specified in the code.

The image can then be used to create a VM or can be registered in the gallery.

Sample Code that I used:
image.pkr.hcl
variable "subid"{
type = string
default = null
}
variable "tenant" {
type = string
default = null
}
variable "rgname" {
type = string
default = null
}
variable "username" {
type = string
default = null
}
variable "password" {
type = string
default = null
}
variable "capturenamename" {
type = string
default = null
}
variable "location" {
type = string
default = "australiaeast"
}
source "azure-arm" "windows-image" {
# Basics authentication
subscription_id = var.subid
tenant_id = var.tenant
# Image Settings
os_type = "Windows"
image_publisher = "MicrosoftWindowsServer"
image_offer = "WindowsServer"
image_sku = "2016-Datacenter"
# Temp location / config
location = var.location
vm_size = "Standard_D2_v2"
# Created Image Name
managed_image_name = var.capturenamename
managed_image_resource_group_name = var.rgname
# Communication (WinRM) and settings
communicator = "winrm"
winrm_insecure = "true"
winrm_use_ssl = "true"
winrm_timeout = "3m"
winrm_username = var.username
winrm_password = var.password
}
build {
# Build the Image
sources = ["azure-arm.windows-image"]
# Script for windows settings - powershell
provisioner "powershell" {
script = "Configuration.ps1"
execution_policy = "bypass"
elevated_user = var.username
elevated_password = var.password
}
}
Configuration.ps1
<powershell>
write-output "Running User Data Script"
write-host "(host) Running User Data Script"
Set-ExecutionPolicy Unrestricted -Scope LocalMachine -Force -ErrorAction Ignore
# Don't set this before Set-ExecutionPolicy as it throws an error
$ErrorActionPreference = "stop"
# Remove HTTP listener
Remove-Item -Path WSMan:Localhostlistenerlistener* -Recurse
$Cert = New-SelfSignedCertificate -CertstoreLocation Cert:LocalMachineMy -DnsName "packer"
New-Item -Path WSMan:LocalHostListener -Transport HTTPS -Address * -CertificateThumbPrint $Cert.Thumbprint -Force
# WinRM
write-output "Setting up WinRM"
write-host "(host) setting up WinRM"
cmd.exe /c winrm quickconfig -q
cmd.exe /c winrm set "winrm/config" '@{MaxTimeoutms="1800000"}'
cmd.exe /c winrm set "winrm/config/winrs" '@{MaxMemoryPerShellMB="1024"}'
cmd.exe /c winrm set "winrm/config/service" '@{AllowUnencrypted="true"}'
cmd.exe /c winrm set "winrm/config/client" '@{AllowUnencrypted="true"}'
cmd.exe /c winrm set "winrm/config/service/auth" '@{Basic="true"}'
cmd.exe /c winrm set "winrm/config/client/auth" '@{Basic="true"}'
cmd.exe /c winrm set "winrm/config/service/auth" '@{CredSSP="true"}'
cmd.exe /c winrm set "winrm/config/listener?Address=*+Transport=HTTPS" "@{Port=`"5986`";Hostname=`"packer`";CertificateThumbprint=`"$($Cert.Thumbprint)`"}"
cmd.exe /c netsh advfirewall firewall set rule group="remote administration" new enable=yes
cmd.exe /c netsh firewall add portopening TCP 5986 "Port 5986"
cmd.exe /c net stop winrm
cmd.exe /c sc config winrm start= auto
cmd.exe /c net start winrm
</powershell>
variables.pkvar.hcl
subid = "b83ba8f2-XXXXXXXXXXXX-8ea3710e139aXX"
tenant = "e034d95f-XXXXXXXXXXXXXXXXXXXXXXXXXX"
rgname = "DefaultResourceGroup"
capturenamename = "myimage"
location = "australiaeast"
username = "myadminusername"
password = "Password@thislocation"
I help organisations secure their cloud infrastructure and stay ahead of evolving cyber threats. Microsoft MVP and Certified Trainer, author of Mastering Azure Security, and founder of arnav.au — a platform for practical Cloud, Cybersecurity, DevOps and AI content.
Frequently Asked Questions
Packer is an open-source tool that creates identical machine images for multiple cloud platforms from a single source template. It's commonly used to build "golden images" that teams across an organization can standardize on, ensuring consistency and reducing deployment time in Azure and other cloud environments.
A Packer template has three main blocks: the Source block (which contains the Azure ARM configuration, settings, and plugins), the Build block (which includes builders, provisioners, and post-processors to create the image), and the Variable block (for defining reusable variables similar to Terraform). These blocks work together to define how your image is created and customized.
Packer is transitioning from JSON to HCL2 format for its configuration files. HCL2 is the same language used in Terraform, making it more familiar to infrastructure-as-code practitioners and providing better consistency across HashiCorp tools.
Packer creates a temporary resource group in Azure with a VM and necessary resources (IP, NIC, vNET, etc.), applies your customizations via provisioners (like PowerShell scripts), and then captures the configured VM as a managed image. Once created, the image is placed in the resource group you specified and can be used to create VMs or registered in an image gallery.
Key Packer commands include: `packer version` (displays version info), `packer fmt` (formats template files), `packer validate` (validates template syntax), `packer build` (creates the image), and `packer build -debug` (builds while providing debug output). These commands help you validate, format, and execute your Packer templates.