» Azure Resource Manager Builder

Type: azure-arm

Packer supports building VHDs in Azure Resource Manager. Azure provides new users a $200 credit for the first 30 days; after which you will incur costs for VMs built and stored using Packer.

Unlike most Packer builders, the artifact produced by the ARM builder is a VHD (virtual hard disk), not a full virtual machine image. This means you will need to perform some additional steps in order to launch a VM from your build artifact.

Azure uses a combination of OAuth and Active Directory to authorize requests to the ARM API. Learn how to authorize access to ARM.

The documentation below references command output from the Azure CLI.

» Configuration Reference

The following configuration options are available for building Azure images. In addition to the options listed here, a communicator can be configured for this builder.

» Required:

  • client_id (string) The Active Directory service principal associated with your builder.

  • client_secret (string) The password or secret for your service principal.

  • 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.

  • image_publisher (string) PublisherName for your base image. See documentation for details.

    CLI example az vm image list-publishers --location westus

  • image_offer (string) Offer for your base image. See documentation for details.

    CLI example az vm image list-offers --location westus --publisher Canonical

  • image_sku (string) SKU for your base image. See documentation for details.

    CLI example az vm image list-skus --location westus --publisher Canonical --offer UbuntuServer

» VHD or Managed Image

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. When creating a VHD the following two 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://<storage_account>.blob.core.windows.net/system/Microsoft.Compute/Images/<capture_container_name>/<capture_name_prefix>.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 two 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 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 to learn more about managed images.

