knife-proxmox-ve
A knife plugin (Chef Infra / CINC
Workstation) that creates VMs on Proxmox VE by cloning a pre-configured template,
configuring it, starting it, and waiting for it to boot. Use vm create to provision a
VM, or vm bootstrap to provision it and automatically bootstrap it with Chef/CINC
in one command.
The plugin only ever clones a prepared template; it never builds an image. All VM parameters are optional: anything you don't pass keeps the value baked into the template.
Requirements
- Chef Workstation / CINC Workstation 18+ (the plugin depends on the
knifegem ≥ 18). - A Proxmox VE API token (see Authentication).
- A template that already has a cloud-init drive (e.g.
ide2=<storage>:cloudinit) and the QEMU guest agent enabled. Cloud-init settings are silently ignored by Proxmox if the template has no cloud-init drive — the plugin fails fast when it detects this.
Installation
chef gem install knife-proxmox-ve # Chef Workstation
cinc gem install knife-proxmox-ve # CINC Workstation
knife discovers the commands automatically (no registration step). For development
from a checkout, run via cinc exec bundle exec knife proxmox ....
Configuration
Proxmox clusters are defined in ~/.cinc/config.rb (or ~/.chef/config.rb) under
knife[:proxmox_clusters]. Each key is a cluster name selectable with
--proxmox-cluster.
knife[:proxmox_clusters] = {
"production" => {
host: "pve1.example.com", # required
port: 8006, # optional (default 8006)
token_id: "knife@pve!automation", # required; the USER@REALM!TOKENID part
token_secret: nil, # optional in-file; prefer the ENV override below
verify_ssl: true, # optional (default true); false warns every run
# Optional per-cluster provisioning defaults (any CLI flag overrides these):
storage: "local-lvm",
bridge: "vmbr0",
ciuser: "ubuntu",
nameserver: "10.0.0.1",
searchdomain: "example.com",
target_node: nil,
},
}
# Cluster used when --proxmox-cluster is omitted:
knife[:proxmox_default_cluster] = "production"
Authentication
The plugin authenticates with a Proxmox API token (Authorization: PVEAPIToken=...).
The token secret is resolved with this precedence (highest first):
KNIFE_PROXMOX_TOKEN_SECRET— global override for whichever cluster is selectedKNIFE_PROXMOX_TOKEN_SECRET_<CLUSTER>— per cluster (key upcased, non-alphanumerics →_)token_secret:in the cluster hash
Prefer an environment variable so the secret never sits in a file. If you do store
token_secret: in config.rb, chmod 600 ~/.cinc/config.rb — anyone who can read
the file can read the token.
export KNIFE_PROXMOX_TOKEN_SECRET="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
Proxmox API tokens default to privilege separation: a fresh token has no rights until you grant ACLs to the token itself. A first-run
HTTP 403almost always means this. The token needs:VM.Clone,VM.Config.Disk,VM.Config.Network,VM.Config.Memory,VM.Config.CPU,VM.Config.Cloudinit,VM.Config.Options,VM.PowerMgmt,VM.Audit,VM.Monitor(guest-agent calls; PVE 8 and earlier),VM.Allocate, andDatastore.AllocateSpaceon the target storage (full clones).
TLS
HTTPS to :8006 is verified by default. Set verify_ssl: false per cluster only for
self-signed lab hosts — the plugin warns on every command when verification is off,
because the connection (carrying the token) is then MITM-exploitable.
Commands
knife proxmox vm create NAME
Clone a template → configure → start. Stops there — no Chef bootstrap runs. Use it to
stand up a VM you do not (yet) want to manage with Chef. NAME (the new VM's name) and
--template are the only required inputs; every other parameter falls back to the template's
value.
Because it never connects to the VM, vm create does not wait for SSH and does not
fail if the guest has no network — its job is done once the VM is cloned, configured and
started. The IP is reported best-effort: known immediately for a static --ip, or polled
from the guest agent (bounded by --boot-timeout) for dhcp; if none is found it warns and
still succeeds, omitting the IP from the summary.
cloud-init auth (--ssh-public-key / --cipassword) is optional here: a template with
a baked-in login is a valid result. Pass a key/password if you want one planted on the guest.
knife proxmox vm create web-01 \
--proxmox-cluster production \
--template ubuntu-2404-template \
--cores 2 --memory 4096 \
--bridge vmbr0 --vlan 100 \
--ip 10.0.10.50/24 --gateway 10.0.10.1 \
--nameserver 10.0.0.1 --searchdomain example.com \
--ciuser ubuntu --ssh-public-key ~/.ssh/id_ed25519.pub
knife proxmox vm bootstrap NAME
Everything vm create does, then bootstraps the node with Chef/CINC: clone → configure →
start → wait for SSH → knife bootstrap. Because it must connect, an SSH public key or a
cloud-init password is required. NAME and --template are otherwise the only required
inputs; every other parameter falls back to the template's value.
knife proxmox vm bootstrap web-01 \
--proxmox-cluster production \
--template ubuntu-2404-template \
--cores 2 --memory 4096 \
--bridge vmbr0 --vlan 100 \
--ip 10.0.10.50/24 --gateway 10.0.10.1 \
--nameserver 10.0.0.1 --searchdomain example.com \
--ciuser ubuntu --ssh-public-key ~/.ssh/id_ed25519.pub \
--node web-01 --run-list 'role[base]'
Both commands share the provisioning flags below.
| Flag | Meaning |
|---|---|
--template NAME_OR_VMID |
Source template (name or numeric VMID). Required. |
--proxmox-cluster NAME |
Cluster key from knife[:proxmox_clusters]. |
--target-node NODE |
Node to clone onto (requires shared storage for a cross-node clone). |
--newid VMID |
Use a specific VMID instead of the cluster's next free id. |
--linked-clone |
Linked clone instead of the default full clone (--storage is then ignored). |
--storage NAME / --pool NAME |
Target storage / resource pool. |
--cores N / --sockets N / --memory MiB |
CPU / RAM. |
--bridge vmbrN / --vlan TAG |
net0 bridge and VLAN tag (needs a VLAN-aware bridge). |
| `--ip CIDR\ | dhcp/--gateway IP/--prefix N` |
--nameserver IP / --searchdomain DOMAIN |
cloud-init DNS. |
--ciuser USER |
cloud-init user. |
--ssh-public-key PATH |
Public key injected via cloud-init (preferred auth). |
--cipassword |
Prompt (no echo) for a cloud-init password; or set KNIFE_PROXMOX_CIPASSWORD. |
--clone-timeout SEC / --boot-timeout SEC |
Clone and boot/SSH wait limits (default 600 / 300). |
For vm bootstrap, the standard knife bootstrap options are inherited: -N/--node-name,
-r/--run-list, -E/--environment, --connection-user, --ssh-identity-file,
--bootstrap-version, --ssh-verify-host-key (defaults to :accept_new for the
freshly-created host), --yes, etc. They do not apply to vm create, which never bootstraps.
Clone mode. The clone is a full clone by default. Pass --linked-clone for a linked
clone (faster, thin) — it requires a storage that supports it, and any --storage (CLI or
cluster default) is then dropped, because Proxmox rejects a target storage on a linked clone.
Bootstrap product (CINC by default). A vm bootstrap'd VM is bootstrapped with CINC out of the
box — the install is pinned to the CINC omnitruck regardless of whether you invoke a CINC- or
Chef-branded knife, which also avoids Chef's commercial license gate. To bootstrap with Chef
Infra Client instead, opt in via config.rb:
knife[:proxmox_bootstrap_product] = "chef" # or "chef-ice"; standard Chef licensing then applies
An explicit --bootstrap-product, --bootstrap-url or --bootstrap-install-command always wins.
cloud-init wait. Before installing the client, vm bootstrap waits for cloud-init to finish
(cloud-init status --wait) so the omnibus install never races cloud-init for the apt/dpkg lock
on the freshly booted VM. This makes vm bootstrap deterministic in a single run; override it
with --bootstrap-preinstall-command (it is skipped on images without cloud-init).
SSH authentication. Injecting a public key (--ssh-public-key) is the preferred path — for
vm bootstrap the matching private key is then used for the bootstrap connection. A cloud-init
password is supported as a fallback via KNIFE_PROXMOX_CIPASSWORD or the --cipassword no-echo
prompt (never as a literal command-line argument). A credential is required for vm bootstrap
(it must connect) and optional for vm create. For --ip dhcp the guest must run the QEMU
guest agent so the leased address can be discovered.
knife proxmox cluster list
Lists the configured clusters with host, token id, verify_ssl, and whether a token
secret resolves (the secret value is never printed). Marks the default cluster with *.
Makes no API call.
knife proxmox template list [--proxmox-cluster NAME]
Lists the qemu templates on the selected cluster (name, VMID, node, disk, memory).
knife proxmox vm list [--proxmox-cluster NAME] [--node NODE]
Lists the cluster's qemu VMs (name, VMID, node, status, memory, uptime). --node filters
client-side.
All read commands honour --format json|yaml for scripting.
Development
Tests run under cinc-workstation, so the suite exercises the same knife build the
gem ships on (a cinc-internal build that differs from the rubygems release — e.g.
Bootstrap#fetch_license was removed in it). No bundler is involved.
cinc exec rake # chefstyle + rspec (the default task)
cinc exec rake spec # rspec only
cinc exec rake style # chefstyle only
Do not use
bundle execagainst cinc:Gemfile.lockpins the public knife, which the cinc gem repo does not carry, socinc exec bundle execfails. TheGemfile/Gemfile.lockexist only forgem build/release (cinc exec rake build).
License
Apache-2.0.