Terraform avec Proxmox PVE
Terraform est un outil puissant d'infrastructure as code développé par HashiCorp. Il permet de définir et de provisionner l'infrastructure de manière déclarative, en utilisant un langage de configuration, le HCL. Grâce à Terraform, les équipes peuvent gérer de manière cohérente et automatisée des ressources cloud, sur site ou hybrides, en réduisant les erreurs manuelles et en accélérant le déploiement.
Dans cet article, je fais la démonstration de l'utilisation de Terraform avec Proxmox en exploitant du cloudinit, les VLAN, spécifications de la carte réseau ainsi que l'emplacement du datastore.
Le code Terraform : ici
Important : J'utilise deux datastores (NAS & DATASTORE) à la place de local et local-lvm.
Prérequis
Création du rôle
Proxmox permet de créer des rôles personnalisés avec des permissions spécifiques. Utilisez la commande suivante, en vous connectant en ssh auparavant, pour créer un nouveau rôle (par exemple, TerraformRole) avec des permissions adaptées à Terraform :
pveum role add TerraformProv -privs "Datastore.Allocate Datastore.AllocateSpace Datastore.Audit Pool.Allocate Sys.Audit Sys.Console Sys.Modify VM.Allocate VM.Audit VM.Clone VM.Config.CDROM VM.Config.Cloudinit VM.Config.CPU VM.Config.Disk VM.Config.HWType VM.Config.Memory VM.Config.Network VM.Config.Options VM.Console VM.Migrate VM.Monitor VM.PowerMgmt SDN.Use"
Cette commande crée un rôle TerraformRole avec des privilèges adaptés pour gérer les machines virtuelles.
Création de l'utilisateur
Créez un utilisateur spécifique pour Terraform. Par exemple, pour créer un utilisateur terraform-prov
dans le domaine @pve
avec un mot de passe, utilisez :
pveum user add terraform-prov@pve --password password1234
Après avoir créé l’utilisateur, attribuez-lui le rôle créé précédemment. Vous pouvez le faire pour l’ensemble du datacenter :
pveum aclmod / -user terraform-prov@pve -role TerraformProv
Cette commande assigne le rôle TerraformRole à terraform-prov@pve
pour toutes les ressources du datacenter.
Génération d'un token
Pour une intégration sécurisée et efficace entre Terraform et Proxmox, l’utilisation d’un token API est recommandée. Cela permet à Terraform de se connecter et d’interagir avec Proxmox sans nécessiter des informations d’identification utilisateur classiques. Voici la procédure pour créer un token API dans Proxmox et le configurer dans Terraform.
pveum user token add terraform-prov@pve terraform -expire 0 -privsep 0 -comment "Terraform token"
Création des ressources
L'arborescence cible :
./
├── credentials.auto-sample.tfvars
├── credentials.auto.tfvars
├── main.tf
├── modules
│ ├── debian-bookworm
│ │ ├── main.tf
│ │ ├── outputs.tf
│ │ ├── providers.tf
│ │ └── variables.tf
│ └── debian-bookworm-datastore
│ ├── main.tf
│ ├── outputs.tf
│ ├── providers.tf
│ └── variables.tf
├── providers.tf
├── README.md
├── terraform.tfstate
├── terraform.tfstate.backup
└── variables.tf
Notre module sera situé dans le répertoire : /modules/debian-bookworm/
. Il sera composé des fichiers suivants :
main.tf
: Ressources principalesvariables.tf
: Variables d’entréeoutputs.tf
: Valeurs de sortieproviders.tf
: Déclaration du provider Proxmox
Création de templates
Je t'invite à lire l'article suivant : cloud-init
Déclaration du Provider
Dans le fichier providers.tf
terraform {
required_providers {
proxmox = {
source = "bpg/proxmox"
version = "0.76.0"
}
}
}
provider "proxmox" {
endpoint = var.endpoint
api_token = var.api_token
username = var.username
password = var.password
insecure = true
ssh {
agent = true
username = "root"
}
}
Dans le fichier credentials.auto.tfvars
endpoint = "https://PROMXO-IP:8006/"
username = "terraform-prov@pve"
password = "adminuser"
api_token = "something"
Dans le fichier variables.tf
variable "endpoint" {
description = "URL vers Proxmox"
type = string
}
variable "username" {
description = "Login compte technique"
type = string
}
variable "password" {
description = "Password compte technique"
type = string
}
variable "api_token" {
description = "Token to connect Proxmox API"
type = string
}
Déclaration de notre premier module
Créer le fichier suivant /modules/debian-bookworm/main.tf
.
Le fichier main.tf
contient deux ressources :
- Téléchargement de l’image Debian Bookworm au format qcow2 depuis le dépôt officiel.
- Création de la VM à partir de cette image avec toutes les options configurables (CPU, mémoire, réseau, disques, etc.).
resource "proxmox_virtual_environment_download_file" "latest_debian_12_bookworm_qcow2_img" {
content_type = "iso"
datastore_id = var.datastore_id
file_name = "debian-12-generic-amd64.qcow2.img"
node_name = var.node_name
url = "https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-generic-amd64.qcow2"
}
resource "proxmox_virtual_environment_vm" "debian_template" {
description = "Managed by Terraform"
vm_id = var.vm_id
name = var.vm_name
node_name = var.node_name
tags = var.tags
on_boot = false
template = false
started = true
cpu {
cores = var.cpu_cores
type = var.cpu_type
}
agent {
enabled = true
timeout = "2m"
}
startup {
order = "3"
up_delay = "60"
down_delay = "60"
}
memory {
dedicated = var.memory
floating = var.memory
}
disk {
interface = "scsi0"
datastore_id = var.datastore_id
file_id = proxmox_virtual_environment_download_file.latest_debian_12_bookworm_qcow2_img.id
size = var.disk_size
discard = "on"
ssd = false
}
initialization {
datastore_id = var.datastore_id
ip_config {
ipv4 {
address = var.ipv4_address
gateway = var.gateway
}
}
dns {
servers = var.dns_servers
}
user_account {
username = var.username
keys = [file(var.ssh_public_key_path)]
}
}
network_device {
bridge = var.network_bridge
model = "virtio"
firewall = false
enabled = true
vlan_id = var.network_vlan_id
}
operating_system {
type = "l26"
}
tpm_state {
datastore_id = var.datastore_id
version = "v2.0"
}
serial_device {
device = "socket"
}
}
La VM inclut :
- Un agent QEMU activé pour la communication avec Proxmox
- Une configuration réseau statique
- Une clé SSH injectée pour l’accès sans mot de passe
- Un support TPM 2.0 pour la sécurité
- Des délais de démarrage personnalisés
- Une interface réseau
virtio
avec support VLAN
Créer le fichier suivant /modules/debian-bookworm/variables.tf
.
Ce fichier rend le module flexible et personnalisable. Vous pouvez définir :
- L’ID et le nom de la VM
- Le type et nombre de CPU
- La mémoire et la taille du disque
- Les paramètres réseau (IP, passerelle, DNS, bridge, VLAN)
- Le nom du noeud Proxmox
- Le chemin vers la clé SSH publique
variable "vm_id" {
description = "ID unique de la VM dans le cluster Proxmox"
type = number
}
variable "vm_name" {
description = "Nom de la VM"
type = string
default = "debian12-template"
}
variable "node_name" {
description = "Nom du noeud Proxmox"
type = string
}
variable "tags" {
description = "Tags de la VM"
type = list(string)
default = ["terraform", "debian12", "template"]
}
variable "cpu_cores" {
description = "Nombre de coeurs CPU"
type = number
default = 2
}
variable "cpu_type" {
description = "Type de CPU"
type = string
default = "x86-64-v2-AES"
}
variable "memory" {
description = "Mémoire en Mo"
type = number
default = 1024
}
variable "disk_size" {
description = "Taille du disque en Go"
type = number
default = 10
}
variable "datastore_id" {
description = "ID du datastore pour le disque"
type = string
}
variable "ipv4_address" {
description = "Adresse IPv4 statique"
type = string
}
variable "gateway" {
description = "Passerelle par défaut"
type = string
}
variable "dns_servers" {
description = "Liste des serveurs DNS"
type = list(string)
default = ["8.8.1.1", "8.8.8.8"]
}
variable "username" {
description = "Nom d'utilisateur pour la VM"
type = string
default = "cloud"
}
variable "ssh_public_key_path" {
description = "Chemin du fichier contenant la clé publique SSH"
type = string
}
variable "network_bridge" {
description = "Nom du pont réseau"
type = string
default = "vmbr1"
}
variable "network_vlan_id" {
description = "Tag VLAN à appliquer à la carte réseau (optionnel)"
type = number
default = 20
}
Créer le fichier suivant /modules/debian-bookworm/outputs.tf
Après l’application du module, vous pouvez récupérer facilement certaines informations utiles :
output "vm_ip" {
value = proxmox_virtual_environment_vm.debian_template.initialization[0].ip_config[0].ipv4[0].address
description = "Adresse IP de la VM Debian"
}
output "ssh_public_key_path" {
value = var.ssh_public_key_path
}
Cela permet par exemple d’enchaîner automatiquement avec une configuration Ansible ou un test de connectivité.
Créer le fichier suivant /modules/debian-bookworm/providers.tf
.
Nous déclarons ici le provider Proxmox requis :
terraform {
required_providers {
proxmox = {
source = "bpg/proxmox"
version = "0.76.0"
}
}
}
Le provider bpg/proxmox
est un fork communautaire largement utilisé.
Déclaration de notre second module
La seule différence est qu'on copie l'image pour créer la VM. Ça évite de télécharger pour chaque VM depuis le WEB. Dans le main.tf
du module au niveau de :
disk {
interface = "scsi0"
datastore_id = var.datastore_id
file_id = proxmox_virtual_environment_download_file.latest_debian_12_bookworm_qcow2_img.id
size = var.disk_size
discard = "on"
ssd = false
}
Devient :
disk {
datastore_id = var.datastore_id
file_id = "NAS:iso/debian-12-generic-amd64.img"
interface = "virtio0"
iothread = true
discard = "on"
size = var.disk_size
}
NAS: À remplacer par le nom du datastore qui contient l'image.
Exemple d’utilisation
Vous pouvez intégrer ce module dans un projet Terraform plus large comme suit :
module "debian_bookworm" {
source = "./modules/debian-bookworm"
vm_id = 101
node_name = "pve1"
datastore_id = "local-lvm"
ipv4_address = "192.168.1.101/24"
gateway = "192.168.1.1"
ssh_public_key_path = "~/.ssh/id_rsa.pub"
}
Uniquement à titre d'exemple.
Exemple d’utilisation avec loop
locals {
debian_vms = {
debian-vm-01 = { vm_id = 501, ip = "172.16.20.40/24" }
debian-vm-02 = { vm_id = 502, ip = "172.16.20.41/24" }
debian-vm-03 = { vm_id = 503, ip = "172.16.20.42/24" }
debian-vm-04 = { vm_id = 504, ip = "172.16.20.43/24" }
debian-vm-05 = { vm_id = 505, ip = "172.16.20.44/24" }
debian-vm-06 = { vm_id = 506, ip = "172.16.20.45/24" }
}
}
module "debian_vm" {
for_each = local.debian_vms
source = "./modules/debian-bookworm-datastore"
vm_id = each.value.vm_id
vm_name = each.key
node_name = "pve"
datastore_id = "DATASTORE"
disk_size = 20
ipv4_address = each.value.ip
gateway = "172.16.20.254"
ssh_public_key_path = "~/.ssh/id_rsa.pub"
}
Définit un ensemble de VM Debian à déployer.
Chaque entrée correspond à une VM avec :
- vm_id : un identifiant unique pour la VM.
- ip : l’adresse IP avec masque CIDR.
Paramètres du module :
- source : chemin vers le module Terraform local.
- for_each : instancie une ressource pour chaque élément défini dans local.debian_vms.
Variables passées au module :
- vm_id : identifiant de la VM.
- vm_name : nom de la VM, basé sur la clé de la map.
- node_name : nom du noeud Proxmox cible.
- datastore_id : identifiant du stockage cible.
- disk_size : taille du disque de la VM en Go.
- ipv4_address : adresse IP attribuée à la VM.
- gateway : passerelle réseau commune à toutes les VMs.
- ssh_public_key_path : chemin vers la clé SSH publique à injecter.