Automating Proxmox with Terraform and Ansible

Automating Proxmox with Terraform and Ansible

- 3 mins

During the hoidays I played around a bit with automating parts of my Proxmox homeserver setup. It consists of various LXC containers (CT) and Virtual Machines (VMs) for dedicated tasks and while I don’t regularly setup new containers and VMs, it’d be nice to have an quick and automated way of doing so.

For this automation I created a simple configuration that provisions a VM or CT using Terraform and Ansible. Telemate developed a Terraform provider that maps Terraform functionality to the Proxmox API, so start by defining the use of that provider in version.tf.

terraform {
  required_providers {
    proxmox = {
      source = "Telmate/proxmox"
      version = "2.6.6"
    }
  }
}

In main.tf I’ve defined the variables for the Telemate Proxmox provider, for which the values of these are assigned in var.tf.

provider "proxmox" {
    pm_api_url = var.proxmox_host["pm_api_url"]
    pm_user = var.proxmox_host["pm_user"]
    pm_tls_insecure = true
}

The next block in main.tf defines a Proxmox QEMU VM resource "proxmox_vm_qemu" {} or resource "proxmox_lxc" {}. Probably the most interesting part here it that my Terraform configuration supports the creation of multiple resources at once, by defining the hostnames and IP addresses respectively in var.tf:

variable "hostnames" {
  description = "Virtual machines to be created"
  type        = list(string)
  default     = ["prod-vm", "staging-vm", "dev-vm"]
}

variable "ips" {
    description = "IPs of the VMs, respective to the hostname order"
    type        = list(string)
	default     = ["10.0.42.83", "10.0.42.84", "10.0.42.85"]
}

In addition, I use Ansible as a provioner after the VM has been created. The host that kicks off the Terraform configuration will also run the Ansible playbook that in my default configuration will update the OS, create a sudo user, secure SSH and upload the SSH public keys you specify in ansible/files/authorized_keys.

I use the Terraform connection block before provisioning to check whether the VM or container initialization is complete. Terraform will retry the connection and only continue executing the configuration when that connection is successful.

  # defines ssh connection to check when the VM is ready for ansible provisioning
  connection {
    host = var.ips[count.index]
    user = var.user
    private_key = file(var.ssh_keys["priv"])
    agent = false
    timeout = "3m"
  } 

  provisioner "remote-exec" {
    inline = [ "echo 'Cool, we are ready for provisioning'"]
  }
  
  provisioner "local-exec" {
    working_dir = "../../ansible/"
    command = "ansible-playbook -u ${var.user} --key-file ${var.ssh_keys["priv"]} -i ${var.ips[count.index]}, provision.yaml"
  }

Cloud-init

The configuration will use a VM template created by cloud-init. There are various guides on how to configure one. Make sure the name of the templates matches clone in main.tf.

Usage

The complete Terraform configuration and Ansible scripts I created are available on Github.

  1. Install Terraform and Ansible on your machine
    • macOS: brew install terraform ansible
    • Ubuntu: apt install ansible and install terraform
  2. git clone https://github.com/vivami/proxmox-automation.git
  3. Define your SSH keys in proxmox-automation/ansible/files/authorized_keys
  4. Go to one of the directories tf/ct/ or tf/vm/ and run terraform init. This will initialize the Terraform configuration and pull in the Proxmox provider. 1

  5. Store your Proxmox password in the environment variable $PM_PASS:
    • set +o history (disable history before storing secrets in variables)
    • export PM_PASS='your_proxmox_pass'
  6. Configure var.tf (e.g. add your own private keys, hostnames/IPs) and main.tf where necessary
  7. Run terraform plan -out plan and if everything seems good terraform apply.
  8. SSH into the box using ssh notroot@<configured_IP> -i ~/.ssh/private_key

To destory to infra created run terraform destroy. 2

rss facebook twitter github youtube mail spotify lastfm instagram linkedin google google-plus pinterest medium vimeo stackoverflow reddit quora quora mastodon