puppet


Konfigurationsmanagement mit Puppet

Zu den immer wiederkehrenden Aufgaben eines Administrators gehört es, Änderungen auf viele Server zu verteilen. Möglichkeiten dazu gibt es viele: shell-Skripte in einer ssh-Schleife, Ansible, Bcfg2, CFEngine, Chef, Puppet, SaltStack und viele andere. In diesem Artikel legen wir ein besonderes Augenmerk auf das Systemkonfigurationswerkzeug Puppet.

Installation

Puppet läuft auf den Betriebssystemen AIX, FreeBSD, Linux, OpenBSD, Mac OS X, HP-UX, Solaris und Windows. In der Regel gibt es fertige Pakete, die bei den meisten Distributionen sind diese im Lieferumfang enthalten.

Client-Server

Puppet ist ein Client-Server-System. Der Server (in Puppet-Terminologie: der Master) hält die Konfiguration aller Clients. Der Client (in Puppet-Terminologie: Puppet Agent) verbindet sich in der Regel halbstündlich mit dem Server, holt sich seine Konfigura­tion und führt die notwendigen Aktionen aus. Dabei sorgt er dafür, dass alles, was auf dem Master für die Client-Maschine konfiguriert ist, der Konfiguration auf dem Puppet Master entspricht.

Änderungen, die manuell auf einem Client-System durchgeführt werden, aber eine Ressource betreffen, die von Puppet verwaltet wird, haben also eine Lebensdauer von maximal einer halben Stunde.

Konfiguration

Puppet hat eine Konfigurationsdatei (/etc/puppet/puppet.conf) mit etlichen Einstellungen. Falls Sie Ihren Master puppet (.mydomain.org) nennen, kommen Sie mit den Defaults gut zurecht und müssen dort nichts ändern.

Sicherheit

Die Kommunikation zwischen Master und Agent verläuft über eine SSL-Verschlüsselung. Puppet selbst bein­haltet eine eingebaute Zertifizierungsstelle. Nach der Installation und dem Start des Puppet Master erzeugt diese ein SSL-Zertifikat. Der Client erzeugt bei seinem ersten Start eine Zertifikatsanforderung, die dann manuell auf dem Master signiert werden muss. Ab diesem Zeitpunkt muss jeder Master oder Agent ein SSL-Zertifikat besitzen, welches von dem Gegenüber geprüft wird. Schlägt die Prüfung fehl, findet keine Kommunikation statt.

Wer auf dem Puppet Master root oder Puppet-Berechtigungen hat, ist in der Lage, auf allen Clients beliebige Aktionen durchzuführen. Das System sollte daher gut gehärtet sein, dabei sollten nur die notwendigsten Dienste laufen und Benutzer-Accounts sehr sparsam angelegt werden.

Sprache

Puppet ist in Ruby geschrieben. Die Konfigurationen werden aber in einer einfachen Beschreibungssprache verfasst. Daher sind keine Ruby-Kenntnisse nötig, um Puppet zu nutzen.

Ressourcen

Die Ressourcen, die Puppet verwaltet werden auf dem Server definiert. Diese sind unter anderem:

  • Package ― verwaltet (installiert, deinstalliert) Softwarepakete
  • Service ― verwaltet (startet, stoppt) laufende Dienste
  • File ― verwaltet Dateien einschließlich ihres
  • Inhalts, Eigentümerschaft, Rechte, etc.
  • User ― verwaltet lokale Benutzer
  • Exec ― führt Kommandos auf den Clients aus
  • Mount ― definiert und hängt Dateisysteme ein und aus

Ein Beispiel:
Der Secure Shell Daemon soll laufen und bei jedem Booten neu gestartet werden:

 service { 'ssh' :
    ensure => 'running',
    enable => 'true'
}

