Esta web utiliza cookies, puedes ver nuestra política de cookies aquí. Si continuas navegando estás aceptándola

Puppet-Foreman-ENC bajo Gentoo


Cuando el número de servidores a administrar aumenta la configuración manual se vuelve impracticable, en estos casos es necesario algún tipo de herramienta de gestión centralizada, hay varias opciones en el mercado como chef o ansible, pero la mejor y mas completa a mi parecer es puppet. Esta nos permitirá aplicar clases que no son ni mas ni menos que scripts de instalación y configuración, con ello conseguiremos dejar un servidor exactamente en el mismo estado que si lo hubiesemos instalado a mano.

El manual se dividirá en diferentes partes claramente separadas:


Componentes de la infraestructura:

Puppet se compone de cinco componentes:

  • puppet-master: Encargado de las clases
  • puppet-agent: Cliente que aplica las clases
  • smart-proxy: Ayuda en el displiegue automágico de servidores
  • ENC: External Node Classifier, script encargado de asignar clases a los agentes.
  • foreman: Interfaz web de gestión de todo el entorno, smart-proxys, localizaciones, empresas...

Puppet no se limita simplemente a aplicar las clases definidas, también puede servir como entorno de despliegue completo de servidores, ya sean virtuales o físicos, puppet es capaz de configurar registros DNS, DHCP, servir imágenes de arranque por TFTP...

En este manual se han instalado las siguientes versiones, hay mucha incompatibilidad entre versiones de puppet, gemas de ruby, versiones de foreman y smart-proxy. Siempre se ha utilizado la ultima versión estable ya sea del portage o desde las fuentes.

app-admin/puppet 3.7.3
dev-lang/ruby
1.9.3_p551-r1
2.0.0_p645
dev-ruby/rubygems 2.2.2
eselect ruby list
  [2]   ruby20 (with Rubygems) *
gem -v
2.2.2
www-servers/apache 2.2.29
passenger (5.0.11)
bundler 1.10.5
foreman 1.8
smart-proxy 1.9

Un dato importante es no mezclar versiones distintas de puppet-master puppet-agent, los cambios major podrían provocar comportamientos impredecibles.

2.7.2 - 2.7.9 -> OK
2.6.1 - 2.7.0 -> KO

Los equipos utilizados en este manual siguen el siguiente direccionamiento:

192.168.40.170    puppetmaster.alfaexploit.com
192.168.40.174    foreman.alfaexploit.com
192.168.40.176    puppetnode00.alfaexploit.com

Instalación de puppetmaster:

Comenzamos con la instalación del puppet-master:

emerge -av app-admin/puppet

Seleccionamos ruby2.0:

eselect ruby list
Available Ruby profiles:
  [1]   ruby19 (with Rubygems) *
  [2]   ruby20 (with Rubygems)

eselect ruby set 2
gem -v
2.2.2

Vamos a comenzar con algo sencillo, una clase que cambie el motd del sistema:

vi /etc/puppet/puppet.conf
[main]
        vardir = /var/lib/puppet
        logdir = /var/log/puppet
        rundir = /var/run/puppet
        confdir = /etc/puppet
        ssldir = /var/lib/puppet/ssl
    
[master]
        fileserverconfig = /etc/puppet/fileserver.conf
vi /etc/puppet/fileserver.conf
[extra-files]
    path /etc/puppet/extra-files
    allow *

El allow * es para permitirle el acceso a todos, en principio se pueden definir rangos de ips pero al menos en la versión 3.7.3 NO funciona correctamente y mediante auth.conf no hay manera, así que firewall a machete!!

NOTA: Los agentes deben alcanzar el servidor puppet-master utilizando su FQDN, así que ejecutamos el siguiente comando en el puppet-master para obtenerlo:

facter fqdn

Creamos el fichero para la clase de prueba:

mkdir /etc/puppet/extra-files
vi /etc/puppet/extra-files/motd
Welcome to AlfaExploit!!

