Qué vas a conseguir
Montar desde cero una instalación de Puppet que gestiona servidores Linux y Windows: un servidor primario con su autoridad de certificación, dos agentes con el certificado firmado, un primer módulo que instala un paquete, escribe su fichero de configuración desde una plantilla y reinicia el servicio solo cuando el fichero cambia, los datos en Hiera separados por entorno y el código en Git. Y saber qué mirar cuando un agente deja de aplicar los cambios que se suben al repositorio.
Antes de empezar
- Un servidor Linux para el servidor primario (RHEL 9 o compatible en esta guía; Ubuntu 24.04 también sirve) con 4 GB de RAM como mínimo: Puppet Server es una aplicación Java y arranca con 2 GB de memoria reservada.
- Un nombre DNS estable para él, por ejemplo
puppet.contoso.local, que resuelvan todos los agentes. Los agentes se conectan por TCP 8140. - Dos servidores de prueba:
srv-app-01.contoso.local(Linux) ysrv-win-01.contoso.local(Windows Server 2022 o 2025), con la hora sincronizada. Los certificados fallan con relojes desfasados. - Acceso
sudoen los Linux y administrador local en el Windows. - Un repositorio Git para el código: desde el primer módulo, nada se edita a mano en el servidor.
1. Puppet u OpenVox: qué instalar
Desde 2025 hay dos caminos para la versión 8:
- Perforce, propietario de Puppet, anunció a finales de 2024 que los paquetes oficiales pasarían a un repositorio privado. Su distribución, Puppet Core, exige aceptar una licencia comercial, con un uso gratuito limitado (25 nodos en el anuncio original) y suscripción por encima. El código abierto publicado sigue bajo licencia Apache 2.0, pero el desarrollo nuevo ya no se hace en público.
- OpenVox es la bifurcación de la comunidad (Vox Pupuli), con primera versión en enero de 2025. Es compatible con el código de Puppet, publica paquetes en
yum.voxpupuli.orgyapt.voxpupuli.orgy mantiene la rama 8 mientras prepara la 9.
Los paquetes cambian de nombre (openvox-server y openvox-agent frente a puppetserver y puppet-agent), pero los comandos (puppet, puppetserver), las rutas (/etc/puppetlabs) y el lenguaje son los mismos. Esta guía usa los paquetes de OpenVox 8; con Puppet Core solo cambia el repositorio. Revisa las condiciones vigentes de cada uno antes de elegir.
2. El servidor primario
sudo rpm -Uvh https://yum.voxpupuli.org/openvox8-release-el-9.noarch.rpmsudo dnf install -y openvox-serversource /etc/profile.d/puppet-agent.shsudo /opt/puppetlabs/bin/puppet config set dns_alt_names puppet,puppet.contoso.local --section serversudo /opt/puppetlabs/bin/puppet config set server puppet.contoso.local --section mainsudo firewall-cmd --permanent --add-port=8140/tcp && sudo firewall-cmd --reloadsudo systemctl enable --now puppetserverpuppetserver --versionpuppetserver version: 8.11.0- Los ejecutables quedan en
/opt/puppetlabs/bin; el script de/etc/profile.dlo añade alPATH. Consudohace falta la ruta completa osudo -i. dns_alt_namesva antes del primer arranque: en ese arranque el servidor crea la autoridad de certificación y su propio certificado, y los nombres alternativos quedan grabados en él. Cambiarlo después obliga a regenerar el certificado del servidor.- La memoria de Java está en
/etc/sysconfig/puppetserver(en Ubuntu,/etc/default/puppetserver):JAVA_ARGS="-Xms2g -Xmx2g". Con cientos de agentes se sube aquí. - El código vive en
/etc/puppetlabs/code/environments/, un directorio por entorno. El paquete creaproduction.
3. El agente en Linux y en Windows
En el Linux:
sudo rpm -Uvh https://yum.voxpupuli.org/openvox8-release-el-9.noarch.rpmsudo dnf install -y openvox-agentsudo /opt/puppetlabs/bin/puppet config set server puppet.contoso.local --section mainsudo /opt/puppetlabs/bin/puppet agent -tInfo: Creating a new RSA SSL key for srv-app-01.contoso.localInfo: Creating a new SSL certificate request for srv-app-01.contoso.localInfo: Certificate Request fingerprint (SHA256): 4F:1A:7C:...:9CInfo: Certificate for srv-app-01.contoso.local has not been signed yetCouldn't fetch certificate from CA server; you might still need to sign this agent's certificate (srv-app-01.contoso.local).En Ubuntu, el paquete del repositorio es openvox8-release-ubuntu24.04.deb de apt.voxpupuli.org, se instala con dpkg -i y después apt update y apt install openvox-agent.
En el Windows, el MSI de la rama 8 está en downloads.voxpupuli.org/windows/openvox8/. Se instala en silencio desde PowerShell como administrador:
msiexec /qn /norestart /i openvox-agent-8.28.0-x64.msi PUPPET_MASTER_SERVER=puppet.contoso.local PUPPET_AGENT_STARTUP_MODE=AutomaticGet-Service puppetStatus Name DisplayName------ ---- -----------Running puppet Puppet Agent- El MSI añade
C:\Program Files\Puppet Labs\Puppet\binalPATH; la configuración queda enC:\ProgramData\PuppetLabs\puppet\etc\puppet.conf. Para ejecutarpuppet agent -ta mano, consola como administrador. - El nombre del certificado (certname) es el FQDN en minúsculas. Si el Windows no tiene sufijo DNS, se queda solo con el nombre corto;
PUPPET_AGENT_CERTNAME=srv-win-01.contoso.locallo fija en la instalación. - El agente se ejecuta como servicio cada 30 minutos (
runinterval). En el Linux,sudo /opt/puppetlabs/bin/puppet resource service puppet ensure=running enable=truelo deja activo al arrancar.
4. Firmar los certificados
Cada agente genera su clave y envía una petición de certificado. Hasta que el servidor la firma, no recibe nada:
sudo /opt/puppetlabs/bin/puppetserver ca listRequested Certificates: srv-app-01.contoso.local (SHA256) 4F:1A:7C:...:9C srv-win-01.contoso.local (SHA256) B2:77:0E:...:E0sudo /opt/puppetlabs/bin/puppetserver ca sign --certname srv-app-01.contoso.local,srv-win-01.contoso.localSuccessfully signed certificate request for srv-app-01.contoso.localSuccessfully signed certificate request for srv-win-01.contoso.localsudo /opt/puppetlabs/bin/puppetserver ca list --all- Compara la huella de
ca listcon la que mostró el agente antes de firmar: así sabes que firmas el equipo que crees. - La firma automática (
autosign.confo un script de política) existe y ahorra trabajo en despliegues masivos, pero firmar lo que llega sin comprobarlo da la configuración, y los secretos que lleve, a cualquier equipo que alcance el puerto 8140.
5. site.pp: qué recibe cada nodo
El fichero manifests/site.pp del entorno asigna clases a cada nodo por su certname:
node 'srv-app-01.contoso.local' { include role::app_linux} node 'srv-win-01.contoso.local' { include role::base_windows} node /^srv-web-\d+\.contoso\.local$/ { include role::web} node default {}- Se aplica el bloque más concreto que coincida; si ninguno coincide,
default. Sin bloquedefaultel agente falla con Could not find node statement. - En instalaciones grandes, la clasificación sale de un clasificador externo (Foreman, la consola de la edición comercial) en lugar de
site.pp. La idea es la misma: un nodo, un rol.
6. El primer módulo: paquete, plantilla y servicio
El módulo timesync instala chrony, escribe su configuración desde una plantilla con los servidores de hora de la empresa y reinicia el servicio solo si el fichero cambia:
class timesync ( Array[String] $servers,) { case $facts['os']['family'] { 'RedHat': { $conf = '/etc/chrony.conf' $service = 'chronyd' } 'Debian': { $conf = '/etc/chrony/chrony.conf' $service = 'chrony' } default: { fail("timesync: ${facts['os']['family']} no está soportado") } } package { 'chrony': ensure => installed, } file { $conf: ensure => file, owner => 'root', group => 'root', mode => '0644', content => epp('timesync/chrony.conf.epp', { 'servers' => $servers }), require => Package['chrony'], notify => Service[$service], } service { $service: ensure => running, enable => true, }}<%- | Array[String] $servers | -%># Gestionado por Puppet (módulo timesync). Los cambios a mano se pierden.<% $servers.each |$s| { -%>server <%= $s %> iburst<% } -%>driftfile /var/lib/chrony/driftmakestep 1.0 3rtcsyncrequireordena (primero el paquete, luego el fichero);notifyordena y reinicia el servicio cuando el fichero cambia. Si el fichero ya está como debe, no hay reinicio.$serversno tiene valor por defecto: sale de Hiera (apartado 8). Un valor fijo en el código obligaría a cambiar el módulo para cada sede.- Las plantillas EPP usan el propio lenguaje de Puppet; las ERB (
template(), sintaxis Ruby) siguen funcionando y son las que se verán en módulos antiguos. - Antes de subir:
puppet parser validate modules/timesync/manifests/init.ppypuppet-lintsobre el módulo.
En Windows los mismos tipos de recurso funcionan con otras rutas. Un perfil base mínimo:
class profile::base_windows { service { 'W32Time': ensure => running, enable => true, } file { 'C:/ProgramData/Contoso': ensure => directory, }}En las rutas de Windows, la barra normal evita problemas de escape en el código.
7. Roles y perfiles
El patrón habitual separa tres capas:
| Capa | Qué contiene | Ejemplo |
|---|---|---|
| Módulo de componente | Cómo se configura una pieza, sin datos de la empresa | timesync, módulos de Puppet Forge |
| Perfil | Una pieza de la empresa: qué módulos y con qué ajustes | profile::base_linux incluye timesync y el agente de monitorización |
| Rol | Qué es el servidor, solo con include de perfiles | role::app_linux = profile::base_linux + profile::app |
Cada nodo recibe un solo rol. Si dos servidores necesitan algo distinto, son dos roles. Los roles y perfiles suelen vivir en site/role y site/profile, junto a los módulos.
8. Hiera: los datos fuera del código
Hiera da valores a los parámetros de las clases según el nodo. En la raíz de cada entorno:
---version: 5defaults: datadir: data data_hash: yaml_datahierarchy: - name: "Por nodo" path: "nodes/%{trusted.certname}.yaml" - name: "Por sistema operativo" path: "os/%{facts.os.family}.yaml" - name: "Común" path: "common.yaml"---timesync::servers: - dc01.contoso.local - dc02.contoso.local- Puppet busca de arriba abajo y se queda con el primer valor: un fichero en
nodes/gana acommon.yaml. La clavetimesync::serversrellena el parámetro$serverssin que el código lo pida. - Usa
trusted.certname(del certificado) para la capa de nodo, no un fact que el propio agente puede falsear. - Como cada entorno tiene su
hiera.yamly sudata/,stagingpuede apuntar a otros servidores de hora sin tocarproduction. - Para ver qué valor sale y de dónde:
puppet lookup timesync::servers --environment production --explainen el servidor. - Las contraseñas no van en claro: hiera-eyaml las cifra dentro del YAML.
9. El código en Git y los entornos
- Un repositorio de control con
manifests/,site/,data/,hiera.yamly unPuppetfilecon los módulos de Puppet Forge y sus versiones. - Cada rama es un entorno: la rama
productionse despliega en/etc/puppetlabs/code/environments/production, la ramastagingen.../staging. La herramienta que hace ese despliegue es r10k (o Code Manager en la edición comercial), lanzada desde el pipeline al fusionar. - El flujo de un cambio: rama, revisión, fusión a
staging, prueba en unos pocos nodos, fusión aproduction.
Antes de aplicar nada, el ensayo en el agente:
sudo /opt/puppetlabs/bin/puppet agent -t --noop --environment stagingInfo: Using environment 'staging'Info: Retrieving pluginfactsInfo: Retrieving pluginInfo: Loading factsInfo: Caching catalog for srv-app-01.contoso.localInfo: Applying configuration version '1762160512'Notice: /Stage[main]/Timesync/File[/etc/chrony.conf]/content: current_value '{sha256}3b1f...', should be '{sha256}9ac2...' (noop)Notice: /Stage[main]/Timesync/Service[chronyd]: Would have triggered 'refresh' from 1 eventNotice: Applied catalog in 0.94 seconds--noop compila el catálogo y dice qué cambiaría sin tocar nada. Si el resultado es el esperado, la misma orden sin --noop aplica el cambio en ese nodo; el resto lo recibe en su siguiente ejecución al fusionar en production.
10. Informes: qué pasó en cada ejecución
- Con
-t, el código de salida dice el resultado: 0 sin cambios, 2 con cambios, 4 con fallos, 6 cambios y fallos. Sirve para un pipeline o un script. - En el agente,
puppet config print lastrunfileda la ruta del resumen de la última ejecución (hora, recursos cambiados, fallidos). Una comprobación de monitorización que avise si ese fichero tiene más de dos horas detecta agentes parados. - El agente envía un informe al servidor en cada ejecución; por defecto se guarda en
/opt/puppetlabs/server/data/puppetserver/reports/<certname>/. - Con más de unos pocos nodos, PuppetDB (u OpenVoxDB) guarda hechos, catálogos e informes de todos, y un panel como Puppetboard muestra qué nodos fallan o llevan tiempo sin informar.
11. El ticket: "un agente dejó de aplicar los cambios"
El cambio de servidores de hora llegó a todos los Linux menos a srv-app-02.contoso.local, reinstalado la semana pasada. Puppetboard dice que su último informe es de hace nueve días. Lo primero, una ejecución a mano en el agente y leer el primer error:
sudo /opt/puppetlabs/bin/puppet agent -tError: The certificate for 'CN=srv-app-02.contoso.local' does not match its private keyLos cuatro motivos habituales, por orden de frecuencia:
1. Certificado que no corresponde tras una reinstalación. El equipo nuevo generó otra clave, pero la CA conserva el certificado firmado del equipo anterior con el mismo nombre. Se borra en los dos lados y se vuelve a firmar:
# en puppet.contoso.localsudo /opt/puppetlabs/bin/puppetserver ca clean --certname srv-app-02.contoso.local# en srv-app-02.contoso.localsudo /opt/puppetlabs/bin/puppet ssl cleansudo /opt/puppetlabs/bin/puppet agent -t# de nuevo en el servidor: comprobar la huella y firmarsudo /opt/puppetlabs/bin/puppetserver ca sign --certname srv-app-02.contoso.localpuppet ssl clean borra la clave y el certificado del agente; en Windows es el mismo comando en una consola de administrador. Para que no se repita, el procedimiento de baja o reinstalación de un servidor incluye puppetserver ca clean y, con PuppetDB, puppet node deactivate.
2. Reloj desfasado. Errores como certificate verify failed (certificate is not yet valid) o un certificado recién firmado que el agente da por caducado. timedatectl en Linux o w32tm /query /status en Windows. Es justo lo que el módulo timesync evita, pero un equipo recién instalado aún no lo tiene: la hora se corrige a mano antes del primer puppet agent -t.
3. El puerto 8140. Failed to open TCP connection to puppet.contoso.local:8140 indica red o cortafuegos, no Puppet. nc -zv puppet.contoso.local 8140 en Linux o Test-NetConnection puppet.contoso.local -Port 8140 en Windows. Si no conecta, revisa el cortafuegos del servidor, el del propio equipo y si el nombre resuelve a la IP correcta.
4. Agente deshabilitado. Alguien lo paró para un cambio manual y no lo reactivó:
sudo /opt/puppetlabs/bin/puppet agent -tNotice: Skipping run of Puppet configuration client; administratively disabled (Reason: 'INC-4471 prueba manual de chrony');Use 'puppet agent --enable' to re-enable.sudo /opt/puppetlabs/bin/puppet agent --enablesudo /opt/puppetlabs/bin/puppet agent -t --nooppuppet agent --disable "motivo" es la forma correcta de parar un agente: deja el motivo a la vista. Antes de reactivarlo, el --noop enseña qué deshará Puppet de lo que se cambió a mano; si ese cambio debe quedarse, va al código primero.
En el ticket: nodo, primer error, causa, comandos ejecutados en servidor y agente, y la ejecución final con código de salida 0 o 2 y sin fallos.
Siguientes pasos
- La guía de Ansible: el primer playbook para parchear servidores cubre el otro enfoque: sin agente, por SSH y a demanda. Muchos equipos usan Puppet para el estado permanente y Ansible para tareas puntuales como el parcheo.
- La de Git para los scripts del equipo explica ramas, revisiones y fusiones, la base del repositorio de control.
- En el lado Windows, la guía de Windows Server: roles, parches y eventos ayuda a decidir qué conviene describir como código en un servidor base.
¿Falta algo o en tu entorno es distinto? Escríbeme y lo corrijo.
Tech Career Lab · newsletter
¿Te ha servido? Cada dos semanas envío una idea práctica para perfiles IT: LinkedIn, proyectos, networking y procesos de selección.
Apúntate y llévate las 33 ideas →