Puppet: Manifest Dokumentation mit puppet doc / post-commit Hook

Wie ueberall im Leben bietet es sich auch an puppet Manifest Dateien zu dokumentieren. Die Dokumentation dort basiert auf rdoc. Die Syntax wird in der Puppet Manifest Documentation Wiki Seite unten ganz gut beschrieben. Hier ein paar Beispiele:

  1. Eine Testklasse mit Dokumentation davor. Wichtig ist, dass zwischen Ende der Dokumentation und Definition der Klasse KEINE Leerzeile ist, sondern die Kommentare bis direkt an die class test() {} Zeile gehen:
    Bildschirmfoto vom 2014-05-18 20:02:08
  2. Die einfachste Art- und Weise die Dokumentation zu lesen ist, diese auf der Kommandozeile auszugeben. Das tut man mit dem folgenden Befehl:
    puppet doc /path/to/manifest.pp

    Bildschirmfoto vom 2014-05-18 20:01:17

  3. Schoener zu lesen ist das ganze als HTML Seite. Ich persoenlich habe in dem GIT Repository in dem ich die Puppet Konfiguration verwalte einen post-commit Hook, der mir die Dokumentation erzeugt und in einem Verzeichnis ablegt, das mit Apache freigegeben ist. Der Aufruf dafuer ist in der post-commit Datei:
    puppet doc --all --mode rdoc --outputdir /var/www/example.org/puppetdocs/

    Und es sieht dann am Ende wie folgt aus:
    Bildschirmfoto vom 2014-05-18 20:02:44

    Wenn im Modul root Verzeichnis eine Datei README liegt, wird diese als Gesamtdokumentation fuer das Modul mit hinzugenommen.

Puppet: Reports per Mail mit tagmail

Puppet bietet die Moeglichkeit bei Aenderungen Reports per Email zu versenden. Dafuer gibt es den Tagmail Report Processor. Folgendes muss man tun um ihn zu verwenden:

Zuerst muss tagmail fuer die Reports aktiviert werden. Dafuer tagmail in der /etc/puppet/puppet.conf in den reports unter master hinzufuegen. Falls die Zeile bereits vorhanden ist den Wert ergaenzen. Der Standardwert ist uebrigens store. Beispiel:

[master]
reports = store, tagmail

Danach kann man die Reports in der Datei /etc/puppet/tagmail.conf konfigurieren. Die Datei ist immer gleich aufgebaut. Werte: Emailadressen. Die Werte und Emailadressen koennen einzelne oder kommaseparierte Eintraege sein. Pro Zeile eine neue Definition. Folgende Werte sind moeglich:

  • all
  • Klassennamen
  • Loglevel
  • Tags

Beispiele:

  1. Alle Reports sollen an die Emailadresse puppetreports@example.org gesendet werden:
     all: puppetreports@example.org
  2. Reports der Klassen sudoers und fail2ban soll an admins@example.org geschickt werden
    sudoers, fail2ban: admins@example.org
  3. Events mit dem Logleven emerg und crit sollen an John Doe und operators@example.org verschickt werden:
    emerg, crit: john.doe@example.org, operators@examplr.org

Es kann auch mit NOT gearbeitet werden, weitere Informationen dazu gibt es in der Dokumentation unter Docs: Config Files: tagmail.conf.

Ausserdem koennen Tags als Grundlage fuer Reports dienen. Tags werden zum Beispiel in Klassen definiert. Die Syntax dafuer ist anders als das was bisher hier auf dem Blog zu lesen war:

tag 'foo', 'bar'

Es koennen ein oder mehrere Tags vergeben werden, wichtig ist, dass sie nicht => zugewiesen werden und auch am Ende kein Komma steht. Weitere Informationen ueber Tags gibt es in der Puppet Dokumentation unter Docs: Language: Tags

Diese Tags kann man danach ebenfalls als Wert in der /etc/puppet/tagmail.conf definieren:

foo: foo@example.org

Gibt es keine Aenderungen werden keine Mails verschickt:

May 11 11:04:38 host puppet-master[18075]: Compiled catalog for node01.example.org in environment production in 0.05 seconds
May 11 11:04:40 host puppet-master[18075]: Not sending tagmail report; no changes

Gibt es Aenderungen einfach den Posteingang pruefen.

Puppet: Pruefung auf Syntaxfehler von .pp und .erb Dateien

In dem Blogeintrag Konfiguration in GIT Repository verwalten / push-to-deploy habe ich den update Hook verlinkt, der eine Syntaxpruefung von .pp Dateien macht. Diesen habe ich heute morgen noch erweitert, so das auch die Templates mit der Endung .erb ueberprueft werden.

Wer die beiden Kommandos manuell ausfuehren moechte, sie sind wie folgt:

  1. Pruefen der Syntax von .pp Dateien:
    puppet parser validate /path/to/file.pp

    Im Fehlerfall gibt es eine Ausgabe wie zum Beispiel:

    Error: Could not parse for environment production: Syntax error at 'jails' at /home/user/git/puppet/modules/fail2ban/manifests/init.pp:13
  2. Pruefen der Syntax von .erb Template Dateien:
    erb -x -T '-' /path/to/file.erb  | ruby -c

    Im Fehlerfall gibt es eine Ausgabe wie zum Beispuel:

    -:44: syntax error, unexpected ')', expecting $end
    ...:jails').include? "ssh" ).to_s); _erbout.concat "n"
    ...

