Puppet es una herramienta de gestión de configuración declarativa: describes en manifiestos cómo debe quedar cada servidor y un agente lo aplica periódicamente, corrigiendo cualquier desviación. En este tutorial instalarás un servidor Puppet y un agente en Ubuntu 24.04 usando OpenVox, la distribución de código abierto de Puppet mantenida por la comunidad Vox Pupuli, firmarás el certificado del agente y aplicarás un módulo propio con datos en Hiera.
Notadesde finales de 2024, Perforce ya no publica paquetes libres actualizados de Puppet para uso general. OpenVox es un fork compatible: mismos comandos (
puppet,puppetserver), mismas rutas (/etc/puppetlabs) y mismo lenguaje. Si tienes licencia de Puppet Core o Puppet Enterprise, los pasos a partir del paso 3 son equivalentes.
Requisitos previos
Necesitas:
- Dos servidores con Ubuntu 24.04 LTS, por ejemplo dos VPS de CubePath:
- Servidor Puppet: al menos 2 vCPU y 4 GB de RAM (Puppet Server corre sobre la JVM).
- Agente: cualquier tamaño.
- Un usuario no root con privilegios
sudoen ambos. - El puerto TCP 8140 del servidor accesible desde el agente.
Valores de ejemplo usados en la guía:
| Rol | FQDN | IP |
|---|---|---|
| Servidor | puppet.example.com | server_ip |
| Agente | web01.example.com | agent_ip |
Paso 1: Configurar nombres de host
Puppet identifica cada máquina por su certificado, que se emite para su nombre (certname). Ambos equipos deben resolver los nombres del otro. Si no tienes DNS interno, añade las dos entradas en /etc/hosts en los dos servidores:
sudo nano /etc/hosts
server_ip puppet.example.com puppet
agent_ip web01.example.com web01
Fija el hostname de cada máquina. En el servidor:
sudo hostnamectl set-hostname puppet.example.com
En el agente:
sudo hostnamectl set-hostname web01.example.com
Comprueba que cada uno resuelve al otro:
ping -c 1 puppet.example.com
Paso 2: Añadir el repositorio de OpenVox
Vox Pupuli publica un paquete que instala la definición del repositorio y su clave de firma. Hazlo en los dos servidores:
wget https://apt.voxpupuli.org/openvox8-release-ubuntu24.04.deb
sudo dpkg -i openvox8-release-ubuntu24.04.deb
sudo apt update
Comprueba que los paquetes están disponibles:
apt-cache policy openvox-server openvox-agent
La salida debe mostrar un candidato para cada paquete procedente de apt.voxpupuli.org. Si el nombre del archivo .deb cambia, consulta el listado en https://apt.voxpupuli.org/.
Paso 3: Instalar y arrancar Puppet Server
En el servidor, instala el paquete:
sudo apt install openvox-server
Por defecto Puppet Server reserva 2 GB de heap para la JVM. En un servidor de 4 GB está bien; si tienes menos memoria, ajústalo en /etc/default/puppetserver:
sudo nano /etc/default/puppetserver
JAVA_ARGS="-Xms1g -Xmx1g"
Indica al servidor su propio nombre en la configuración principal. Los binarios se instalan en /opt/puppetlabs/bin, que no está en el PATH de sudo, así que usa la ruta completa:
sudo /opt/puppetlabs/bin/puppet config set server puppet.example.com --section main
sudo /opt/puppetlabs/bin/puppet config set certname puppet.example.com --section main
Arranca el servicio. El primer arranque genera la autoridad de certificación (CA) y tarda uno o dos minutos:
sudo systemctl enable --now puppetserver
sudo systemctl status puppetserver
● puppetserver.service - puppetserver Service
Loaded: loaded (/usr/lib/systemd/system/puppetserver.service; enabled; preset: enabled)
Active: active (running) since ...
Permite el puerto 8140 solo desde el agente:
sudo ufw allow from agent_ip to any port 8140 proto tcp
Paso 4: Instalar el agente y solicitar el certificado
En el agente, instala el paquete:
sudo apt install openvox-agent
Apunta el agente al servidor:
sudo /opt/puppetlabs/bin/puppet config set server puppet.example.com --section main
Lanza una primera ejecución manual. El agente genera su par de claves, envía una petición de firma (CSR) al servidor y se queda esperando:
sudo /opt/puppetlabs/bin/puppet agent --test --waitforcert 60
Info: Creating a new SSL key for web01.example.com
Info: Creating a new SSL certificate request for web01.example.com
Info: Certificate Request fingerprint (SHA256): 8A:3F:...
Info: Certificate for web01.example.com has not been signed yet
Anota la huella (fingerprint) que aparece en la salida y deja el comando corriendo.
Paso 5: Firmar el certificado en el servidor
En el servidor, lista las peticiones pendientes:
sudo /opt/puppetlabs/bin/puppetserver ca list
Requested Certificates:
web01.example.com (SHA256) 8A:3F:...
Si la huella coincide con la que mostró el agente, fírmala:
sudo /opt/puppetlabs/bin/puppetserver ca sign --certname web01.example.com
En el agente, el comando que dejaste esperando descarga el certificado, pide su catálogo (todavía vacío) y termina con:
Notice: Applied catalog in 0.02 seconds
A partir de aquí el agente se conecta al servidor con TLS mutuo. No uses la autofirma de certificados salvo en redes completamente cerradas.
Paso 6: Crear un módulo
El código de Puppet vive en entornos. El entorno por defecto, production, está en /etc/puppetlabs/code/environments/production, con los módulos en modules/ y el punto de entrada en manifests/site.pp. En el servidor, crea un módulo miweb que instale Nginx y publique una página:
sudo mkdir -p /etc/puppetlabs/code/environments/production/modules/miweb/{manifests,templates}
sudo nano /etc/puppetlabs/code/environments/production/modules/miweb/manifests/init.pp
class miweb (
String $site_name,
) {
package { 'nginx':
ensure => installed,
}
file { '/var/www/html/index.html':
ensure => file,
owner => 'root',
group => 'root',
mode => '0644',
content => epp('miweb/index.html.epp', {
'site_name' => $site_name,
}),
require => Package['nginx'],
}
service { 'nginx':
ensure => running,
enable => true,
subscribe => File['/var/www/html/index.html'],
}
}
La plantilla usa EPP, el formato de plantillas nativo de Puppet:
sudo nano /etc/puppetlabs/code/environments/production/modules/miweb/templates/index.html.epp
<%- | String $site_name | -%>
<h1><%= $site_name %></h1>
<p>Servidor: <%= $facts['networking']['fqdn'] %></p>
Valida la sintaxis antes de seguir:
sudo /opt/puppetlabs/bin/puppet parser validate /etc/puppetlabs/code/environments/production/modules/miweb/manifests/init.pp
Si no imprime nada, la sintaxis es correcta.
Paso 7: Asignar el módulo y sus datos con Hiera
La clase tiene un parámetro obligatorio, site_name. En lugar de escribir el valor en el código, sepáralo en Hiera, el sistema de datos jerárquico de Puppet. El entorno production ya incluye un hiera.yaml que busca primero en data/nodes/<certname>.yaml y después en data/common.yaml. Crea el dato común:
sudo mkdir -p /etc/puppetlabs/code/environments/production/data
sudo nano /etc/puppetlabs/code/environments/production/data/common.yaml
---
miweb::site_name: 'Mi web gestionada con Puppet'
Puppet asigna automáticamente la clave miweb::site_name al parámetro site_name de la clase miweb. Ahora declara qué nodos reciben la clase en site.pp:
sudo nano /etc/puppetlabs/code/environments/production/manifests/site.pp
node 'web01.example.com' {
include miweb
}
node default {
}
Comprueba que Hiera resuelve el dato (al estar en common.yaml, vale para cualquier nodo):
sudo /opt/puppetlabs/bin/puppet lookup miweb::site_name
--- Mi web gestionada con Puppet
Paso 8: Aplicar la configuración en el agente
En el agente, primero haz una ejecución en seco con --noop, que muestra los cambios sin aplicarlos:
sudo /opt/puppetlabs/bin/puppet agent --test --noop
Si todo cuadra, aplícala:
sudo /opt/puppetlabs/bin/puppet agent --test
Notice: /Stage[main]/Miweb/Package[nginx]/ensure: created
Notice: /Stage[main]/Miweb/File[/var/www/html/index.html]/content: content changed ...
Notice: /Stage[main]/Miweb/Service[nginx]: Triggered 'refresh' from 1 event
Notice: Applied catalog in 12.41 seconds
Comprueba el resultado:
curl -s http://localhost
<h1>Mi web gestionada con Puppet</h1>
<p>Servidor: web01.example.com</p>
Una segunda ejecución de puppet agent --test no debe mostrar cambios.
Finalmente, habilita el servicio del agente para que aplique el catálogo automáticamente, por defecto cada 30 minutos:
sudo systemctl enable --now puppet
Solución de problemas
Connection refused - connect(2) for "puppet.example.com" port 8140: Puppet Server no ha terminado de arrancar o el firewall bloquea el puerto. Revisasudo journalctl -u puppetservery la regla de UFW.- Puppet Server no arranca por memoria: el heap de
JAVA_ARGSes mayor que la RAM disponible. Redúcelo en/etc/default/puppetserver. certificate verify failedo certificados que no coinciden tras reinstalar un agente: revoca y borra el certificado antiguo en el servidor consudo /opt/puppetlabs/bin/puppetserver ca clean --certname web01.example.com, borra/etc/puppetlabs/puppet/sslen el agente y repite el paso 4.Could not find class miweb: el directorio del módulo no se llama igual que la clase o está fuera deenvironments/production/modules.Class[Miweb]: expects a value for parameter 'site_name': Hiera no encuentra el dato. Revísalo conpuppet lookup ... --explain.
Conclusión
Tienes un servidor Puppet con su propia CA, un agente autenticado por certificado y un módulo que separa código y datos con Hiera. Como siguientes pasos, puedes versionar el directorio de código con Git y desplegarlo con r10k, reutilizar módulos del Puppet Forge y añadir datos por nodo en data/nodes/.
