Configuración de Puppet en Debian Jessie y creación de un módulo
Cuando tienes hacer un despliegue en muchos servidores o automatizar tareas repetitivas, Puppet es una gran opción. En base a manifiestos declarativos, Puppet se asegura de que existan recursos, los crea sin aún no existen y los utiliza. A diferencia de muchos otros lenguajes, en los manifiestos no se definen los procesos para aprovechar los recursos, sino que se describe «lo que debe haber» y Puppet se encarga de hacerlo realidad. Así ha sido dicho y así será hecho.
Arquitectura
En Puppet, hay dos arquitecturas:
Agent/Master
En esta arquitetura, uno o más servidores son el master de varios nodos cliente, llamados «agentes».
El agente envía una lista de «hechos» (facts) y pide un manifiesto de recursos al master. Éste compila un catalogo y lo envía al agente, el cual lo usará para realizar las tareas.
Standalone
Y, al contrario, en esta arquitectura sólo se utiliza una máquina para el Puppet.
Entorno
En el post utilizo dos máquinas virtuales:
Sistema Operativo: Debian Jessie IP address: 192.168.1.137 Host: puppetserver
Sistema Operativo: Debian Jessie IP address: 192.168.1.133 Host: puppetclient
Preparativos
NTP
El tiempo entre ambas máquinas debe estar lo más ajustado posible. Para ello usaremos NTP en los dos lados:
# apt install ntp
Nombres de dominio
Tanto en el master como en el agente, usaremos el archivo /etc/hosts . En el master:
192.168.1.133 puppetclient
En el agente:
192.168.1.137 puppetserver
Repositorio
Descargamos e instalamos el siguiente paquete para apt en ambas máquinas:
# wget //apt.puppetlabs.com/puppetlabs-release-pc1-jessie.deb # dpkg -i puppetlabs-release-pc1-jessie.deb # apt update
Instalando el servidor
El servidor puppet es el software que se ejecuta en el Master y envía las configuraciones a los nodos agente.
Instalamos con el siguiente comando:
# apt install -y puppetserver
Configurando el servidor
Editamos el archivo:
# vim /etc/puppetlabs/puppet/puppet.conf
Utilizaremos un entorno test para los manifiestos de más abajo. Añadimos las siguientes líneas:
[main] certname = puppetserver server = puppetserver environment = production runinterval = 1h environmentpath = /etc/puppetlabs/code/environments basemodulepath = /etc/puppetlabs/code/environments/production/modules log_level = notice
Empezar y autoarrancar al inicio del sistema operativo:
# systemctl start puppetserver # systemctl enable puppetserver
Instalando el Agente
Instalamos el agente con el siguiente comando:
# apt install -y puppet-agent
Añadimos en el archivo puppet.conf
[main] certname = puppetclient server = puppetserver environment = production runinterval = 1h
Arrancamos el agente al modo de Puppet:
# /opt/puppetlabs/bin/puppet resource service puppet ensure=running enable=true
Certificados
Eliminar certificados
Si ya hay certificados creados, pueden eliminarse escribiendo en el master:
# puppet cert sign --all # puppet cert clean nombrecertificado
Y en el agente:
# rm -rf /var/lib/puppet/ssl/*
Creando certificados
En el cliente:
# /opt/puppetlabs/bin/puppet agent -t Info: Caching certificate for ca Info: csr_attributes file loading from /etc/puppetlabs/puppet/csr_attributes.yaml Info: Creating a new SSL certificate request for puppetclient Info: Certificate Request fingerprint (SHA256): D0:DF:9F:13:D4:46:9A:9E:81:5D:D7:64:9E:F1:69:40:62:B1:1C:B6:C5:8A:6C:BB:D4:9A:CD:8A:88:F8:B4:78 Info: Caching certificate for ca Exiting; no certificate found and waitforcert is disabled
En el servidor, firmamos el certificado para el agente:
# /opt/puppetlabs/bin/puppet cert sign puppetclient Signing Certificate Request for: "puppetclient" (SHA256) D0:DF:9F:13:D4:46:9A:9E:81:5D:D7:64:9E:F1:69:40:62:B1:1C:B6:C5:8A:6C:BB:D4:9A:CD:8A:88:F8:B4:78 Notice: Signed certificate request for puppetclient Notice: Removing file Puppet::SSL::CertificateRequest puppetclient at '/etc/puppetlabs/puppet/ssl/ca/requests/puppetclient.pem'
Comprobamos el certificado:
# /opt/puppetlabs/bin/puppet cert list --all + "puppetclient" (SHA256) F7:9B:57:33:84:D2:06:13:77:61:C7:FD:04:5A:1E:1E:38:E8:12:0F:6E:E0:98:79:06:5E:49:BF:59:22:1F:94 + "puppetserver" (SHA256) AC:D9:3C:05:66:68:59:D8:87:DD:85:9D:8F:FA:F6:A7:28:4C:C1:1E:E4:85:B6:C8:F8:B9:AC:6C:24:03:C9:51 (alt names: "DNS:puppet", "DNS:puppetserver")
Comprobamos que el certificado haya sido firmado:
# opt/puppetlabs/bin/puppet agent --test Info: Caching certificate_revocation_list for ca Info: Using configured environment 'production' Info: Retrieving pluginfacts Info: Retrieving plugin Info: Caching catalog for puppetclient Info: Applying configuration version '1487457939' Info: Creating state file /opt/puppetlabs/puppet/cache/state/state.yaml Notice: Applied catalog in 0.09 seconds
Creando manifiestos
Vamos a realizar unas tareas básicas:
- Crear un usuario
- Crear un directorio
Entorno
Iniciamos la creación de un entorno test:
# mkdir -p /etc/puppetlabs/code/environments/test/modules/ # cd /etc/puppetlabs/code/environments/test # mkdir manifests
Creamos un módulo llamado enredadera-mod
# cd modules # /opt/puppetlabs/bin/puppet module generate enredadera-mod # mkdir /etc/puppetlabs/code/environments/test/mod/files
puppet.conf
Modificamos en el archivo puppet.conf del, master y del agente, la variable environment y cambiamos «production» por «test».
Manifiesto inicial del módulo
Los módulos necesitan un manifiesto con el nombre init.pp a partir del cual accede a los recursos del resto del módulo:
# vim /etc/puppetlabs/code/environments/test/modules/enredadera-mod/manifests/init.pp
Clase mod::usuario
Creamos una clase llamada mod::usuario:
class mod::usuario { }
Dentro de la clases declaramos los recursos grupo, usuario y home del usuario:
group { 'usuario': ensure => 'present', gid => '500', }
Continuamos:
user {'usuario': ensure => 'present', uid => '500', gid => '500', groups => ['gus'], home => '/home/usuario', shell => '/bin/bash', password => '$6$uAwjqazsaN$wUb5V4wgIQUbvIXHCfkkfDwtPHm8X8m/nVMgz/kbOgaTUuUA2SsENXN61s5lpIOzB3IFNnlbgmkos414ZwrtQ.', }
Por último declaramos el home del usuario:
file {'/home/usuario/': ensure => 'directory', owner => 'usuario', group => 'usuario', recurse => 'true', }
Por último, respetar el orden de ejecución de las declaraciones:
Group['usuario'] -> User['usuario']
El operador -> indica el orden de precedencia. De este modo, el grupo se crea entes del usuario. Podríamos añadir el recurso file, sin embargo, no sería un problema, en este caso, que sea creado a continuación del usuario.
La clase quedaría así:
class mod::usuario { group {'usuario': ... } user {'usuario': ... } file {'/home/usuario/': ... } Group['usuario'] -> user ['usuario'] }
Manifiesto principal
Para que la clase sea cargada desde el agente, hay que llamarla desde el archivo site.pp, para ello se crea un manifiesto en el entorno test:
# vim /etc/puppetlabs/code/environments/test/manifests/site.pp
Llamando a la clase
En el archivo definimos qué agentes tienen acceso con su hostname. El manifiesto site.pp llama a la clase del siguiente modo:
node 'puppetclient' { include mod::usuario }
Lanzando el manifiesto
Con el siguiente comando le decimos al agente que pida el manifiesto al master:
# /opt/puppetlabs/bin/puppet agent -t
Puede añadirse la opción –noop, con la cual ejecuta el manifiesto en «modo simulación» sin cambiar nada en el sistema.
Con esto cualquier nodo que utilice el manifiesto habrá creado un usuario.
Copiando y ejecutando un script bash
Creamos un archivo bash en el directorio files del módulo.
# vim /etc/puppetlabs/code/environments/test/modules/mod/files/nombre.sh
El contenido del archivo lo obvio. Puede ser cualquier script y un simple «echo ‘¡Hola, mundo!'» serviría para el ejemplo.
Ampliando el manifiesto
Objetivo
- Copiar un script desde el master al agente
- Ejecutar el script
Añadimos a init.pp la siguiente clase:
class mod::ejecuta { }
Copiamos el script desde el directorio files del módulo al directorio /usr/local/bin del agente:
file {'nombre': ensure => 'file', source => 'puppet://puppetserver/modules/basico/nombre.sh', path => '/usr/local/bin/nombre.sh', owner => 'root', group => '755', mode => '0777', }
Después de que se haya realizado la copia, el script será ejecutado en el agente:
exec {'nombre.sh': path => '/usr/local/bin', logoutput => 'true' }
Por último, y no menos importante, ordenamos la precedencia de ambos recursos:
File['nombre'] -> Exec['nombre.sh']
La clase quedará con la misma estructura que la clase definida anteriormente.
Incluimos la clase en el archivo site.pp
node 'puppetclient' { include mod::usuario include mod::ejecuta }
Montando carpetas para el agente
Creamos o editamos el archivo en cliente:
# vim /etc/puppetlabs/puppet/fileserver.conf
y añadimos las líneas:
[files] path /usr/local/bin allow *
Por último
Lanzamos el script del modo ya mostrado:
# /opt/puppetlabs/bin/puppet agent -t
En próximos posts mostraré como leer parámetros del sistema utilizando la aplicación Facter para configurar un módulo y cómo ampliar el comportamiento de Facter creando una extensión. También escribiré sobre los operadores de precedencia, ya que existen otros aparte de -> y varías maneras de utilizarlos.