Creating a Windows 10 64-bit VM on Proxmox with Packer v1.6.3 and Vault

This blog post is going to demonstrate how to implement a new feature added to Packer in version 1.6.3. This new feature provides the ability to mount multiple ISOs on Proxmox VMs because Proxmox “doesn’t” support virtual floppy drives. Since Proxmox doesn’t support virtual floppy drives you can’t supply an Autounattend.xml file to automate the installation and initial configuration of Windows. By converting an Autounattend.xml file to an ISO we can now mount the ISO to install the OS and the ISO containing the necessary file to automate the installation. Lastly, I will be using Vault to store my sensitive values required by Packer to create this VM.


What is Packer?

Packer is an open-source tool for creating identical machine images for multiple platforms from a single source configuration. Packer is lightweight, runs on every major operating system, and is highly performant, creating machine images for multiple platforms in parallel.

Install Packer v1.6.3 on macOS

  1. brew install hashicorp/tap/packer
    1. Install packer
  2. packer -v
    1. Make sure the version is 1.6.3 or higher

Setup Proxmox

Download Windows and Windows VirtoIO driver ISOs

You can instruct Packer to download the ISO via a URL but for Windows, I find this process tedious, First, Packer has to download it locally on the machine Packer is being executed on. Next, Packer has to upload the ISO to Proxmox. Since my server is remote I have a 5MB upload speed to my server, which takes about two hours to upload the ISO to Proxmox. Since the network for my Proxmox instance has 1GB down it takes seconds to download a 4GB ISO onto Proxmox directly. If you prefer the ISO URL download method skip this section.

  1. SSH into the Proxmox node
  2. cd <ISO directory>
  3. wget <Windows ISO URL>
    1. Windows 10 x64 Enterprise
  4. wget <VirtIO Windows driver>
    1. virtio-win-0.1.185.iso

Setup Vault

Lately, I have been integrating Vault into a lot of my projects and I am continuing that here. If your environment does not have Vault you can replace all {{ vault "<secret/path>" secret }} with actual values and you can skip this section. If you want to take a look at how to integrate Vault into your Packer builds keep reading.

Enable secrets engine

  1. vault login
  2. vault secrets enable -version=2 -path=secrets kv

Setup Policies

  1. vault policy write packer-read-only vault_policies/read-only.hcl
    1. Add the read-only policy for Packer secrets
  2. vault policy write packer-admin vault_policies/admin.hcl
    1. Add the admin policy for Packer secrets
  3. Attach the policies to their respective users

Proxmox secrets

  1. vault kv put secrets/proxmox proxmox_url=https://<Proxmox IP addr or FQDN>/api2/json
    1. Set the Proxmox URL
  2. vault kv patch secrets/proxmox proxmox_host=<Proxmox node name>
    1. Set the Proxmox node to create VM on
  3. vault kv patch secrets/proxmox proxmox_username=<proxmox_username>@pam
    1. Set the Proxmox username
  4. vault kv patch secrets/proxmox proxmox_password=changeme
    1. Set the Proxmox password
  5. vault kv patch secrets/proxmox proxmox_skip_tls_verify=false
    1. Define if Packer should validate the TLS certificate
  6. vault kv get secrets/proxmox

Windows secrets

Since a majority of these values are not secret I provided a vault-win10x64-vars.json which can make the process easier. Vault will accept secret key-value pairs from a JSON which I provided with NON-secret values.

  1. vault kv put secrets/packer/win10x64 @vault-win10x64-vars.json
  2. vault kv get secrets/packer/win10x64
  3. vault kv patch secrets/packer/win10x64 winrm_username=vagrant
    1. Set username to be used by WinRM
  4. vault kv patch secrets/packer/win10x64 winrm_password=vagrant
    1. Set password to be used by WinRM
  5. vault kv get secrets/win10x64

Compose a Windows build for Packer

Convert Autounattend.xml to Autounattend.iso

During a typical Windows installation, the Autounattend.xml would be provided via a floppy device. However, as I stated above, Proxmox does not support floppy devices. This new Packer feature provides the ability to mount multiple ISOs for a Windows VM, therefore, we have to convert the XML file to an ISO.

  1. git clone
  2. cd BlogProjects/packer-windows
  3.  macOS
    1. hdiutil makehybrid -o Autounattend.iso -hfs -joliet -iso -default-volume-name cidata <input_directory>
      1. If the command above ran successfully an Autounattend.iso should be generated
    2. scp Autounattend.iso <username>@<proxmox>:<ISO directory>/Autounattend.iso
  4. Linux
    1. mkisofs -J -l -R -V "Label CD" -iso-level 4 -o Autounattend.iso <input_directory>

Packer compose


As you can see from the screenshot below this Packer file does not contain any secrets. By specifying Vault as the location of the secret Packer will reach out to Vault for it. Not only does Vault contain sensitive values it can also contain values to standardize building templates, such as VM name, VM template description, how many CPU cores, and how much memory to allocate the VM template.

  • Proxmox
    • proxmox_url – This value specifies the location of Proxmox by specifying the location of the API
      • Ex: https://proxmox.local/api2/json
    • proxmox_host – Specify the Proxmox node to build the VM on
    • proxmox_username – Specify a Proxmox username that has the permissions to create a VM
    • proxmox_password – Specify a Proxmox password that has the permissions to create a VM
    • proxmox_skip_tls_verify – Specify whether Packer should validate the TLS serving Proxmox
  • WinRM
    • winrm_username – Specify the username in the Autounattend.xml file to create the default user
    • winrm_password – Specify the password in the Autounattend.xml file to create the default user
  • VM
    • vm_name – Name of the VM template
    • template_description – Description for the VM template
    • iso_file – Specify the location of the ISO on the Proxmox cluster
      • Ex: <proxmox datastore path>:iso/<ISO file name>
      • Ex: local:iso/Fedora-Server-dvd-x86_64-29-1.2.iso
      • Packer docs on iso_file
    • vm_cpu_cores – Specify how many CPU cores to allocate the VM template
    • vm_memory – Specify how much memory to allocate the VM template
    • vm_disk_size – Specify the size of the hard drive for the VM template

Packer build

  1. export VAULT_TOKEN=`vault token lookup --format=json | jq -r ''`
    1. Request the users token and store it in an environment variable for Packer
  2. packer build win10x64-enterprise.json


What now?!?!?

So this blog post is a jumping-off point for me to complete a REALLY awesome blog series. In the past, I have set up the Cuckoo sandbox and the HARDEST part about Cuckoo is the creation and maintenance of VMs. This new Packer feature allows me to automate the building of Windows VMs on Proxmox.

Lessons learned

I am currently reading a book called “Cracking the Coding Interview” and it is a great book. One interesting part of the book is their matrix to describe projects you worked on and the matrix contains the following sections which are: challenges, mistakes/failures, enjoyed, leadership, conflicts, and what would you do differently. I am going to try and use this model at the end of my blog posts to summarize and reflect on the things I learn. I don’t blog to post things that I know, I blog to learn new things and to share the knowledge of my security research.

New skills/knowledge

  • Integrate Packer and Vault
  • Learned how to configure the Autounattend.xml


  • Getting a working configuration and setup to allow Packer to connect to the VM via WinRM. Packer is unable to obtain the VM’s IP address unless the VM has the VirtIO drivers and QEMU agent installed.
  • The path to secrets is actually secrets/data/proxmox and not secrets/proxmox which is how you interact with secrets with the Vault CLI


Leave a Reply

Your email address will not be published.