» 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:

  • azure_tags (object of name/value strings) - the user can define up to 15 tags. Tag names cannot exceed 512 characters, and tag values cannot exceed 256 characters. Tags are applied to every resource deployed by a Packer build, i.e. Resource Group, VM, NIC, VNET, Public IP, KeyVault, etc.

  • cloud_environment_name (string) One of Public, China, Germany, or USGovernment. Defaults to Public. Long forms such as USGovernmentCloud and AzureUSGovernmentCloud are also supported.

  • custom_data_file (string) Specify a file containing custom data to inject into the cloud-init process. The contents of the file are read, base64 encoded, and injected into the ARM template. The custom data will be passed to cloud-init for processing at the time of provisioning. See documentation to learn more about custom data, and how it can be used to influence the provisioning process.

  • custom_managed_image_name (string) Specify the source managed image's name to use. If this value is set, do not set image_publisher, image_offer, image_sku, or image_version. If this value is set, the value custom_managed_image_resource_group_name must also be set. See documentation to learn more about managed images.

  • custom_managed_image_resource_group_name (string) Specify the source managed image's resource group used to use. If this value is set, do not set image_publisher, image_offer, image_sku, or image_version. If this value is set, the value custom_managed_image_name must also be set. See documentation to learn more about managed images.

  • image_version (string) Specify a specific version of an OS to boot from. Defaults to latest. There may be a difference in versions available across regions due to image synchronization latency. To ensure a consistent version across regions set this value to one that is available in all regions where you are deploying.

    CLI example az vm image list --location westus --publisher Canonical --offer UbuntuServer --sku 16.04.0-LTS --all

  • image_url (string) Specify a custom VHD to use. If this value is set, do not set image_publisher, image_offer, image_sku, or image_version.

  • managed_image_storage_account_type (string) Specify the storage account type for a managed image. Valid values are Standard_LRS and Premium_LRS. The default is Standard_LRS.

  • os_disk_size_gb (number) Specify the size of the OS disk in GB (gigabytes). Values of zero or less than zero are ignored.

  • disk_additional_size (array of integers) - The size(s) of any additional hard disks for the VM in gigabytes. If this is not specified then the VM will only contain an OS disk. The number of additional disks and maximum size of a disk depends on the configuration of your VM. See Windows or Linux for more information.

    For VHD builds the final artifacts will be named PREFIX-dataDisk-<n>.UUID.vhd and stored in the specified capture container along side the OS disk. The additional disks are included in the deployment template PREFIX-vmTemplate.UUID.

    For Managed build the final artifacts are included in the managed image. The additional disk will have the same storage account type as the OS disk, as specified with the managed_image_storage_account_type setting.

  • os_type (string) If either Linux or Windows is specified Packer will automatically configure authentication credentials for the provisioned machine. For Linux this configures an SSH authorized key. For Windows this configures a WinRM certificate.

  • plan_info (object) - Used for creating images from Marketplace images. Please refer to Deploy an image with Marketplace terms for more details. Not all Marketplace images support programmatic deployment, and support is controlled by the image publisher.

    An example plan_info object is defined below.

     {
        "plan_info": {
            "plan_name": "rabbitmq",
            "plan_product": "rabbitmq",
            "plan_publisher": "bitnami"
        }
     }
    

    plan_name (string) - The plan name, required. plan_product (string) - The plan product, required. plan_publisher (string) - The plan publisher, required. plan_promotion_code (string) - Some images accept a promotion code, optional.

    Images created from the Marketplace with plan_info must specify plan_info whenever the image is deployed. The builder automatically adds tags to the image to ensure this information is not lost. The following tags are added.

   1. PlanName
   1. PlanProduct
   1. PlanPublisher
   1. PlanPromotionCode
  • shared_image_gallery (object) Use a Shared Gallery image as the source for this build. VHD targets are incompatible with this build type - the target must be a Managed Image. "shared_image_gallery": { "subscription": "00000000-0000-0000-0000-00000000000", "resource_group": "ResourceGroup", "gallery_name": "GalleryName", "image_name": "ImageName", "image_version": "1.0.0" } "managed_image_name": "TargetImageName", "managed_image_resource_group_name": "TargetResourceGroup"

  • temp_compute_name (string) temporary name assigned to the VM. If this value is not set, a random value will be assigned. Knowing the resource group and VM name allows one to execute commands to update the VM during a Packer build, e.g. attach a resource disk to the VM.

  • tenant_id (string) The account identifier with which your client_id and subscription_id are associated. If not specified, tenant_id will be looked up using subscription_id.

  • private_virtual_network_with_public_ip (boolean) This value allows you to set a virtual_network_name and obtain a public IP. If this value is not set and virtual_network_name is defined Packer is only allowed to be executed from a host on the same subnet / virtual network.

  • virtual_network_name (string) Use a pre-existing virtual network for the VM. This option enables private communication with the VM, no public IP address is used or provisioned (unless you set private_virtual_network_with_public_ip).

  • virtual_network_resource_group_name (string) If virtual_network_name is set, this value may also be set. If virtual_network_name is set, and this value is not set the builder attempts to determine the resource group containing the virtual network. If the resource group cannot be found, or it cannot be disambiguated, this value should be set.

  • virtual_network_subnet_name (string) If virtual_network_name is set, this value may also be set. If virtual_network_name is set, and this value is not set the builder attempts to determine the subnet to use with the virtual network. If the subnet cannot be found, or it cannot be disambiguated, this value should be set.

  • vm_size (string) Size of the VM used for building. This can be changed when you deploy a VM from your VHD. See pricing information. Defaults to Standard_A1.

    CLI example az vm list-sizes --location westus

  • async_resourcegroup_delete (boolean) If you want packer to delete the temporary resource group asynchronously set this value. It's a boolean value and defaults to false. Important Setting this true means that your builds are faster, however any failed deletes are not reported.

» Basic Example

Here is a basic example for Azure.

{
    "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 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

{
    "provisioners": [
    {
        "type": "powershell",
        "inline": [
            "& $env:SystemRoot\\System32\\Sysprep\\Sysprep.exe /oobe /generalize /quiet /quit",
            "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 } }"
        ]
    }
  ]
}

» Linux

The following provisioner snippet shows how to deprovision a Linux VM. Deprovision should be the last operation executed by a build.

{
 "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"
   }
 ]
}

To learn more about the Linux deprovision process please see WALinuxAgent's README.

» 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

The Azure builder uses ARM 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-<random>. The value <random> is a random value that is generated at every invocation of packer. The <random> 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.
  • 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.

» 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 folder in the packer project for more examples.