Wie bereits frueher geschrieben, richtig praktisch ist das ganze als update Hook im Git Repository. Die Fehler werden zwar trotzdem nicht zu 100% korrekt abgefangen, dafuer muss man noch Tests ausfuehren (dazu spaeter mehr), aber fuers Erste fangen die beiden Pruefungen schon eine Menge ab.

Bildschirmfoto vom 2014-05-07 07:26:27

Puppet: Service bei Aenderung neu starten / fail2ban

Heute moechte ich mein fail2ban Modul vorstellen. Neu dabei ist, dass der Service neu gestartet wird, wenn sich eine Datei aendert. Das ist wichtig, damit die Einstellungen auch uebernommen werden.

Die Verzeichnisstruktur sieht wie folgt aus:

├── files
│   └── etc
│       └── fail2ban
│           └── action.d
│               └── sendmail-whois-lines.conf
├── manifests
│   └── init.pp
└── templates
    └── jail.local.erb

In der init.pp ist wird in dem file Abschnitt ein „notify“ in Richtung des Services aufgerufen. Das fuehrt dazu, dass wenn die Datei auf dem Node geaendert wird, auch der Service benachrichtigt wird damit dieser neu startet. Siehe dazu auch „Restart service when file changes“ aus dem Puppet CookBook. Folgendermassen sieht die init.pp aus:

# class to configure fail2ban
 
class fail2ban (
  $jails       = [],
  $sshport     = 'ssh',
  $apacheport  = 'http,https',
  $proftpdport = 'ftp,ftp-data,ftps,ftps-data',
  $postfixport = 'smtp,ssmtp',
  $dovecotport = 'smtp,ssmtp,imap2,imap3,imaps,pop3,pop3s',
  ) {
 
  package { 'fail2ban':
    ensure => installed
  }
 
  service { 'fail2ban':
    ensure => running,
    enable => true,
  }
 
  file { '/etc/fail2ban/jail.local':
    ensure  => 'present',
    content => template('fail2ban/jail.local.erb'),
    owner   => 'root',
    group   => 'root',
    mode    => '0644',
    notify  => Service['fail2ban'],
  }
 
  file { '/etc/fail2ban/action.d/sendmail-whois-lines.conf':
    ensure  => 'present',
    source  => 'puppet:///modules/fail2ban/etc/fail2ban/action.d/sendmail-whois-lines.conf',
    owner   => 'root',
    group   => 'root',
    mode    => '0644',
    notify  => Service['fail2ban'],
  }
 
}

Mein Template jail.local.erb ist wie folgt:

#############################################################################
#                                                                           #
# !!! This file is managed by puppet, all manual changes will be lost !!!   #
#                                                                           #
#############################################################################
 
 
 
#
# Local Fail2Ban configuration file.
#
 
 
[DEFAULT]
ignoreip = 127.0.0.1/8
bantime  = 600
maxretry = 3
backend = auto
destemail = fail2ban@localhost
 
 
 
#
# ACTIONS
#
 
banaction = iptables-multiport
mta = sendmail
protocol = tcp
chain = INPUT
action_mwl = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
               %(mta)s-whois-lines[name=%(__name__)s, dest="%(destemail)s", logpath=%(logpath)s, chain="%(chain)s"]
action = %(action_mwl)s
 
 
 
 
#
# JAILS
#
 
[ssh]
enabled  = <%= scope.lookupvar('fail2ban::jails').include? "ssh" %>
port     = <%= sshport %>
filter   = sshd
logpath  = /var/log/auth.log
maxretry = 6
 
 
 
[ssh-ddos]
enabled  = <%= scope.lookupvar('fail2ban::jails').include? "ssh-ddos" %>
port     = <%= sshport %>
filter   = sshd-ddos
logpath  = /var/log/auth.log
maxretry = 6
 
 
 
[apache]
enabled  = <%= scope.lookupvar('fail2ban::jails').include? "apache" %>
port     = <%= apacheport %>
filter   = apache-auth
logpath  = /var/log/apache*/*error.log
maxretry = 6
 
 
 
[proftpd]
enabled  = <%= scope.lookupvar('fail2ban::jails').include? "proftpd" %>
port     = <%= proftpdport %>
filter   = proftpd
logpath  = /var/log/proftpd/proftpd.log
maxretry = 6
 
 
 
[postfix]
enabled  = <%= scope.lookupvar('fail2ban::jails').include? "postfix" %>
port     = <%= postfixport %>
filter   = postfix
logpath  = /var/log/mail.log
 
 
 
[dovecot]
enabled = <%= scope.lookupvar('fail2ban::jails').include? "dovecot" %>
port    = <%= dovecotport %>
filter  = dovecot
logpath = /var/log/mail.log

Auch im Template gab es den scope.lookupvar Aufruf bisher nicht. Die Rueckgabe ist true oder false und so kann man nur die Dienste aktivieren, die auch manuell definiert wurden. Weitere Informationen gibt es in der Puppetlabs Doku unter Out-of-Scope Variables.

Definiert wird das ganze dann in der sites.pp wie folgt:

node 'node1.example.org' inherits default {
  class { 'fail2ban':
    jails   => [ 'ssh', 'ssh-ddos', 'apache' ],
    sshport => '2222',
  }
}

Zu der sendmail-whois-lines.conf gibts noch nen separaten Blogeintrag