Allgemeine Informationen zu CFEngine

CFEngine steht für ConFigurationEngine. Es ist eine Software, mit der sich verschiedene Betriebssysteme (Unix, Linux und Windows) konfigurieren lassen.

Entgegen anderer Produkte, die das selbe Ziel verfolgen (Ansible, Chef, Puppet, Salt, u.a.) basiert CFEngine auf einer Promise-(Versprechens)-Therorie, welche vom freiwilligen Mitarbeiten eines jeden Systems ausgeht. Es wird also keinem System von zentraler Stelle etwas vorgeschrieben (wie mittles imperativer Programmierung), es wird bspw. keine Datei auf Systeme kopiert oder dort verändert, es wird keine Software ausgerollt u.ä.  An zentraler Stelle werden „Versprechensdateien“ erstellt, die sogenannten Promises; das sind Dateien, deren Namen auf .cf enden. Auf jedem System, welches mittels CFEngine verwaltet werden soll, läuft ein Agent. Für die Kommunikation zwischen dem Agenten und dem zentralen Server (sogenannter Hub (Narbe) oder Policy-(Richtlinien-)Server) muss ein Port auf ggf. vorhandenen Firewalls freigeschaltet werden. Dieser Agent kopiert die zentral vom Hub zur Verfügung gestellten Promises von dort auf das lokale System. Es wird also nichts vom Hub ausgeteilt, jedes System holt sich die Dateien vom Hub. Dieses Vorgehen ist sicherer als andere Mechanismen, die Systemveränderungen ausrollen i.S.v. „pushen“, also von zentraler Stelle aus aktiv verteilen. Weiter gibt es durch dieses Konzept keine zentrale Schwachstelle. Der zentrale Hub kann ausfallen; jedes System arbeitet dann mit den zuletzt lokal kopierten Promises weiter.

Was sind Promises und wie sehen sie aus?

In den Promises wird in der CFEngine-eigenen Programmiersprache der Wunschzustand des Systems beschrieben/ deklariert. Die Syntax ist einfach und selbsterklärend; allerdings nur, wenn man die englischen Begriffe versteht; wer hier einsteigt, muss soweit technisches Englisch verstehen. Bspw. kann ein Promise wie folgt aussehen (etwas vereinfacht):

Linux::
  packages:
    "apache2"
    policy => "present",
    version => "2.2.22";

Der Agent liest diese Datei. Liest das nun ein Agent auf einem Windows-System, passiert gar nichts, weil dieses Promise nur für Linux-Systeme einen Zustand beschreibt. Liest das ein Agent auf einem Linux-System, wird er den Apache-Webserver in der Version 2.2.22 auf dem lokalen System installieren, sofern er noch nicht installiert ist. Hier sind weitere Feinjustierungen möglich und zum Teil notwendig: Die Linux-Systeme werden weiter in Redhat, CentOS, Debian, SuSE usw. unterschieden; diese Systeme arbeiten mit verschiedenen Paketmanagern (apt-get, zypper, yum) und CFEngine muss entsprechend unterscheiden, damit es weiß, welchen Paketmanager es auf dem entsprechenden System verwenden muss. Das ist mittels „Klassen“/Classes möglich; diese Klassen sind nicht mit den Klassen der objektorientierten Programmierung zu verwechseln; aus diesem Grunde wird der Begriff in der CFEngine-Sprache mit den neuen Versionen auf „Contexts“ (Zusammenhänge) geändert.

An diesem Beispiel kann man erkennen, wie CFEngine arbeitet: es wird keinem System ein Befehl erteilt, es ist keine imperative Programmierung. Es wird ausschließlich der Zustand beschrieben, den man erreichen möchte: auf jedem Linux-System soll der Webserver, das apache-Paket, installiert werden. Wer das soweit versteht, sieht, dass hier weitere Information fehlt. Ist das Linux bspw. ein Redhat-System, so heißt das Webserverpaket nicht apache2, sondern httpd. In diesem Falle würde also obiges Promise nicht funktionieren, weil der Redhat-Paketmanager (yum) kein apache2-Paket finden wird. Wollen wir auf jedem Redhat-System den Webserver installieren, müsste das Promise derart aussehen:

redhat::
  packages:
    "httpd"
    policy => "present",
    package_module => yum,
    version => "2.4.18";

Hier wird jeder Agent nur weiter aktiv, wenn er auf einem Redhat-System läuft. Weiter wird CFEngine mitgeteilt, mit welchem Paketmanager eine Installation auf dem System funktioniert, nämlich yum.
Wer mit CFEngine arbeitet, muss das Geschehen immer aus Sicht des Agenten auf dem jeweiligen System betrachten; aus dieser Sicht werden die Wunschzustände deklariert bzw. die Promises geschrieben. Es gibt keinen Blick von einer zentralen Stelle, die alles kontrolliert. Auf jedem System, auf dem CFEngine installiert ist, laufen ein cf-server und ein cf-agent. Es können auch Promises geschrieben werden, die nur für den Hub definierte Wunschzustände beinhalten:

policy-server::
  packages:
    "httpd"
    policy => "present",
    package_module => yum,
    version => "2.4.18";