En site.pp se definen que clases aplicar a que hosts, se puede combinar o ser sustituido por ENC: External Node Classifier.

vi /etc/puppet/manifests/site.pp
node default {
  file { '/etc/motd':
    source => 'puppet:///extra-files/motd'
  }
}
/etc/init.d/puppetmaster start

NOTA: node default indica que se aplicará a todos los agentes


Instalación de puppetagent:

emerge -av app-admin/puppet

eselect ruby list
Available Ruby profiles:
  [1]   ruby19 (with Rubygems) *
  [2]   ruby20 (with Rubygems)

eselect ruby set 2
gem -v
2.2.2

gem install msgpack
vi /etc/puppet/puppet.conf
[main]
        vardir = /var/lib/puppet
        logdir = /var/log/puppet
        rundir = /var/run/puppet
        ssldir = /var/lib/puppet/ssl

[agent]
        server = puppetmaster.alfaexploit.com
        environment = production
   

Pedimos a puppetmaster que nos acepte el certificado y corremos puppet por primera vez, cada 10s se comprobará si el cert ha sido confirmado:

puppet agent --test --waitforcert 10

En puppetmaster aceptamos el certificado del agente:

puppet cert --list
puppet cert --sign "SERVERNAME"

Comprobamos como puppet nos ha modificado el MOTD en el agente:

cat /etc/motd
Welcome to AlfaExploit!!

Puppet por defecto correrá cada 30min, arrancamos el servicio y lo añadimos al arranque:

/etc/init.d/puppet start
rc-update add puppet default 

Puppetmaster mediante Passenger:

Por defecto puppet utiliza Ruby’s WEBrick como servidor web, este está bien para hacer algunas pruebas iniciales pero está muy limitado, cuando haya un número considerable de hosts haciendo peticiones no aguantará y tendremos que pasar a algo mas escalable.
Yo he optado por instalar Apache con soporte para Rails/Rack(passenger), se podría instalar con el servidor web de nuestra elección pero yo he optado por Apache por ser con el que mas familiarizado estoy.

Paramos puppetmaster, a partir de ahora Apache tomará el control:

/etc/init.d/puppetmaster stop

Instalamos Apache y RubyGems:

emerge -av www-servers/apache virtual/rubygems

gem install rack passenger
passenger-install-apache2-module
-> Ruby

Please edit your Apache configuration file, and add these lines:

LoadModule passenger_module /usr/local/lib64/ruby/gems/2.0.0/gems/passenger-5.0.11/buildout/apache2/mod_passenger.so
   <IfModule mod_passenger.c>
     PassengerRoot /usr/local/lib64/ruby/gems/2.0.0/gems/passenger-5.0.11
     PassengerDefaultRuby /usr/bin/ruby20
   </IfModule>

Retocamos la config por defecto de Apache, cargando el módulo SSL, asignando un Timeout de 5s y definimos el ServerName:

vi /etc/apache2/httpd.conf
LoadModule ssl_module modules/mod_ssl.so
KeepAliveTimeout 5
ServerName puppetmaster.alfaexploit.com

Borramos los vhosts por defecto y generamos el nuestro:

