Problema
En muchas infraestructuras basadas en VMware, los paquetes open‑vm‑tools que llegan desde los repositorios oficiales de la distribución llegan con varios meses de retraso respecto al código fuente de VMware. Ese desfase implica:
- Falta de correcciones de kernel y controladores que aparecen en versiones upstream.
- Ausencia de mejoras en la gestión de memoria (balloon) y en la sincronización de tiempo.
- Vulnerabilidades CVE que permanecen sin parchear hasta que el mantenedor de la distro actualiza el paquete.
El síntoma típico es que, tras una actualización del hipervisor, los invitados siguen usando versiones antiguas de vmtoolsd, generando logs de incompatibilidad o, peor, exponiéndose a vulnerabilidades conocidas. La solución “instalar lo que trae la distro” ya no es suficiente en entornos donde la seguridad y el rendimiento son críticos.
Causa
- Política de congelación de paquetes – Distribuciones como Ubuntu LTS o RHEL mantienen versiones estables durante años y sólo actualizan
open‑vm‑toolscuando la nueva versión no rompe dependencias. - Cadena de compilación interna – Los paquetes oficiales se generan en entornos controlados que pueden no incluir los últimos parches de seguridad o los flags de compilación óptimos para hipervisores modernos.
- Falta de automatización – Cada administrador que necesita la última versión termina compilando manualmente en su máquina de trabajo, lo que contamina el host y dificulta la reproducibilidad.
- Diversidad de distros – Un mismo data‑center puede mezclar Debian, CentOS y openSUSE; mantener scripts ad‑hoc para cada una genera errores de consistencia.
Solución
Una estrategia reutilizable combina contenedores Docker para la compilación y Ansible para la orquestación de despliegue. El flujo es:
- Construir paquetes en un contenedor aislado. Un Dockerfile parametrizable descarga la última tarball de
open‑vm‑toolsdesde el repositorio oficial, instala las dependencias necesarias y genera tanto.debcomo.rpm. El contenedor nunca toca el host, por lo que la máquina de control permanece limpia. - Almacenar los artefactos en un repositorio interno (por ejemplo, un bucket S3 o un Nexus) o simplemente copiarlos a un directorio compartido accesible por Ansible.
- Desplegar con un rol Ansible que:
- Detecta la familia y versión de la distro objetivo.
- Elimina paquetes
open‑vm‑toolsinstalados desde los repositorios de la distro para evitar conflictos. - Instala el paquete generado (
dpkg -iorpm -Uvh). - Asegura que el servicio
vmtoolsdestá activo y habilitado. - Verifica la versión instalada contra la versión upstream esperada.
Este enfoque es extensible: basta con añadir una nueva variante de Dockerfile para Alpine o con una tarea Ansible para manejar zypper en openSUSE. La reutilización del mismo rol reduce la deuda técnica y garantiza que todos los nodos reciben exactamente el mismo binario.
Alternativas prácticas
- Uso de Buildah/Podman en lugar de Docker cuando la política de la empresa prohíbe Docker daemon.
- GitLab CI/CD o GitHub Actions para disparar la compilación automáticamente cada vez que upstream publica una nueva versión (webhook o polling).
- Distribución mediante paquetes locales (
aptly,createrepo) para evitar dependencias externas en entornos air‑gapped.
Cuándo aplicar esta solución
Se recomienda cuando:
- Los invitados corren versiones de
open‑vm‑toolsque están 2 o más versiones por detrás del upstream. - Se necesita aplicar rápidamente parches de CVE críticos sin esperar al ciclo de actualización de la distro.
- La infraestructura incluye al menos dos familias de paquetes (DEB y RPM) y se busca una única fuente de verdad.
- Existe un repositorio interno de artefactos o la capacidad de almacenar archivos binarios de forma segura.
No es necesario si:
- La distro ya ofrece paquetes al día (p.ej., Fedora con actualizaciones semanales).
- El entorno es estático y no se requieren parches de seguridad frecuentes.
- No se dispone de un mecanismo de orquestación (Ansible, Puppet, etc.) y la escala es de menos de diez nodos, donde la compilación manual es aceptable.
Código
# Dockerfile genérico para compilar open-vm-tools
FROM ubuntu:22.04 AS builder
ARG OPENVMTOOLS_VERSION=latest
ARG PKGTYPE=deb # cambiar a rpm para RedHat based
RUN apt-get update && \
DEBIAN_FRONTEND=noninteractive apt-get install -y \
build-essential autoconf automake libtool pkg-config \
libglib2.0-dev libssl-dev libx11-dev libxext-dev \
libxinerama-dev libxrandr-dev libxss-dev libgtk-3-dev \
wget ca-certificates
# Descargar la última tarball (si no se especifica versión, usa la última)
RUN wget -O /tmp/open-vm-tools.tar.gz \
https://github.com/vmware/open-vm-tools/releases/download/${OPENVMTOOLS_VERSION}/open-vm-tools-${OPENVMTOOLS_VERSION}.tar.gz && \
tar -xzf /tmp/open-vm-tools.tar.gz -C /opt && \
cd /opt/open-vm-tools-${OPENVMTOOLS_VERSION} && \
./configure --disable-static && \
make -j$(nproc)
# Empaquetado
FROM ubuntu:22.04 AS packager
ARG PKGTYPE=deb
COPY --from=builder /opt/open-vm-tools-${OPENVMTOOLS_VERSION} /src
RUN apt-get update && \
DEBIAN_FRONTEND=noninteractive apt-get install -y \
fakeroot dpkg-dev rpm
WORKDIR /src
RUN if [ "$PKGTYPE" = "deb" ]; then \
make DESTDIR=/package install && \
dpkg-deb --build /package open-vm-tools_${OPENVMTOOLS_VERSION}_all.deb; \
else \
make DESTDIR=/package install && \
fpm -s dir -t rpm -n open-vm-tools -v ${OPENVMTOOLS_VERSION} -C /package .; \
fi
# Resultado en /output
FROM scratch AS final
COPY --from=packager /src/*.deb /output/
COPY --from=packager /src/*.rpm /output/
# tasks/main.yml – rol Ansible para despliegue
- name: Detectar gestor de paquetes
ansible.builtin.package_facts:
- name: Eliminar paquete distro (si existe)
ansible.builtin.package:
name: open-vm-tools
state: absent
when: "'open-vm-tools' in ansible_facts.packages"
- name: Copiar paquete compilado al host
ansible.builtin.copy:
src: "{{ local_pkg_path }}/{{ pkg_file }}"
dest: /tmp/{{ pkg_file }}
mode: '0644'
- name: Instalar paquete DEB
ansible.builtin.apt:
deb: /tmp/{{ pkg_file }}
when: ansible_facts.os_family == 'Debian'
- name: Instalar paquete RPM
ansible.builtin.yum:
name: /tmp/{{ pkg_file }}
state: present
when: ansible_facts.os_family == 'RedHat'
- name: Asegurar servicio vmtoolsd activo
ansible.builtin.service:
name: vmtoolsd
state: started
enabled: true
Verificación
- Ejecutar
vmtoolsd --versionen el nodo y comparar con la versión que se compiló ({{ OPENVMTOOLS_VERSION }}). - Revisar el log de
systemd(journalctl -u vmtoolsd -b) para asegurarse de que no aparecen errores de carga de módulos. - En un host con vulnerabilidad conocida (por ejemplo CVE‑2023‑XXXXX), validar que la salida de
open-vm-tools --cve-check(si el binario lo soporta) no lista la CVE. - Repetir la comprobación en al menos dos nodos de cada familia de distro para confirmar la consistencia del paquete.
Notas adicionales
- Cache de dependencias: montar un volumen en
/var/cache/apto/var/cache/yumdentro del contenedor reduce significativamente el tiempo de compilación en ejecuciones sucesivas. - Firmado de paquetes: si la política de la empresa exige firmas GPG, añadir
dpkg-sigorpm --addsignal bloque de empaquetado. - Manejo de kernel headers: en RHEL‑based sistemas, el paquete
kernel-develdebe coincidir con la versión del kernel en ejecución; de lo contrario la compilación falla por símbolos ausentes. - Actualizaciones automáticas: programar una pipeline CI que invoque el Docker build cada semana y, al detectar una nueva versión upstream, publique el paquete y ejecute el rol Ansible contra un inventario de pruebas antes de propagar a producción.