Dieses Promise würde auf jedem Hub (Policy-Server) den Webserver installieren, vorausgesetzt, er läuft auf Redhat oder CentOS. Das würde der cf-agent auf dem Hub erledigen.


Konvergenz

Wichtig im Umgang mit CFEngine ist das Prinzip der Konvergenz. Die Systeme werden nicht auf einen Schlag auf den Wunschzustand aktualisiert. Einige Konfigurationen bzw. Änderungen können auf einen Schlag durchgeführt werden, andere nicht. In den Promises wird der gewünschte Endzustand des Systems beschrieben; im obigen Beispiel ist der gewünschte Endzustand, dass das Paket httpd auf jedem Redhat-System installiert ist. Das muss aber nicht unbedingt beim ersten Lauf des Agenten passieren. Vielleicht erkennt der Agent beim ersten Lauf, dass eine ältere Version installiert ist und deinstalliert diese im ersten Durchgang und installiert die gewünschte Version im zweiten Lauf.

Bei der Arbeit mit CFEngine muss man sich vom Wunsch der eigenen vollständigen Kontrolle lösen. Das ist speziell für Systemadministratoren schwierig, die jahrelang Scripte geschrieben haben, in denen Schritt für Schritt die Kontrolle über das System behalten wird; jeder Schritt wird dem System vorgeschrieben, alle Abhängigkeiten werden selbst programmiert. All dieser Code und all diese Gedanken bzw. mentalen Kapazitäten sind hier nicht nur überflüssig, sondern störend. Mit CFEngine wird anders gearbeitet und die Kontrolle, was wann und wie auf den Systemen geschieht, wird der Software überlassen. Bei der Programmierung der CFEngine muss man nicht wissen, wie man auf Redhat, Ubuntu, SuSE oder Windows eine Datei erstellt, editiert oder eine Paket installiert; man muss nur wissen, wie man das Promise schreibt; all das andere, das Systemspezifische, macht CFEngine.


Warum CFEngine

Zum einen ist der o.g. Sicherheitsaspekt (kein Pushmechanismus, keine zentrale Fehlerstelle (Single point of failure) ein Vorteil. Weiter benötigt man für die Arbeit mit CFEngine nicht so detaillierte Programmierkenntnisse wie mit den anderen Produkten, die zudem oft nur mit Ruby funktionieren, was das Paket zum einen „schwerer bzw. fetter" macht und ebenfalls alle Sicherheitslücken von Ruby direkt mit einschleppt. CFEngine ist in C geschrieben und läuft daher auf jeder Hardware, die C unterstützt, bspw. auch einem Rasperry Pi! Hierdurch sind einige Lösungen in einer Preisklasse möglich, die sonst nicht zu halten ist. Hier sei als Beispielt eine Videoüberwachung genannt. Wer ein Gebäude mit vielen Videokameras überwachen muss, zahlt bereits zig-tausend Euro nur für Hardware. So etwas ist auch mit Rasperry Pis zu machen, die unter 30 Dollar zu haben sind! Die Geräteanforderungen sind: Linux- oder Unix-System, 400MHz CPU, 50MB Festplattenplatz und 25MB RAM.


CFEngine Versionen Community und Enterprise

CFEngine ist als Community-Edition frei verfügbar cfengine.com/product/community Die Enterprise-Edition ist bis 25 zu verwaltende Systeme (Nodes) ebenfalls frei verfügbar. Ab einer größeren Anzahl zu verwaltender Systeme wird CFEngine-Enterprise kostenpflichtig. Support auf die Enterprise-Edition bietet das Unternehmen CFEngine AS aus Norwegen. Vorteile der Enterprise-Edition sind eine grafische Oberfläche, auf denen die zu verwaltenden Systeme überwacht werden können und auf der Reports grafisch aufbereitet werden. Funktionen zur Verwaltung von Windows- Systemen werden nur in der Enterprise-Edition unterstützt und supported.

Die Installationen der Versionen ist unterschiedlich: bei der Community-Version wird das gleiche Paket auf dem Hub und auf den Nodes installiert. Die Enterprise-Version beinhaltet zwei separate Pakete. Zur lokalen Entwicklung am Desktop oder auf dem Notebook empfiehlt sich die Vagrant-Umgebung; diese arbeitet mit virtuellen Maschinen (VM) auf Virtual Box. Die Installation generiert zwei VMs, einen Hub und einen Node. Auf diese loggt man sich via ssh ein und kann somit lokal entwickeln.

Englische Vagrant-Anleitung von CFEngine.com

Community Support

Die Community-Edition wird von der Google-Gruppe „help-cfengine“ supported:  https://groups.google.com/forum/#!forum/help-cfengine Die Leute in der Gruppe sind nicht nur kompetent, freundlich und hilfsbereit, sondern auch noch sehr schnell dabei! Allerdings wird hier nur in Englischer Sprache kommuniziert. Wenn Sie Support in Deutscher Sprache wünschen, wenden Sie sich an mich.

Introduction in English

Hier ist ein eine Einführung in Englischer Sprache, die ich für meine Präsentation auf dem Config-Managment-Camp in Genf erstellt habe:
Get set for getting work done by CFEngine