Problema

En entornos de virtualización con Proxmox es frecuente crear plantillas de máquinas virtuales (VM) basadas en imágenes cloud‑ready y usar la unidad cloud‑init para provisionar usuarios, claves SSH y configuración de red. Cuando la VM arranca, el usuario definido con ciuser no aparece y la clave pública no permite el acceso por SSH. El agente de QEMU tampoco se registra, lo que impide inspeccionar la VM desde el host. El síntoma típico es un login local que muestra el usuario por defecto de la imagen (por ejemplo fedora) y una dirección IP asignada por DHCP, pero sin ningún rastro de la configuración de cloud‑init.

Este patrón ocurre en distintas distribuciones y versiones, y suele estar relacionado con la forma en que Proxmox crea la plantilla, el orden de arranque y la configuración de la unidad cloud‑init.

Causa

Los fallos de cloud‑init en Proxmox provienen de tres áreas principales:

  1. Unidad cloud‑init no detectada

    • La unidad ide2 o scsiX que contiene la semilla cloud‑init no está marcada como media=cdrom o no se incluye en la lista de discos de arranque.
    • En plantillas con UEFI, el disco EFI (efidisk0) a veces sobrescribe la detección de la unidad de datos, impidiendo que el kernel encuentre /dev/sr0.
  2. Metadata incompleta o mal referenciada

    • Los parámetros ciuser y sshkeys se pasan a la VM mediante la API de Proxmox, pero si la plantilla ya contiene un archivo user-data vacío o una configuración previa, cloud‑init prioriza esa información y descarta los valores enviados.
    • El archivo meta-data debe contener al menos una referencia a la instancia (instance-id) para que cloud‑init se ejecute.
  3. Orden de arranque incorrecto

    • Cuando el disco que contiene la imagen del sistema (scsi0) se coloca antes que la unidad cloud‑init en la cadena de arranque, el firmware arranca directamente sin pasar por el proceso de inicialización de la semilla.
    • En sistemas UEFI, la variable bootorder debe incluir la unidad cloudinit antes que el disco raíz.

En la práctica, la combinación de una plantilla sin cloudinit habilitado y un arranque que omite la semilla es la causa más frecuente.

Solución

La solución se divide en tres pasos: preparar la plantilla, validar la unidad cloud‑init y clonar la VM con los parámetros correctos.

1. Crear la plantilla con la unidad cloud‑init preparada

# 1.1 Crear VM vacía (ID 9000)
qm create 9000 \
  --name fedora-cloud-template \
  --ostype l26 \
  --memory 4096 \
  --cores 4 \
  --cpu host \
  --scsihw virtio-scsi-single \
  --bios ovmf \
  --agent enabled=1 \
  --serial0 socket \
  --vga serial0 \
  --onboot 0

# 1.2 Importar la imagen como disco SCSI0
qm importdisk 9000 /tmp/fedora-cloud-base-uefi-uki.qcow2 local-lvm --target-disk scsi0

# 1.3 Añadir disco EFI (necesario para arranque UEFI)
qm set 9000 --efidisk0 local-lvm:1,efitype=4m,pre-enrolled-keys=1

# 1.4 Crear la unidad cloud‑init como IDE2 (media=cdrom)
qm set 9000 --ide2 local-lvm:cloudinit

# 1.5 Forzar que la unidad cloud‑init sea la primera en el orden de arranque
qm set 9000 --boot order=ide2;scsi0

# 1.6 Convertir a plantilla
qm template 9000

Puntos críticos:

  • La unidad ide2 se crea con el tipo cloudinit; Proxmox la formatea automáticamente como ISO de semilla.
  • El parámetro order=ide2;scsi0 garantiza que el firmware lea la semilla antes de montar el disco raíz.
  • No se incluye --netX ni --ipconfig en la plantilla; esos valores se especifican al clonar.

2. Clonar la VM y pasar los datos de cloud‑init

# 2.1 Clonar la plantilla (ID 101)
qm clone 9000 101 --name fedora-smoke-test --full 1 --storage local-lvm

# 2.2 Configurar la consola (opcional, pero útil para depuración)
qm set 101 --vga std

# 2.3 Conectar a la red (bridge sin VLAN)
qm set 101 --net0 virtio,bridge=vmbr0

# 2.4 Definir la configuración de cloud‑init
qm set 101 \
  --ipconfig0 ip=dhcp \
  --ciuser lizzy \
  --sshkeys /root/.ssh/homelab.pub

# 2.5 Asegurarse de que el disco EFI sigue presente (heredado) y que el orden de arranque es correcto
qm set 101 --boot order=ide2;scsi0

