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.
Background
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
brew install hashicorp/tap/packer
- Install packer
packer -v
- 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.
- SSH into the Proxmox node
cd <ISO directory>
wget <Windows ISO URL>
wget <VirtIO Windows driver>
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
vault login
vault secrets enable -version=2 -path=secrets kv
Setup Policies
vault policy write packer-read-only vault_policies/read-only.hcl
- Add the read-only policy for Packer secrets
vault policy write packer-admin vault_policies/admin.hcl
- Add the admin policy for Packer secrets
- Attach the policies to their respective users
Proxmox secrets
vault kv put secrets/proxmox proxmox_url=https://<Proxmox IP addr or FQDN>/api2/json
- Set the Proxmox URL
vault kv patch secrets/proxmox proxmox_host=<Proxmox node name>
- Set the Proxmox node to create VM on
vault kv patch secrets/proxmox proxmox_username=<proxmox_username>@pam
- Set the Proxmox username
vault kv patch secrets/proxmox proxmox_password=changeme
- Set the Proxmox password
vault kv patch secrets/proxmox proxmox_skip_tls_verify=false
- Define if Packer should validate the TLS certificate
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.
vault kv put secrets/packer/win10x64 @vault-win10x64-vars.json
vault kv get secrets/packer/win10x64
vault kv patch secrets/packer/win10x64 winrm_username=vagrant
- Set username to be used by WinRM
vault kv patch secrets/packer/win10x64 winrm_password=vagrant
- Set password to be used by WinRM
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.
git clone https://github.com/CptOfEvilMinions/BlogProjects/tree/master/packer-windows
cd BlogProjects/packer-windows
- macOS
hdiutil makehybrid -o Autounattend.iso -hfs -joliet -iso -default-volume-name cidata <input_directory>
- If the command above ran successfully an Autounattend.iso should be generated
scp Autounattend.iso <username>@<proxmox>:<ISO directory>/Autounattend.iso
- Linux
mkisofs -J -l -R -V "Label CD" -iso-level 4 -o Autounattend.iso <input_directory>
Packer compose
Variables
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
- Ex:
proxmox_host
– Specify the Proxmox node to build the VM onproxmox_username
– Specify a Proxmox username that has the permissions to create a VMproxmox_password
– Specify a Proxmox password that has the permissions to create a VMproxmox_skip_tls_verify
– Specify whether Packer should validate the TLS serving Proxmox
- WinRM
winrm_username
– Specify the username in theAutounattend.xml
file to create the default userwinrm_password
– Specify the password in theAutounattend.xml
file to create the default user
- VM
vm_name
– Name of the VM templatetemplate_description
– Description for the VM templateiso_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
- Ex:
vm_cpu_cores
– Specify how many CPU cores to allocate the VM templatevm_memory
– Specify how much memory to allocate the VM templatevm_disk_size
– Specify the size of the hard drive for the VM template
Packer build
export VAULT_TOKEN=`vault token lookup --format=json | jq -r '.data.id'`
- Request the users token and store it in an environment variable for Packer
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
Challenges
- 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 notsecrets/proxmox
which is how you interact with secrets with the Vault CLI
References
- Github – boxcutter/windows
- OS X equivalents for Ubuntu’s genisoimage and qemu-img
- How to create an ISO image from a Folder (Linux)
- Announcing HashiCorp’s Homebrew Tap
- Packer – Proxmox Builder
- Vault – Policies
- Vault – KV Secrets Engine – Version 2 (API)
- Packer – Debugging Packer Builds
- Github issue – Using Packer with Vault Secret Engine KV2 #7204
- Packer – Template User Variables
- Vault – Secrets Engines
- Vault – kv patch
- Github – CptOfEvilMinions/BlogProjects – packer-windows