Dieses wird zwar auf dem Master konfiguriert, die Intelli­genz, wie dies zu erreichen ist, liegt allerdings beim Agenten. Dieser weiß, wie ein Dienst auf dem jeweiligen System zu starten ist. Man bekommt damit eine gewisse Unabhängigkeit vom Betriebssystem des Client. Unglücklicherweise heißen die Dienste aber nicht auf allen Sys­temen gleich. Hat man also einen Rechnerpark mit z. B. Solaris- und Linux-Maschinen, muss es so, wie in Abbildung 1 geschrieben werden.

Der Secure Shell Deamon kann natürlich nur laufen, wenn das sshd-Softwarepaket auch installiert ist. Da Puppet auch Softwarepakete verwaltet, fügt man ein Statement für die Paketressource ein, die vor dem Start des Dienstes installiert sein muss und verbinden diese in einer Klasse (siehe Abbildung 2).

Falls nun auch die Konfigurationsdatei des Secure Shell Daemon verwaltet werden soll, fügt man noch eine File-Ressource in die Klasse ein (siehe Abbildung 3).

Wenn sich der Client am Server meldet, wird im Unterver­zeichnis /etc/puppet/modules/ssh/files des Servers zuerst nach einer Datei sshd_config.<client hostname> gesucht, dann nach sshd_config.<client operationsystem> und zuletzt nach sshd_config.

Die zuerst gefundene ssh-Konfiguration wird mit der Datei /etc/ssh/sshd_config auf dem Client verglichen und, falls sie sich unterscheidet, auf den Client kopiert. Anschließend wird der ssh-Service neu gestartet. Es fehlt dann nur noch die Angabe, auf welchen Servern die sshd-Datei laufen soll. Diese steht in der zentralen Puppet-Konfigurationsdatei site.pp:

....
node server1.mydomain.con, server2.mydomain.com  {
    include ssh
    ....
}
....

Als Nodename kann auch ein regulärer Ausdruck angegeben werden.

Das Beispiel hat jetzt die Ressourcen Files, Services und Packages verwendet. Wie bereits erwähnt gibt es etliche weitere Ressourcen, die aber nicht alle benutzt werden müssen. In jedem Fall, sollte man sich gut überlegen, was mit Puppet verwaltet werden soll und was nicht. So kann man beispielsweise Benutzer inklusive Passwort und öffentlichem ssh-Schlüssel zentral verwalten. Man sollte diese Möglichkeit aber auf System- und Funktions-User beschränken. Personale Accounts sollten beispielsweise besser mit LDAP verwaltet werden, da bei einer zentralen Puppet-Benutzer- und Passwortverwaltung die Benutzer keine Möglichkeit haben, ihr Passwort selbst zu ändern. Die Verwaltung von ssh-Schlüsseln mittels Puppet funk­tioniert nicht ohne Weiteres, falls die Heimatverzeichnisse auf einem NFS-Laufwerk liegen und der NFS keinen root-Zugriff der NFS Clients erlaubt, was in der Regel aus Sicherheitsgründen der Fall sein sollte. Es erscheint aber auf jeden Fall sinnvoll, Benutzer, die bei der Betriebssysteminstallation unnötigerweise automatisch installiert wurden, per Puppet-Konfiguration zu entfernen - wie zum Beispiel den Benutzer uucp:

user 'uucp': { 
ensure => 'absent',
}

Puppet Subsystem Facter

Die in dem Beispiel verwendeten Variablen $hostname oder $operatingsystem werden vom Puppet Sub­system Facter bereitgestellt. Facter sammelt grundlegende Fakten über Clients und Server wie beispielsweise Hardwaredetails, Netzwerkeinstellungen, Betriebssystem und Version, IP-Adressen, MAC-Adressen, ssh-Schlüssel und vieles mehr. Diese Informationen werden dann in Puppet als Variablen zur Verfügung gestellt. Die Variablen können mit dem Befehl facter ausgegeben werden (siehe Abbildung 4).

Der Server hält nicht nur seine eigenen Facts, sondern auch die der Clients. Facter ist erweiterbar und es ist leicht, eigene Fakten oder ortsspezifische Fakten hinzuzufügen.

Fazit

