--- description: Packer supports building VHDs in Azure Resource manager. page_title: Azure arm - Builders --- # Azure Resource Manager Builder Type: `azure-arm` Artifact BuilderId: `Azure.ResourceManagement.VMImage` Packer supports building Virtual Hard Disks (VHDs) and Managed Images in [Azure Resource Manager](https://azure.microsoft.com/en-us/documentation/articles/resource-group-overview/). Azure provides new users a [`$200` credit for the first 30 days](https://azure.microsoft.com/en-us/free/); after which you will incur costs for VMs built and stored using Packer. Azure uses a combination of OAuth and Active Directory to authorize requests to the ARM API. Learn how to [authorize access to ARM](/docs/builders/azure#authentication-for-azure). The documentation below references command output from the [Azure CLI](https://azure.microsoft.com/en-us/documentation/articles/xplat-cli-install/). ## Configuration Reference There are many configuration options available for the builder. We'll start with authentication parameters, then go over the Azure ARM builder specific options. In addition to the options listed here, a [communicator](/docs/templates/legacy_json_templates/communicator) can be configured for this builder. ### Authentication options @include 'builder/azure/common/client/Config.mdx' #### Managed Identity If you're running Packer on an Azure VM with a [managed identity](/docs/builders/azure#azure-managed-identity) you don't need to specify any additional configuration options. As Packer will attempt to use the Managed Identity and subscription of the VM that Packer is running on. #### Interactive User Authentication To use interactive user authentication, you should specify `subscription_id` only. Packer will use cached credentials or redirect you to a website to log in. #### Service Principal To use a [service principal](/docs/builders/azure#azure-active-directory-service-principal) you should specify `subscription_id`, `client_id` and one of `client_secret`, `client_cert_path` or `client_jwt`. - `subscription_id` (string) - Subscription under which the build will be performed. **The service principal specified in `client_id` must have full access to this subscription, unless build_resource_group_name option is specified in which case it needs to have owner access to the existing resource group specified in build_resource_group_name parameter.** - `client_id` (string) - The Active Directory service principal associated with your builder. - `client_secret` (string) - The password or secret for your service principal. - `client_cert_path` (string) - The location of a PEM file containing a certificate and private key for service principal. - `client_cert_token_timeout` (duration string | ex: "1h30m12s") - How long to set the expire time on the token created when using `client_cert_path`. - `client_jwt` (string) - The bearer JWT assertion signed using a certificate associated with your service principal principal. See [Azure Active Directory docs](https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-certificate-credentials) for more information. ### Azure ARM builder specific options The Azure builder can create either a VHD or a managed image. If you are creating a VHD, you **must** start with a VHD. Likewise, if you want to create a managed image you **must** start with a managed image. ### Required: @include 'builder/azure/arm/Config-required.mdx' When creating a VHD the following additional options are required: - `capture_container_name` (string) - Destination container name. Essentially the "directory" where your VHD will be organized in Azure. The captured VHD's URL will be `https://.blob.core.windows.net/system/Microsoft.Compute/Images//.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.vhd`. - `capture_name_prefix` (string) - VHD prefix. The final artifacts will be named `PREFIX-osDisk.UUID` and `PREFIX-vmTemplate.UUID`. - `resource_group_name` (string) - Resource group under which the final artifact will be stored. - `storage_account` (string) - Storage account under which the final artifact will be stored. When creating a managed image the following additional options are required: - `managed_image_name` (string) - Specify the managed image name where the result of the Packer build will be saved. The image name must not exist ahead of time, and will not be overwritten. If this value is set, the value `managed_image_resource_group_name` must also be set. See [documentation](https://docs.microsoft.com/en-us/azure/storage/storage-managed-disks-overview#images) to learn more about managed images. - `managed_image_resource_group_name` (string) - Specify the managed image resource group name where the result of the Packer build will be saved. The resource group must already exist. If this value is set, the value `managed_image_name` must also be set. See [documentation](https://docs.microsoft.com/en-us/azure/storage/storage-managed-disks-overview#images) to learn more about managed images. Creating a managed image using a [Shared Gallery image](https://azure.microsoft.com/en-us/blog/announcing-the-public-preview-of-shared-image-gallery/) as the source can be achieved by specifying the [shared_image_gallery](#shared_image_gallery) configuration option. #### Resource Group Usage The Azure builder can either provision resources into a new resource group that it controls (default) or an existing one. The advantage of using a packer defined resource group is that failed resource cleanup is easier because you can simply remove the entire resource group, however this means that the provided credentials must have permission to create and remove resource groups. By using an existing resource group you can scope the provided credentials to just this group, however failed builds are more likely to leave unused artifacts. To have Packer create a resource group you **must** provide: - `location` (string) Azure datacenter in which your VM will build. CLI example `az account list-locations` and optionally: - `temp_resource_group_name` (string) name assigned to the temporary resource group created during the build. If this value is not set, a random value will be assigned. This resource group is deleted at the end of the build. To use an existing resource group you **must** provide: - `build_resource_group_name` (string) - Specify an existing resource group to run the build in. Providing `temp_resource_group_name` or `location` in combination with `build_resource_group_name` is not allowed. ### Optional: @include 'builder/azure/arm/Config-not-required.mdx' @include 'builder/azure/common/client/Config-not-required.mdx' ### Communicator Config In addition to the builder options, a communicator may also be defined: @include 'packer-plugin-sdk/communicator/Config-not-required.mdx' @include 'packer-plugin-sdk/communicator/SSH-not-required.mdx' @include 'packer-plugin-sdk/communicator/SSH-Private-Key-File-not-required.mdx' ## Basic Example Here is a basic example for Azure. ```hcl source "azure-arm" "basic-example" { client_id = "fe354398-d7sf-4dc9-87fd-c432cd8a7e09" client_secret = "keepitsecret&#*$" resource_group_name = "packerdemo" storage_account = "virtualmachines" subscription_id = "44cae533-4247-4093-42cf-897ded6e7823" tenant_id = "de39842a-caba-497e-a798-7896aea43218" capture_container_name = "images" capture_name_prefix = "packer" os_type = "Linux" image_publisher = "Canonical" image_offer = "UbuntuServer" image_sku = "14.04.4-LTS" azure_tags = { dept = "engineering" } location = "West US" vm_size = "Standard_A2" } build { sources = ["sources.azure-arm.basic-example"] } ``` ```json { "type": "azure-arm", "client_id": "fe354398-d7sf-4dc9-87fd-c432cd8a7e09", "client_secret": "keepitsecret&#*$", "resource_group_name": "packerdemo", "storage_account": "virtualmachines", "subscription_id": "44cae533-4247-4093-42cf-897ded6e7823", "tenant_id": "de39842a-caba-497e-a798-7896aea43218", "capture_container_name": "images", "capture_name_prefix": "packer", "os_type": "Linux", "image_publisher": "Canonical", "image_offer": "UbuntuServer", "image_sku": "14.04.4-LTS", "azure_tags": { "dept": "engineering" }, "location": "West US", "vm_size": "Standard_A2" } ``` ## Deprovision Azure VMs should be deprovisioned at the end of every build. For Windows this means executing sysprep, and for Linux this means executing the waagent deprovision process. Please refer to the Azure [examples](https://github.com/hashicorp/packer/tree/master/builder/azure/examples) for complete examples showing the deprovision process. ### Windows The following provisioner snippet shows how to sysprep a Windows VM. Deprovision should be the last operation executed by a build. The code below will wait for sysprep to write the image status in the registry and will exit after that. The possible states, in case you want to wait for another state, [are documented here](https://technet.microsoft.com/en-us/library/hh824815.aspx) ```json { "provisioners": [ { "type": "powershell", "inline": [ " # NOTE: the following *3* lines are only needed if the you have installed the Guest Agent.", " while ((Get-Service RdAgent).Status -ne 'Running') { Start-Sleep -s 5 }", " while ((Get-Service WindowsAzureTelemetryService).Status -ne 'Running') { Start-Sleep -s 5 }", " while ((Get-Service WindowsAzureGuestAgent).Status -ne 'Running') { Start-Sleep -s 5 }", "& $env:SystemRoot\\System32\\Sysprep\\Sysprep.exe /oobe /generalize /quiet /quit /mode:vm", "while($true) { $imageState = Get-ItemProperty HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State | Select ImageState; if($imageState.ImageState -ne 'IMAGE_STATE_GENERALIZE_RESEAL_TO_OOBE') { Write-Output $imageState.ImageState; Start-Sleep -s 10 } else { break } }" ] } ] } ``` ```hcl provisioner "powershell" { inline = [ " # NOTE: the following *3* lines are only needed if the you have installed the Guest Agent.", " while ((Get-Service RdAgent).Status -ne 'Running') { Start-Sleep -s 5 }", " while ((Get-Service WindowsAzureTelemetryService).Status -ne 'Running') { Start-Sleep -s 5 }", " while ((Get-Service WindowsAzureGuestAgent).Status -ne 'Running') { Start-Sleep -s 5 }", "& $env:SystemRoot\\System32\\Sysprep\\Sysprep.exe /oobe /generalize /quiet /quit /mode:vm", "while($true) { $imageState = Get-ItemProperty HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State | Select ImageState; if($imageState.ImageState -ne 'IMAGE_STATE_GENERALIZE_RESEAL_TO_OOBE') { Write-Output $imageState.ImageState; Start-Sleep -s 10 } else { break } }" ] } ``` The Windows Guest Agent participates in the Sysprep process. The agent must be fully installed before the VM can be sysprep'ed. To ensure this is true all agent services must be running before executing sysprep.exe. The above JSON snippet shows one way to do this in the PowerShell provisioner. This snippet is **only** required if the VM is configured to install the agent, which is the default. To learn more about disabling the Windows Guest Agent please see [Install the VM Agent](https://docs.microsoft.com/en-us/azure/virtual-machines/extensions/agent-windows#install-the-vm-agent). Please note that sysprep can get stuck in infinite loops if it is not configured correctly -- for example, if it is waiting for a reboot that you never perform. ### Linux The following provisioner snippet shows how to deprovision a Linux VM. Deprovision should be the last operation executed by a build. ```json { "provisioners": [ { "execute_command": "chmod +x {{ .Path }}; {{ .Vars }} sudo -E sh '{{ .Path }}'", "inline": [ "/usr/sbin/waagent -force -deprovision+user && export HISTSIZE=0 && sync" ], "inline_shebang": "/bin/sh -x", "type": "shell" } ] } ``` ```hcl provisioner "shell" { execute_command = "chmod +x {{ .Path }}; {{ .Vars }} sudo -E sh '{{ .Path }}'" inline = [ "/usr/sbin/waagent -force -deprovision+user && export HISTSIZE=0 && sync" ] inline_shebang = "/bin/sh -x" } ``` To learn more about the Linux deprovision process please see WALinuxAgent's [README](https://github.com/Azure/WALinuxAgent/blob/master/README.md). #### skip_clean Customers have reported issues with the deprovision process where the builder hangs. The error message is similar to the following. Build 'azure-arm' errored: Retryable error: Error removing temporary script at /tmp/script_9899.sh: ssh: handshake failed: EOF One solution is to set skip_clean to true in the provisioner. This prevents Packer from cleaning up any helper scripts uploaded to the VM during the build. ## Defaults The Azure builder attempts to pick default values that provide for a just works experience. These values can be changed by the user to more suitable values. - The default user name is Packer not root as in other builders. Most distros on Azure do not allow root to SSH to a VM hence the need for a non-root default user. Set the ssh_username option to override the default value. - The default VM size is Standard_A1. Set the vm_size option to override the default value. - The default image version is latest. Set the image_version option to override the default value. - By default a temporary resource group will be created and destroyed as part of the build. If you do not have permissions to do so, use `build_resource_group_name` to specify an existing resource group to run the build in. ## Implementation ~> **Warning!** This is an advanced topic. You do not need to understand the implementation to use the Azure builder. The Azure builder uses ARM [templates](https://azure.microsoft.com/en-us/documentation/articles/resource-group-authoring-templates/) to deploy resources. ARM templates allow you to express the what without having to express the how. The Azure builder works under the assumption that it creates everything it needs to execute a build. When the build has completed it simply deletes the resource group to cleanup any runtime resources. Resource groups are named using the form `packer-Resource-Group-`. The value `` is a random value that is generated at every invocation of packer. The `` value is re-used as much as possible when naming resources, so users can better identify and group these transient resources when seen in their subscription. > The VHD is created on a user specified storage account, not a random one > created at runtime. When a virtual machine is captured the resulting VHD is > stored on the same storage account as the source VHD. The VHD created by > Packer must persist after a build is complete, which is why the storage > account is set by the user. The basic steps for a build are: 1. Create a resource group. 2. Validate and deploy a VM template. 3. Execute provision - defined by the user; typically shell commands. 4. Power off and capture the VM. 5. Delete the resource group. 6. Delete the temporary VM's OS disk. The templates used for a build are currently fixed in the code. There is a template for Linux, Windows, and KeyVault. The templates are themselves templated with place holders for names, passwords, SSH keys, certificates, etc. ### What's Randomized? The Azure builder creates the following random values at runtime. - Administrator Password: a random 32-character value using the _password alphabet_. - Certificate: a 2,048-bit certificate used to secure WinRM communication. The certificate is valid for 24-hours, which starts roughly at invocation time. - Certificate Password: a random 32-character value using the _password alphabet_ used to protect the private key of the certificate. - Compute Name: a random 15-character name prefixed with pkrvm; the name of the VM. - Deployment Name: a random 15-character name prefixed with pkfdp; the name of the deployment. - KeyVault Name: a random 15-character name prefixed with pkrkv. - NIC Name: a random 15-character name prefixed with pkrni. - Public IP Name: a random 15-character name prefixed with pkrip. - OS Disk Name: a random 15-character name prefixed with pkros. - Data Disk Name: a random 15-character name prefixed with pkrdd. - Resource Group Name: a random 33-character name prefixed with packer-Resource-Group-. - Subnet Name: a random 15-character name prefixed with pkrsn. - SSH Key Pair: a 2,048-bit asymmetric key pair; can be overridden by the user. - Virtual Network Name: a random 15-character name prefixed with pkrvn. The default alphabet used for random values is **0123456789bcdfghjklmnpqrstvwxyz**. The alphabet was reduced (no vowels) to prevent running afoul of Azure decency controls. The password alphabet used for random values is **0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ**. ### Deprecation Warning You may see a scary-looking deprecation warning when you run the Azure builder: ``` ==> azure-arm: Warning: You are using Azure Packer Builder to create VHDs which is being deprecated, consider using Managed Images. Learn more http://aka.ms/packermanagedimage ``` Don't panic. Your build won't stop working next week. Long-term, Azure wants everyone to move to using managed images and managed disks because they hide the complexity with respect to storage account performance. Managed disks can be exported to a VHD. If this is deprecated, it will be done in a transparent process by the Microsoft team who help maintain Packer. In the future, Packer may remove VHD support but add a post-processor that can automate the export to a storage account. ### Windows The Windows implementation is very similar to the Linux build, with the exception that it deploys a template to configure KeyVault. Packer communicates with a Windows VM using the WinRM protocol. Windows VMs on Azure default to using both password and certificate based authentication for WinRM. The password is easily set via the VM ARM template, but the certificate requires an intermediary. The intermediary for Azure is KeyVault. The certificate is uploaded to a new KeyVault provisioned in the same resource group as the VM. When the Windows VM is deployed, it links to the certificate in KeyVault, and Azure will ensure the certificate is injected as part of deployment. The basic steps for a Windows build are: 1. Create a resource group. 2. Validate and deploy a KeyVault template. 3. Validate and deploy a VM template. 4. Execute provision - defined by the user; typically shell commands. 5. Power off and capture the VM. 6. Delete the resource group. 7. Delete the temporary VM's OS disk. A Windows build requires two templates and two deployments. Unfortunately, the KeyVault and VM cannot be deployed at the same time hence the need for two templates and deployments. The time required to deploy a KeyVault template is minimal, so overall impact is small. See the [examples/azure](https://github.com/hashicorp/packer/tree/master/builder/azure/examples) folder in the Packer project for more examples.