API and tokens (official)
Every GUI action has an API counterpart. Token: user + token ID, ACL like a human, with 2FA on the human account and none on the bot (TFA and Automated Access in PBS/PVE). Do not put the root password in a pipeline. Keep ACL paths narrow: one pool, one storage, no Sys.Modify on the whole datacenter.
API docs live in the GUI (Datacenter → Permissions → API Tokens) and in pveum. That is the layer Terraform and Ansible sit on — not the other way around.
Terraform: bpg/proxmox
In the registry: bpg/proxmox (community). Older Telmate/proxmox still shows up in forks — new projects take bpg. It is not an official Proxmox GmbH provider. Keep state off the cluster. Resources: VMs, CTs, network, storage mapping — the scope is the provider version, not “everything the GUI can do”.
vSphere has official vmware/vsphere. PVE has no Proxmox-stamped equivalent. That belongs in the IaC project risks, not under the rug.
In practice we pin the provider version (the number in required_providers), review the changelog before upgrading, and do not mix Telmate with bpg in one state file. The PVE API is versioned; the community provider trails it. That is why cluster day zero and Ceph stay in a runbook, and Terraform takes guests, tags, bridges and VNets the provider actually supports.
Ansible: community.general
Modules community.general.proxmox, proxmox_kvm, proxmox_pct, proxmox_template call the same API. The collection is community (Ansible / contributors), not “Ansible certified Proxmox”. Fine for idempotent CT/VM create, snapshots, start/stop. It does not replace terraform state across twenty SDN layers. In practice Ansible calls the API idempotently for CT/VM, and Terraform holds the network and tags that belong in git. Two tools on the same object with no ownership split drift: GUI, Ansible and Terraform overwrite each other.
Cloud-init and images
PVE supports cloud-init on VMs (vendor/meta/network). Terraform and Ansible pass user-data. CT templates from pveam, cloud images from Linux vendors. Windows: cloudbase-init or sysprep in your own gold image — we do not promise “cloud-init like Debian”.
What not to automate blindly
- Standing up Corosync and QDevice “from Terraform on first boot” without a network runbook — quorum is not a cloud resource.
- Deleting a PBS datastore with the same token that also creates backups (see PBS and ransomware).
- VMs/CTs, cloud-init, tags, affinity, SDN VNets — yes, with PR review and state in S3/Git.
In practice: API token + Terraform for guests and network, Ansible for packages inside VMs, GUI clicks left for Ceph/OSDs and cluster day zero.
Tokens: narrow ACLs
API docs and pveum: a token is user + token ID, the same ACL paths as a human. 2FA on the operator account, no 2FA on the automaton (TFA and Automated Access). Root passwords stay out of CI. A separate token for Terraform (VM/CT/network), a separate one for Ansible (if it calls PVE at all), neither gets Datastore.Modify on PBS nor Sys.Modify on the whole datacenter “just in case”.
Ansible modules community.general.proxmox, proxmox_kvm, proxmox_pct, proxmox_template call the same API. They are not “Ansible certified Proxmox”. They fit CT/VM, snapshots, start/stop — not twenty SDN layers as the source of truth.
State, SDN and day zero
Keep Terraform state off the cluster (S3/Git with a lock). The bpg provider does not cover “everything the GUI can do” — the scope depends on the version. Corosync, QDevice and Ceph OSDs stay on the day-zero runbook, not on apply at first boot without a quorum network. PBS: the backup token does not delete the datastore — see PBS and ransomware.
Cloud-init on VMs (vendor/meta/network) is in PVE; Windows is cloudbase-init or sysprep in your own image, not “cloud-init like Debian”. CT templates from pveam.
pvesh and the API explorer
Every GUI action has a REST path. pvesh is the CLI client for that API on the node (get/set/create/delete/ls). The GUI explorer (Documentation → API Viewer) shows the same paths Terraform calls. That is the vendor layer. The bpg provider and the Ansible collection sit on top and can lag a new PVE release — hence version pins and a changelog review before upgrade.
An API token with 2FA on the human account and none on the bot (TFA and Automated Access) is in the PVE/PBS docs. Privilege separation: the token inherits the user’s ACL, but you can narrow it. A separate token for Terraform, a separate one for PBS backup — neither holds both worlds.
In practice: cluster day zero, QDevice and Ceph OSDs stay in a runbook. Terraform takes guests and VNets the provider supports. Ansible — packages inside VMs. The GUI stays for incidents and for what the provider does not cover yet.
We’ll put IaC on Proxmox VE
Tokens, bpg/proxmox, Ansible and cloud-init — with an explicit note that the provider is community.
⚡ Free consultation → Proxmox implementation