Create Proxmox VM with Terraform

Page content

In this post I will show you how how you can create a Proxmox VMs with Terraform.

To ease the creation of the VMs in Proxmox I will use predefined VM templates. So our first task is create the template. To do this login to one of the proxmox nodes.

# installing libguestfs-tools only required once, prior to first run
sudo apt update -y
sudo apt install libguestfs-tools -y

# download a debian cloud-init disk image:
wget http://cloud.debian.org/images/cloud/bullseye/latest/debian-11-generic-amd64.qcow2

sudo virt-customize -a debian-11-generic-amd64.qcow2 --install qemu-guest-agent
sudo qm create 100200 --name "debian11.vm.shiwaforce.com" --memory 2048 --cores 2 --net0 virtio,bridge=vmbr0

sudo qm importdisk 100200 debian-11-generic-amd64.qcow2 zfs-vm-none
sudo qm set 100200 --scsihw virtio-scsi-pci --scsi0 zfs-vm-none:vm-100200-disk-0
sudo qm set 100200 --boot c --bootdisk scsi0
sudo qm set 100200 --ide2 zfs-vm-none:cloudinit
sudo qm set 100200 --serial0 socket --vga serial0
sudo qm set 100200 --agent enabled=1
sudo qm template 100200

rm debian-11-generic-amd64.qcow2

Determine Authentication Method (use API keys)

The next step is to create a service account in proxmox for authentication and generate an authentication token:

pveum role add TerraformProv -privs "Pool.Allocate VM.Console VM.Allocate VM.Clone VM.Config.CDROM VM.Config.CPU VM.Config.Cloudinit VM.Config.Disk VM.Config.HWType VM.Config.Memory VM.Config.Network VM.Config.Options VM.Monitor VM.Audit VM.PowerMgmt Datastore.AllocateSpace Datastore.Audit"
pveum user add tfuser@pve
pveum aclmod / -user tfuser@pve -role TerraformProv
pveum user token add tfuser@pve terraform --privsep 0

# Please save the token secret as there isn't any way to fetch it at a later point.

Create teh Terraform config files

mkdir terraform
cd terraform

Create backend config:

nano backend.tf 
terraform {
  required_providers {
    proxmox = {
      source  = "telmate/proxmox"
      version = "2.9.11"
    }
  }
  backend "local" {
  }
}

Create provider config:

nano provider.tf
provider "proxmox" {
  pm_api_url = "https://proxmox.mydomain.intra:8006/api2/json"
  # api token id is in the form of: <username>@pam!<tokenId>
  pm_api_token_id = "tfuser@pve!terraform"
  # this is the full secret wrapped in quotes.
  pm_api_token_secret = var.PROXMOX_API_SECRET
  pm_tls_insecure     = true

  # debug log
  #  pm_log_enable = true
  #  pm_log_file   = "terraform-plugin-proxmox.log"
  #  pm_debug      = true
  #  pm_log_levels = {
  #    _default    = "debug"
  #    _capturelog = ""
  #  }
}

The auth token will be ised from the PROXMOX_API_SECRET linux environment variable. Now create the terraform variable file:

nano vars.tf
variable "PROXMOX_API_SECRET" {
  type = string
}

variable "ssh_key" {
  default = "ssh-rsa AAAAB3NzaC1y..."
}

variable "proxmox_host" {
  default = "proxmox"
}
variable "template_name" {
  default = "debian11.vm.shiwaforce.com"
}

Create the main Terraform config file vit the resource definitions:

touch main.tf 

nano k8s-master.tf 
resource "proxmox_vm_qemu" "k8s-master" {
  count       = 3
  name        = "k8s0${count.index + 1}.mydomain.intra"
  target_node = var.proxmox_host
  vmid        = "101${count.index + 1}"
  clone       = var.template_name
  os_type     = "cloud-init"
  cpu         = "kvm64"
  cores       = 2
  sockets     = 1
  memory      = 6144
  scsihw      = "virtio-scsi-pci"
  bootdisk    = "scsi0"

  disk {
    slot     = 0
    size     = "50G"
    type     = "scsi"
    storage  = "zfs-vm-etc"
    iothread = 1
  }

  network {
    model     = "virtio"
    bridge    = "vmbr0"
    tag       = 101
    firewall  = false
    link_down = false
  }

  ipconfig0 = "ip=192.168.10.1${count.index + 1}/22,gw=192.168.10.1"
  ciuser    = "terraform"
  sshkeys   = <<EOF
  ${var.ssh_key}
  EOF
}

If you created all the files it looks like this:

cd ..
tree .
.
└── terraform
    ├── backend.tf
    ├── provider.tf
    ├── outputs.tf
    ├── k8s-master.tf 
    └── vars.tf

1 directory, 5 files

Now we can create the VMs:

export PROXMOX_API_SECRET="9f881350-175c-4a09-a25c-bce726ada447"

# inicialise the terraform modules
terraform init --upgrade

# generate a terraform plan
terraform plan -out k8s-master.tfplan

# deploym the VMs
terraform apply -parallelism=1 -auto-approve k8s-master.tfplan

# cleanup
terraform plan -destroy -out k8s-master.destroy.tfplan
terraform apply k8s-master.destroy.tfplan