Puppet: Virtuelle Ressourcen fuer Benutzer und SSH-Keys

Puppet kann Ressourcen nur einfach definieren. Hat man eine Klasse einmal eingebunden, kann man dieses an einer zweiten Stelle nicht erneut tun. Folgendes Beispiel:

Ich deploye eine selbst entwickelte Software und moechte sie unter einem bestimmten Nutzeraccount laufen lassen. Mit Puppet stelle ich sicher, dass der Nutzeraccount existiert. Spaeter moechte ich auf dem gleichen Server eine zweite Software deployen die ebenfalls unter diesem Benutzeraccount laeuft. Ich erzeuge dafuer ein weiteres Modul das die Abhaengigkeiten abbildet. Laesst sich wunderbar alles konfigurieren, aber spaetestens auf dem Server gibt es dann einen Fehler:

err: Could not retrieve catalog from remote server: Error 400 on SERVER: Duplicate declaration: Class[FOO] is already declared; cannot redeclare at /etc/puppet/manifests/site.pp:20 on node node01.example.org

Die Loesung fuer das Problem sind virtuelle Ressourcen. Im folgenden Beispiel moechte ich aufzeigen, wie man Benutzeraccounts als virtuelle Ressourcen definiert und auf den Nodes einbindet. Die Loesung die ich hier aufzeige habe ich mir nicht selbst ausgedacht, sondern bei meinem Kollegen abgeguckt.

Eigentlich kommt man bei mehreren Benutzeraccounts auf mehreren Servern nicht um einen LDAP Server herum. Bei kleineren Setups kann man es aber auch noch auf die klassische Art- und Weise mit lokalen Konten machen.

Viele Anleitungen die man im Internet liesst zeigen Wege, bei denen man die Benutzerinformationen als Parameter an die Klasse uebergibt. Ich habe mich bewusst dagegen entschieden und alle Infos in dem Modul. Spaeter werde ich mich wohl noch mal mit Hiera beschaeftigen, dann werde ich die Informationen dort ablegen.

Die Verzeichnisstruktur meines Moduls „users“ sieht wie folgt aus:

└── manifests
    ├── init.pp
    ├── mmuster.pp
    └── virtual.pp

Die init.pp ist sehr simpel:

class users () {
  include users::virtual
}

Spannender wird es dann, wenn man die virtual.pp anschaut:

class users::virtual {
 
  @user { 'mmuster':
    ensure      => 'present',
    comment     => 'Max Mustermann,,,',
    shell       => '/bin/bash',
    managehome  => true,
    groups      => ['sudo', 'wheel' ],
    }
 
  @ssh_authorized_key { 'mmuster-privat':
    ensure      => 'present',
    type        => 'ssh-rsa',
    user        => 'mmuster',
    key         => 'AAA [...] ZZZ='
  }
}

Virtuelle Ressourcen definiert man mit einem vorgestellten @. In dem Beispiel werden zwei virtuelle Ressourcen definiert:

  1. Den Nutzeraccount mmuster
  2. Den oeffentlichen SSH-Key mmuster-privat

Die Parameter fuer den Nutzeraccount mmuster bedeuten folgendes:

  • ensure => ‚present‘: Stellt sicher, dass der Benutzeraccount existiert. Wenn nicht wird er angelegt.
  • comment => ‚Max Mustermann,,,‘: Kommentar zum Benutzeraccountt in der /etc/passwd
  • shell => ‚/bin/bash‘: Die Shell die der Benutzeraccount haben soll.
  • managehome => true: Stellt sicher das das Homeverzeichnis existiert.
  • groups => [’sudo‘, ‚wheel‘ ]: Stellt sicher, dass der Benutzeraccount Mitglied in den Gruppen sudo und wheel ist. Die Gruppen muessen im System existieren. Sie werden nicht automatisch angelegt!

Die Einstellungen fuer den SSH-Key mmuster-privat bedeuten folgendes:

  • ensure => ‚present‘: Stellt sicher, dass der SSH-Key existiert
  • type => ’ssh-rsa‘: Definiert den Verschluesselungsalgorithmus
  • user => ‚mmuster‘: Der Benutzeraccount zu dem dieser oeffentliche SSH Schlussel gehoert
  • key => ‚AAA […] ZZZ=‘:Der eigentliche public key

Fertig ist die Definition der virtuellen Ressourcen. Damit diese spaeter auch auf dem Node ausgefuehrt werden, muessen sie mit der realize Funktion markiert werden. Das passiert in der dritten Datei: mmuster.pp

class users::mmuster inherits users::virtual {
 
  realize(
    User['mmuster'],
    Ssh_authorized_key['mmuster-privat']
  )
}

Das schoene an dieser Loesung ist, dass der Nutzer nun mit einer einzigen Zeile zu dem Node hinzugefuegt werden kann:

include users::mmuster

Zum Schluss: Das Passwort wird nicht gesetzt. Man kann den Hash bei dem Nutzer mit dem Parameter password => “ mitgeben. Das finde ich aber nicht gut, weil die Nutzer dann die Passwoerter nicht selbst aendern koennen. Man findet im Netz auch Infos zu Kruecken mit denen man das Passwort nur beim Nutzer anlegen setzen kann, sollte man an diesem Punkt angelangt sein ist definitiv wieder der Zeitpunkt erreicht sich erneut Gedanken ueber einen LDAP Server zur Benutzerverwaltung zu machen 8-)

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.

Fail2ban: Hostname im Subject / Emails vom 01.01.1970

Ich habe bei fail2ban immer die Emailbenachrichtigung aktiviert und dabei zwei Aenderungen in der /etc/fail2ban/action.d/sendmail-whois-lines.conf vorgenommen:

  1. Im Betreff habe ich den Hostnamen mit aufgenommen. Dafuer habe ich die actionstart, actionstop und actionban Zeilen so abgeaendert, dass Sie wie folgt beginnen:
    printf %%b "Subject: [Fail2Ban] - `hostname -f` - <name>:

    Neu ist das `hostname -f`.

  2. Weiter gibt es das Problem, das die Mails immer am 01.01.1970 verschickt werden. Dafuer existiert auch ein Bugreport auf Github, der Bugfix ist aber auf meinen Systemen noch nicht angekommen, weswegen ich ihn von Hand eingepflegt habe. In der Zeile unter den oben bereits erwaehnten habe ich hinter den date Aufruf jeweils ein –rfc 2822 eingefuegt. Die Zeile sieht nun bei mir wie folgt aus:
    Date: `date --rfc-2822 -u +"%%a, %%d %%h %%Y %%T +0000"`