Puppet ist wohl das am weitesten verbreitete Tool für Konfigurationsmanagement, das es derzeit auf dem Markt gibt. Wer es produktiv einsetzen will, muss sich allerdings früher oder später Gedanken zu Themen wie Hochverfügbarkeit und Lastverteilung machen. In diesem Artikel demonstrieren wir ein Setup, welches genau das verspricht und zeigen, wie die einzelnen Komponenten für ein reibungsloses Zusammenspiel konfiguriert werden müssen.
Dabei decken wir in diesem ersten Teil die dazu notwendige Theorie ab, sodass ein grundsätzliches Verständnis für den Aufbau und das Konzept vermittelt wird. In Teil 2 gehen wir dann auf die Konfiguration der einzelnen Komponenten genauer ein.
Ziel dieser Architektur ist es, eine für den Puppet Agent (Client) transparente Lösung zu schaffen. Das bedeutet, dass Clients nicht über neue oder ausgefallene Cluster Knoten Bescheid wissen müssen und bei einer Topologieänderung keine Anpassung der Konfiguration notwendig ist
Um das zu erreichen benutzen wir HAproxy als Load Balancer. Er steht zwischen den Puppet Agents und den Puppet Master Servern. Dabei überwacht er den Zustand der Master und leitet Agents auf aktive Master-Server um.
Im Vergleich zu einfachen Architekturen mit nur einem Master und vielen Agents, tauchen nun einige Herausforderungen auf, die es zu lösen gilt. Schuld ist der in Puppet immanente auf SSL basierende Mechanismus zur Authentifizierung und Verschlüsselung, welcher von den Entwicklern anderer Configuration Management Tools wie Ansible und Chef regelmäßig angeprangert wird.
Puppet authentifiziert Server bidirektional, d.h. Agents authentifizieren den Server und der Server die Agents. So kann eine vertrauensvolle Kommunikation in beide Richtungen gewährleistet werden. Dazu setzt der Puppet Master eine eigene CA (Certificate Authority) auf und signiert Client Zertifikate auf Anfrage. Das ist allerdings ein manueller Prozess, den der Admin, der ein neues System in Puppet integrieren möchte, ausführen muss.
Mit zwei oder mehr Puppet Master Servern werden automatisch auch mehrere CAs erzeugt, nämlich eine pro Master. Stellt man nun einen Load Balancer davor, hat man ein Problem: Viele CAs aber nur ein Client Zertifikat. In dieser Konstellation könnte ein Puppet Agent nur mit dem Master kommunizieren, dessen CA sein Client Zertifikat signiert hat. Dies widerspricht natürlich vollständig den Konzepten der Ausfallsicherheit und Skalierfähigkeit. Stattdessen müssen die CAs auf allen Mastern außer einem deaktiviert werden. Nur dieser CA Master darf Zertifikate signieren. Gleichtzeitig müssen alle anderen Master Knoten den von dieser CA ausgestellten Zertifikaten vertrauen, selbst ein solches besitzen und mit Hilfe des CA Zertifikats Signaturen validieren zu können.
Verzeichnis | Beschreibung |
/var/lib/puppet/ssl | Hier liegen alle SSL bezogenen Dateien. |
/var/lib/puppet/ssl/ca | Ist der Puppet Master ein CA Master, liegen hier Private Key, Public Key und Zertifikat der CA sowie einige zusätzliche Dateien wie CRL (Certificate Revocation List), etc. |
/var/lib/puppet/ssl/certs | Hier legt der Puppet Master alle Zertifikate ab. Dazu gehört das CA Zertifikat, welches zur Validierung einer Signatur benötigt wird, sowie das eigene Server Zertifikat über welches der Master die Verschlüsselung aufbaut. |
/var/lib/puppet/ssl/private_keys | Private Key des Puppet Master |
/var/ib/puppet/ssh/public/keys | Public Keys des Puppet Master |
Hat man den Schritt der Verteilung der CA Zertifikate erledigt, kann ein Client nun sein Zertifikat vom aktiven CA Master signieren lassen und danach seine Konfiguration von jedem beliebigen Puppet Master abholen. Der nächste Schritt besteht also darin, einen Load Balancer dazwischen zu schalten.
Zu beachten ist allerdings noch die Problematik der Namen auf die Zertifikate ausgestellt werden. In einem Aufbau, in welchem jeder Agent mit jedem Master über denselben Namen kommunizieren können soll (z.B. puppet.local löst einmal auf Master 1 und ein anderes Mal auf Master 2 auf), ist es notwendig “puppet.local” in die Liste der alternativen Namen in das SSL Zertifikat aufzunehmen.
In einem Aufbau ohne Load Balancer bei dem Agent und Master direkt miteinander kommunizieren können ist die Sache ziemlich klar: Für den Erstkontakt muss der Admin den Verbindungsaufbau an den CA Master richten und anschließend das Zertifikat signieren. Danach ist der Agent in der Auswahl frei und kann über einen Load Balancer oder per Round Robin DNS auf die existierenden Puppet Master verteilt werden.
Mit Load Balancer gestaltet sich die Sache etwas schwieriger. Es stellen sich im Wesentlichen zwei Fragen, welche gleichzeitig die zu lösenden Probleme darstellen:
Punkt 1 kann relativ leicht gelöst werden, indem der Admin im Load Balancer zwei Gruppen von Server Backends anlegt: CA Server und alle.
Punkt 2 ist etwas komplexer: Richtet sich ein Agent an die CA um das CA Zertifikat zu downloaden und sein CSR (Certificate Signing Request) hochzuladen, tut er das über die folgende URL: http://<hostname>/<environment>/certificate/…
Kann der Load Balancer diese URL erkennen und auswerten, ist er in der Lage die Anfragen an das eine oder andere Server Backend weiterzuleiten.
Hier haben wir allerdings schon das nächste Problem: Agent und Master kommunizieren SSL verschlüsselt, heisst: der HTTP Traffic ist in SSL verpackt. So kann ein Load Balancer natürlich nicht die URL auslesen. Um das Problem zu lösen terminieren wir die SSL Verbindung am Load Balancer und erlauben eine weitere unverschlüsselte Kommunikation zwischen Load Balancer und Puppet Master.
Nun haben wir den Puppet Master aber einiger extrem relevanter Informationen beraubt: Über die SSL Kommunikation war es dem Master bisher immer möglich zu erkennen, welcher Agent mit ihm kommuniziert. Anhand dieser Information konnte er dann die Konfiguration zusammenstellen und als Catalog übermitteln. Nun ist die Verbindung aber unverschlüsselt, sodass es keine Informationen mehr über Zertifikate und dergleichen gibt. Dies kann nun gelöst werden, indem der Load Balancer die relevanten Informationen in Form von HTTP Request Headern setzt und an den Puppet Master weiterleitet: X-Client-Verify und X-Client-DN.
Man kann sich vorstellen, dass die Konfiguration dieses Konstrukts und der dahinter liegenden Regeln nicht völlig trivial ist. Aus diesem Grund sind die notwendigen Schritte in Teil 2 dieser Serie zusammengefasst.