rm /etc/apache2/vhosts.d/*
vi /etc/apache2/vhosts.d/00_puppet_passenger.conf
# Ruby locations:
LoadModule passenger_module /usr/local/lib64/ruby/gems/2.0.0/gems/passenger-5.0.11/buildout/apache2/mod_passenger.so
PassengerRoot /usr/local/lib64/ruby/gems/2.0.0/gems/passenger-5.0.11
PassengerDefaultRuby /usr/bin/ruby20

# And the passenger performance tuning settings:
# Set this to about 1.5 times the number of CPU cores in your master:
PassengerMaxPoolSize 6
# Recycle master processes after they service 1000 requests
PassengerMaxRequests 1000
# Stop processes if they sit idle for 10 minutes
PassengerPoolIdleTime 600

PassengerAppRoot /var/www/puppetmasterd

Listen 8140
<VirtualHost *:8140>
    # Make Apache hand off HTTP requests to Puppet earlier, at the cost of
    # interfering with mod_proxy, mod_rewrite, etc. See note below.
    PassengerHighPerformance On

    SSLEngine On

    # Only allow high security cryptography. Alter if needed for compatibility.
    SSLProtocol ALL -SSLv2 -SSLv3
    SSLCipherSuite EDH+CAMELLIA:EDH+aRSA:EECDH+aRSA+AESGCM:EECDH+aRSA+SHA384:EECDH+aRSA+SHA256:EECDH:+CAMELLIA256:+AES256:+CAMELLIA128:+AES128:+SSLv3:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!DSS:!RC4:!SEED:!IDEA:!ECDSA:kEDH:CAMELLIA256-SHA:AES256-SHA:CAMELLIA128-SHA:AES128-SHA
    SSLHonorCipherOrder     on

    SSLCertificateFile      /var/lib/puppet/ssl/certs/puppetmaster.alfaexploit.com.pem
    SSLCertificateKeyFile   /var/lib/puppet/ssl/private_keys/puppetmaster.alfaexploit.com.pem
    SSLCertificateChainFile /var/lib/puppet/ssl/ca/ca_crt.pem
    SSLCACertificateFile    /var/lib/puppet/ssl/ca/ca_crt.pem
    SSLCARevocationFile     /var/lib/puppet/ssl/ca/ca_crl.pem

    SSLVerifyClient         optional
    SSLVerifyDepth          1
    SSLOptions              +StdEnvVars +ExportCertData

    # These request headers are used to pass the client certificate
    # authentication information on to the puppet master process
    RequestHeader set X-SSL-Subject %{SSL_CLIENT_S_DN}e
    RequestHeader set X-Client-DN %{SSL_CLIENT_S_DN}e
    RequestHeader set X-Client-Verify %{SSL_CLIENT_VERIFY}e

    DocumentRoot /var/www/puppetmasterd/public

    <Directory /var/www/puppetmasterd/>
      Options None
      AllowOverride None
      # Apply the right behavior depending on Apache version.
      Order allow,deny
      Allow from all
    </Directory>

    ErrorLog /var/log/apache2/puppet_passenger_ssl_error.log
    CustomLog /var/log/apache2/puppet_passenger_access.log combined
</VirtualHost>

Generamos los directorios necesarios para la aplicación:

mkdir -p /var/www/puppetmasterd
mkdir -p /var/www/puppetmasterd/public/
mkdir -p /var/www/puppetmasterd/tmp

Reiniciamos Apache y lo añadimos al arranque:

/etc/init.d/apache2 restart
rc-update add apache2 default

Indicamos en la config del puppet que tenga en cuenta SSL:

vi /etc/puppet/puppet.conf
[main]
        vardir = /var/lib/puppet
        logdir = /var/log/puppet
        rundir = /var/run/puppet
        confdir = /etc/puppet
        ssldir = /var/lib/puppet/ssl

[master]
        always_cache_fetures = true
        ssl_client_header               = SSL_CLIENT_S_DN
        ssl_client_verify_header        = SSL_CLIENT_VERIFY
        fileserverconfig = /etc/puppet/fileserver.conf

Configuramos la aplicación web:

cd /var/www/puppetmasterd
vi config.ru
# a config.ru, for use with every rack-compatible webserver.
# SSL needs to be handled outside this, though.

# if puppet is not in your RUBYLIB:
# $LOAD_PATH.unshift('/opt/puppet/lib')

$0 = "master"

# if you want debugging:
# ARGV << "--debug"

ARGV << "--rack"

# Rack applications typically don't start as root.  Set --confdir, --vardir,
# --logdir, --rundir to prevent reading configuration from
# ~/ based pathing.
ARGV << "--confdir" << "/etc/puppet"
ARGV << "--vardir"  << "/var/lib/puppet"
ARGV << "--logdir"  << "/var/log/puppet"
ARGV << "--rundir"  << "/var/run/puppet"

# always_cache_features is a performance improvement and safe for a master to
# apply. This is intended to allow agents to recognize new features that may be
# delivered during catalog compilation.
ARGV << "--always_cache_features"

# NOTE: it's unfortunate that we have to use the "CommandLine" class
#  here to launch the app, but it contains some initialization logic
#  (such as triggering the parsing of the config file) that is very
#  important.  We should do something less nasty here when we've
#  gotten our API and settings initialization logic cleaned up.
#
# Also note that the "$0 = master" line up near the top here is
#  the magic that allows the CommandLine class to know that it's
#  supposed to be running master.
#
# --cprice 2012-05-22

require 'puppet/util/command_line'
# we're usually running inside a Rack::Builder.new {} block,
# therefore we need to call run *here*.
run Puppet::Util::CommandLine.new.execute

Asignamos los permisos necesarios:

chown puppet:puppet /var/www/puppetmasterd/config.ru
cd /var/www/puppetmasterd/
chown root:apache tmp/
chown -R root:apache public
chmod 770 tmp/
chmod 750 public/

Generamos los directorios iniciales de la app:

/etc/init.d/apache2 stop
puppet master --verbose --no-daemonize
Ctrl+C

Arrancamos Apache:

/etc/init.d/apache2 start

Comprobamos que se mantiene a la escucha en el puerto 8140:

netstat -nputa|grep 8140
tcp        0      0 0.0.0.0:8140            0.0.0.0:*               LISTEN      13236/apache2   

Hacemos un cambio para comprobar que el cliente lo aplica correctamente:

vi /etc/puppet/extra-files/motd
Welcome to AlfaExploit!!
Test2

Monitorizamos posibles errores:

tail -f /var/log/apache2/puppet_passenger_ssl_error.log

Aplicamos los cambios en el agente:

puppet agent -t
cat /etc/motd 
Welcome to AlfaExploit!!
Test2

Todo un éxito, podemos ver mediante passenger-status que nuestra aplicación está activa:

passenger-status
Version : 5.0.11
Date    : 2015-06-30 10:15:58 +0200
Instance: ha6pDdeg (Apache/2.2.29 (Unix) mod_ssl/2.2.29 OpenSSL/1.0.1m Phusion_Passenger/5.0.11)

----------- General information -----------
Max pool size : 6
App groups    : 1
Processes     : 1
Requests in top-level queue : 0

----------- Application groups -----------
/var/www/puppetmasterd:
  App root: /var/www/puppetmasterd
  Requests in queue: 0
  * PID: 21103   Sessions: 0       Processed: 8       Uptime: 14s
    CPU: 2%      Memory  : 34M     Last used: 11s ago

Foreman:

Foreman nos permitirá administrar de forma fácil y rápida todos los recursos necesarios por un equipo desde su instalación hasta su configuración final.

Instalamos Apache y RubyGems:

emerge -av www-servers/apache virtual/rubygems

No hay ebuild de Foreman para Gentoo por lo tanto debemos instalar desde las fuentes:

cd /var/www
git clone https://github.com/theforeman/foreman.git -b 1.8-stable
cd foreman
cp config/settings.yaml.example config/settings.yaml
vi config/settings.yaml
---
:unattended: true
:login: true
:require_ssl: false
:locations_enabled: false
:organizations_enabled: false
:support_jsonp: false
:mark_translated: false
:domain: 'alfaexploit.com'
:fqdn: 'foreman.alfaexploit.com'
:colorize_logging: false

Instalamos los backends de bases de datos necesarios:

emerge dev-db/sqlite dev-db/mysql++ dev-db/mysql

Mientras configuramos mysql en otro terminal vamos instalando libvirt:

emerge app-emulation/libvirt

Configuramos MySQL:

emerge --config =dev-db/mysql-5.6.24
/etc/init.d/mysql start
rc-update add mysql default
mysql_secure_installation

Creamos la base de datos de Foreman y aplicamos ACLs de acceso:

mysql> CREATE DATABASE foreman DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
mysql> USE mysql
mysql> GRANT ALL PRIVILEGES ON foreman.* TO foreman@'192.168.40.174' IDENTIFIED BY 'Iwn1tGeZnaw7UuSA5pJ2KL5eZ4f3Pc';
mysql> GRANT ALL PRIVILEGES ON foreman.* TO foreman@'127.0.0.1' IDENTIFIED BY 'Iwn1tGeZnaw7UuSA5pJ2KL5eZ4f3Pc';
mysql> FLUSH PRIVILEGES;
mysql> exit

Instalamos las gemas necesarias:

gem install activerecord-mysql2-adapter
gem install jquery-ui-rails
gem install bundler

Como vamos a utilizar MySQL, deshablitamos postgres:

bundle install --without postgresql test --path mysql2

Procedemos con la config de la DB:

cd /var/www/foreman/config
cp database.yml.example database.yml
vi database.yml
production:
  adapter: mysql2
  database: foreman
  username: foreman
  password: Iwn1tGeZnaw7UuSA5pJ2KL5eZ4f3Pc
  host: 127.0.0.1
  socket: "/var/run/mysqld/mysqld.sock"

Inicializamos la base de datos:

cd ..
RAILS_ENV=production bundle exec rake db:migrate
RAILS_ENV=production bundle exec rake assets:precompile
RAILS_ENV=production bundle exec rake db:seed
Login credentials: admin / XXXXXXXXX
RAILS_ENV=production bundle exec rake apipie:cache
gpasswd -a nobody puppet
gpasswd -a apache puppet
gpasswd -a puppet apache
gpasswd -a root puppet
cd /var/lib/puppet/ssl/private_keys/
chmod 660 foreman.alfaexploit.com.pem

Arrancamos Foreman:

cd /var/www/foreman/
./script/rails s -e production

Accedemos a él:

http://foreman.alfaexploit.com:3000
admin / XXXXXXXXXXXX

Foreman con Passenger:

Instalamos las gemas necesarias:

gem install rack passenger

passenger-install-apache2-module
-> Ruby

   LoadModule passenger_module /usr/local/lib64/ruby/gems/2.0.0/gems/passenger-5.0.11/buildout/apache2/mod_passenger.so
   <IfModule mod_passenger.c>
     PassengerRoot /usr/local/lib64/ruby/gems/2.0.0/gems/passenger-5.0.11
     PassengerDefaultRuby /usr/bin/ruby20
   </IfModule>

Configuramos Apache para que cargue el módulo SSL con un timeout de 5s y como ServerName foreman.alfaexploit.com:

vi /etc/apache2/httpd.conf
LoadModule ssl_module modules/mod_ssl.so
KeepAliveTimeout 5
ServerName foreman.alfaexploit.com

Borramos todos los vhosts y creamos el nuestro:

rm /etc/apache2/vhosts.d/*
vi /etc/apache2/vhosts.d/00_foreman_passenger.conf
# Ruby locations:
LoadModule passenger_module /usr/local/lib64/ruby/gems/2.0.0/gems/passenger-5.0.11/buildout/apache2/mod_passenger.so
PassengerRoot /usr/local/lib64/ruby/gems/2.0.0/gems/passenger-5.0.11
PassengerDefaultRuby /usr/bin/ruby20

# And the passenger performance tuning settings:
# Set this to about 1.5 times the number of CPU cores in your master:
PassengerMaxPoolSize 6
# Recycle master processes after they service 1000 requests
PassengerMaxRequests 1000
# Stop processes if they sit idle for 10 minutes
PassengerPoolIdleTime 600

Listen 443
<VirtualHost *:443>
  ServerName foreman.alfaexploit.com

  DocumentRoot /var/www/foreman/public
  PassengerAppRoot /var/www/foreman

  # Use puppet certificates for SSL

  SSLEngine On
  SSLCertificateFile      /var/lib/puppet/ssl/certs/foreman.alfaexploit.com.pem
  SSLCertificateKeyFile   /var/lib/puppet/ssl/private_keys/foreman.alfaexploit.com.pem
  SSLCertificateChainFile /var/lib/puppet/ssl/certs/ca.pem
  SSLCACertificateFile    /var/lib/puppet/ssl/certs/ca.pem
  SSLVerifyClient         optional
  SSLOptions              +StdEnvVars
  SSLVerifyDepth          3

  <Directory /var/www/foreman/>
    Options None
    AllowOverride None
    # Apply the right behavior depending on Apache version.
    Order allow,deny
    Allow from all
  </Directory>

  ErrorLog /var/log/apache2/foreman_passenger_ssl_error.log
  CustomLog /var/log/apache2/foreman_passenger_access.log combined

</VirtualHost>

Asignamos los permisos necesarios:

cd  /var/www/foreman
chmod 775 -R tmp
chown -R root:nobody tmp
chmod 0666 /var/www/foreman/log/production.log

Arrancamos Apache y lo añadimos al arranque:

/etc/init.d/apache2 restart
rc-update add apache2 default

Dejamos un tail en los logs por si apareciese algún error:

tail -f /var/log/apache2/foreman_passenger_ssl_error.log
tail -f /var/www/foreman/log/production.log

NOTA: Si se queja de ficheros de cache:

cd /var/www/foreman/
RAILS_ENV=production bundle exec rake apipie:cache

Accedemos al foreman:

https://foreman.alfaexploit.com
admin / XXXXXXXXXXXXXXXX

Podemos ver que apache tiene constancia de nuestra app en ruby:

passenger-status 
Version : 5.0.11
Date    : 2015-06-30 17:15:31 +0200
Instance: gog1gIeX (Apache/2.2.29 (Unix) mod_ssl/2.2.29 OpenSSL/1.0.1m Phusion_Passenger/5.0.11)

----------- General information -----------
Max pool size : 6
App groups    : 1
Processes     : 1
Requests in top-level queue : 0

----------- Application groups -----------
/var/www/foreman:
  App root: /var/www/foreman
  Requests in queue: 0
  * PID: 17718   Sessions: 0       Processed: 4       Uptime: 1m 9s
    CPU: 1%      Memory  : 63M     Last used: 8s ago

La mayoría de parámetros se pueden configurar desde la interfaz web pero hay algunos que solo se pueden tocar desde el fichero de config.

vi /var/www/foreman/config/settings.yaml
---
:unattended: true
:login: true
:require_ssl: true
:locations_enabled: false
:organizations_enabled: false
:support_jsonp: false
:mark_translated: false
:domain: 'alfaexploit.com'
:fqdn: 'foreman.alfaexploit.com'
:colorize_logging: false
:puppet_server: puppetmaster.alfaexploit.com
:create_new_host_when_facts_are_uploaded: true

Se puede habilitar el debug:

:logging:
  :level: debug

Reiniciamos Apache y Puppet:

/etc/init.d/apache2 restart
/etc/init.d/puppet restart

Si queremos recibir notificaciones via email debemos configurarlo:

cp email.yaml.example email.yaml
vi email.yaml
production:
  delivery_method: :smtp
  smtp_settings:
    address: localhost
    port: 25
    domain: alfaexploit.com
    authentication: :none

SmartProxy:

Para que puppet pueda exportar las clases a foreman es necesario el smart-proxy, lo instalaremos en puppet-master, esta es la parte mas peliaguda sin duda alguna ya que existen varias incompatibilidades entre versiones.

Añadimos en la sección master:

vi /etc/puppet/puppet.conf
[master]
        basemodulepath = /etc/puppet/modules

Nos bajamos el código fuente de la versión estable:

cd /usr