Für Puppet benötigt man einige Einarbeitungszeit und es erhöht die Komplexität der Systeme. Der Administrator muss seine Systeme auch weiterhin gut kennen und benötigt zusätzlich noch Puppet-Kenntnisse. Allerdings nimmt – wenn die Puppet-Konfiguration einmal steht – das Tool dem Administrator auch eine Menge Arbeit ab. Der Aufwand der Konfiguration und Pflege von Puppet wächst mit der Inhomogenität der Server. Die Arbeitsersparnis wächst mit der Anzahl der verwalteten Systeme. So kann es bei einer Webserverfarm mit gleichem Betriebssystem schon bei einem Dutzend Servern gewinnbringend sein, Puppet einzusetzen.

Gerhard Weick
()

 

 

Abbildungen:

service { 'ssh' :
Name => $operatingsystem ? {
/Redhat|CentOS|Fedora|Ubuntu|Debian/ => "sshd",
Solaris => "ssh",
}
ensure => 'running',
enable => 'true'
Abb. 1: Kommando für einen heterogenen Rechnerpark
class 'ssh' {
package { 'ssh':
name => operatingsystem ? {
/Redhat|CentOS|Fedora|Ubuntu|Debian/ => 'openssh-
server',
Solaris => "ssh",
}
ensure => installed,
before => Service['ssh'],
}
service { 'ssh' :
name => $operatingsystem ? {
/Redhat|CentOS|Fedora|Ubuntu|Debian/ => "sshd",
Solaris => "ssh",
}
ensure => 'running',
enable => 'true'
}
}
 Abb. 2: Statement für die Paketressource
class 'ssh' {
package { 'ssh':
name => operatingsystem ? {
/Redhat|CentOS|Fedora|Ubuntu|Debian/ => 'openssh-
server',
Solaris => "ssh",
}
ensure => installed,
before => Service['ssh'],
}
service { 'ssh' :
name => $operatingsystem ? {
/Redhat|CentOS|Fedora|Ubuntu|Debian/ => "sshd",
Solaris => "ssh",
}
ensure => 'running',
enable => 'true'
}
fi le { 'sshd_confi g':
path => '/etc/ssh/sshd_confi g',
ensure => fi le,
owner => root,
group => sys,
mode => 0644,
source => [
"puppet:/modules/ssh/sshd_confi g.$hostname",
"puppet:/modules/ssh/sshd_
confi g.$operatingsystem",
"puppet:/modules/ssh/sshd_confi g"
],
notify => Service['ssh']
}
Abb. 3: File-Ressource zum Verwalten der Konfigurationsdatei
root@puppet:~# facter
architecture => i86pc
hardwareisa => i386
hostname => puppet
id => root
interfaces => lo0,net0
ipaddress => 10.0.2.15
ipaddress_lo0 => 127.0.0.1
ipaddress_net0 => 10.0.2.15
is_virtual => true
kernel => SunOS
kernelmajversion => 11.2
macaddress => 08:00:27:9f:42:7a
macaddress_net0 => 8:0:27:9f:42:7a
memoryfree => 2.57 GB
memorytotal => 5.00 GB
netmask => 255.255.255.0
netmask_lo0 => 255.0.0.0
netmask_net0 => 255.255.255.0
network_lo0 => 127.0.0.0
network_net0 => 10.0.2.0
operatingsystem => Solaris
operatingsystemrelease => 5.11
osfamily => Solaris
path => /usr/bin:/usr/sbin
productname => VirtualBox
puppetversion => 3.4.1
swapfree => 2.00 GB
swapsize => 2.00 GB
timezone => CET
....
Abb. 4: Ausgabe mit facter

Logo ORDIX<sup>®</sup>  news lang

Weitere Artikel

Eine Übersicht über alle Artikel finden Sie im Inhaltsverzeichnis.

Impressum

Impressum der ORDIX® news 1/2016

Quellen

[Q1] Puppet Labs Documentation:
https://docs.puppetlabs.com/

Bildnachweis

© pixabay.com | Yomare | Marionette
© allvectors.com | Vector Gear