# 2.6 (Opcional) Expandir el disco raíz
qm disk resize 101 scsi0 +20G

Aspectos a observar:

  • --ciuser y --sshkeys se aplican a la unidad cloud‑init recién creada; no es necesario editar archivos user-data manualmente.
  • --ipconfig0 ip=dhcp permite que la VM obtenga una dirección sin interferir con la generación de la semilla.
  • Mantener el mismo orden de arranque que en la plantilla evita que el firmware ignore la semilla.

3. Verificar que cloud‑init se ejecutó

  1. Iniciar la VM y observar la consola. Los primeros segundos deben mostrar algo como cloud-init[...]: Cloud-init v... y luego cloud-init[...]: Finished.
  2. Después del arranque, ejecutar dentro de la VM (por consola) id lizzy para confirmar que el usuario existe.
  3. Desde el host, usar qm guest exec 101 -- cat /var/lib/cloud/instance/boot-finished para validar que el proceso finalizó.
  4. Probar el acceso SSH con la clave privada correspondiente: ssh lizzy@<IP>.

Si alguno de los pasos falla, revisar los logs de cloud‑init en la VM (/var/log/cloud-init.log y /var/log/cloud-init-output.log) y confirmar que la unidad ide2 está montada como /dev/sr0.

Cuándo aplicar esta solución

Esta guía es útil cuando:

  • Se usan plantillas basadas en imágenes cloud‑ready (Fedora, Ubuntu, CentOS, etc.) en Proxmox con UEFI.
  • El usuario ciuser no aparece y la clave SSH no funciona después del primer arranque.
  • El agente QEMU no se registra y los comandos qm guest exec devuelven errores de permiso.

No es necesario aplicar este procedimiento si:

  • La VM se crea sin usar cloud‑init (por ejemplo, instalando manualmente el sistema operativo).
  • Se utiliza un método de aprovisionamiento externo (Ansible, Terraform) que no depende de la semilla ISO.

Código

# Plantilla completa (pasos 1‑6)
qm create 9000 --name fedora-cloud-template --ostype l26 --memory 4096 --cores 4 \
  --cpu host --scsihw virtio-scsi-single --bios ovmf --agent enabled=1 \
  --serial0 socket --vga serial0 --onboot 0

qm importdisk 9000 /tmp/fedora-cloud-base-uefi-uki.qcow2 local-lvm --target-disk scsi0
qm set 9000 --efidisk0 local-lvm:1,efitype=4m,pre-enrolled-keys=1
qm set 9000 --ide2 local-lvm:cloudinit
qm set 9000 --boot order=ide2;scsi0
qm template 9000

# Clonado y configuración (pasos 2‑6)
qm clone 9000 101 --name fedora-smoke-test --full 1 --storage local-lvm
qm set 101 --vga std
qm set 101 --net0 virtio,bridge=vmbr0
qm set 101 --ipconfig0 ip=dhcp --ciuser lizzy --sshkeys /root/.ssh/homelab.pub
qm set 101 --boot order=ide2;scsi0
qm disk resize 101 scsi0 +20G

Verificación

  1. Consola: qm monitor 101 → observar mensajes cloud-init.
  2. Usuario: qm guest exec 101 -- id lizzy → salida uid=1000(lizzy).
  3. SSH: ssh lizzy@$(qm guest exec 101 -- ip -4 -brief addr show dev eth0 | awk '{print $3}' | cut -d/ -f1) → acceso sin contraseña.
  4. Agente: qm agent 101 ping → respuesta pong.

Si alguno de los pasos falla, revisar el archivo de semilla con qm cloudinit dump 101 y comparar con la documentación de cloud‑init.

Notas adicionales

  • En distribuciones que usan cloud-init versión 22 o superior, el archivo user-data se genera automáticamente; no es necesario crear uno manualmente.
  • Cuando se trabaja con Secure Boot, asegúrese de que la clave de firma del kernel esté incluida en el disco EFI; de lo contrario el arranque puede detenerse antes de que cloud‑init tenga oportunidad de ejecutarse.
  • Si la VM necesita una dirección IP estática, cambie --ipconfig0 ip=dhcp por --ipconfig0 ip=192.168.1.100/24,gw=192.168.1.1 y añada --nameserver 8.8.8.8.
  • Para depurar problemas de detección de la unidad ide2, ejecute qm cloudinit dump <VMID> y verifique que el campo disk apunte a ide2.

Con estos ajustes, la mayoría de los fallos de cloud‑init en Proxmox desaparecen y la provisión automática de usuarios y claves SSH vuelve a ser fiable.