Puppet Master Clustering mit HAProxy – Teil 2

Team evoila
1. März 2016
Reading time: 7 min

Während sich Teil 1 dieser Serie mit dem grundlegenden Aufbau eines HA Clusters mit Puppet und HAProxy beschäftigte, werden wir in diesem Artikel auf die Konfiguration der Systeme sowie die Reihenfolge in der die Konfiguration zu geschehen hat eingehen.

Installation und Konfiguration

Puppet Master

Für die Installation und Konfiguration der Puppet Master, muss für puppet00 und puppet01 (siehe Architekturdiagramm) teilweise unterschiedlich vorgegangen werden:

puppet00 puppet01
Installation von Puppetmaster mit Passenger:

$ wget https://apt.puppetlabs.com/puppetlabs-release-trusty.deb
$ sudo dpkg -i puppetlabs-release-trusty.deb
$ sudo apt-get update$ sudo apt-get install puppetmaster-passenger

Löschen der standardmäßig erzeugten CA auf beiden Systemen:

$ rm -fR /var/lib/puppet/ssl/*
Anlegen einer neuen CA und Generierung von Serverzertifikaten für puppet00 und puppet01:

$ puppet cert --generate puppet00.nbg.evoila.com --dns_alt_names=puppet,puppet.nbg.evoila.com
$ puppet cert --generate puppet01.nbg.evoila.com --dns_alt_names=puppet,puppet.nbg.evoila.com
Nun mussen die folgenden Dateien von puppet00 auf puppet01 kopiert werden:

ca/ca_crl.pem
certs/ca.pemcerts/puppet01.nbg.evoila.com.pem
private_keys/puppet01.nbg.evoila.com.pem
public_keys/puppet01.nbg.evoila.com.pem

Anschließend werden die Berechtigungen gesetzt:

$ chown -R puppet:puppet /var/lib/puppet/ssl/
Anpassen der /etc/puppet/puppet.conf, so dass alternative DNS Namen möglich sind und die vom Load Balancer gesetzten HTTP Request Header Daten zur Authentifizierungausgelesen werden.

[main]
dns_alt_names=puppet,puppet.nbg.evoila.com

[master]
ssl_client_header = HTTP_X_CLIENT_DN
ssl_client_verify_header = HTTP_X_CLIENT_VERIFY
Da puppet00 unsere CA sein wird, muss die CA Funktion auf puppet01 deaktiviert werden.
/etc/puppet/puppet.conf

ca = false
Auf beiden Systemen muss nun die Apache2 Konfiguration angepasst werden. Zum einen muss SSL deaktiviert werden, da der Load Balancer die Anfragen unverschlüsselt weiterleiten wird. Zum anderen muss Apache die gesetzten HTTP Request Header auswerten und an Puppetmaster weitergeben.
/etc/apache2/sites-available/puppetmaster.conf

SSLEngine offSetEnvIf X-Client-Verify "(.*)" 
SSL_CLIENT_VERIFY=$1SetEnvIf X-Client-DN "(.*)" 
SSL_CLIENT_S_DN=$1

HAProxy

Um HAProxy für SSL Terminierung zu konfigurieren ist eine Version größer oder gleich 1.5 erforderlich. Der einfachste Weg unter Ubuntu sieht wie folgt aus:

$ add-apt-repository ppa:vbernat/haproxy-1.6
$ apt-get update
$ apt-get install haproxy

SSL Terminierung

Um die SSL Verbindung auf dem HAProxy zu terminieren muss HAProxy mit einem Zertifikat sowie Public und Private Key ausgestattet sein, wordurch es ihm möglich wird die eingehende verschlüsselte Verbindung vom Puppet Agent zu entschlüsseln. Dieses Zertifkat muss natürlich von derselben CA signiert sein wie das des Master und des Agents.

puppetlb puppet00
Zunächst muss auf dem CA Server ein Zertifikat für den Load Balancer ausgestellt werden. Dieser wird für den Client mit dem Namen “puppetlb” erreichbar sein. Das Zertifikat muss natürlich dementsprechend benannt werden:

$ puppet cert --generate puppetlb.nbg.evoila.com --dns_alt_names=puppetlb,puppetlb.nbg.evoila.com
Nun übertragen wir die folgenden Dateien von puppet00 auf puppetlb:

certs/ca.pem
certs/puppetlb.nbg.evoila.com.pem
private_keys/puppetlb.nbg.evoila.com

HAProxy verlangt bei der Konfiguration der SSL Terminierung ein sog. “combined PEM” welches das Zertifikat sowie den Private beinhaltet. Dieses kann nun leicht erzeugt werden:

$ cat /var/lib/puppet/ssl/certs/puppetlb.nbg.evoila.com.pem /var/lib/puppet/ssl/private_keys/puppetlb.nbg.evoila.com > /etc/haproxy/ssl/puppetlb.pem
$ cat /var/lib/puppet/ssl/certs/puppetlb.nbg.evoila.com.pem /var/lib/puppet/ssl/private_keys/puppetlb.nbg.evoila.com > /etc/haproxy/ssl/puppetlb.pem

Konfiguration von HAProxy

In diesem Beispiel fungiert HAProxy als LoadBalancer. Wir terminieren die SSL Verbindung wie oben beschrieben in HAProxy selbst, damit wir Anfragen an die CA zum richtigen Puppet Master senden können.

Dazu legen wir in der Konfigurationsdatei von HAproxy (/etc/haproxy/haproxy.cfg) ein Frontend an, welches sich um die SSL Terminierung und Weiterleitungsauswahl kümmert, sowie zwei verschiedene Backends:

  • “puppet-backend”: alle Puppet Master, die Agents mit Konfigurationen versorgen
  • “puppet-ca-backend”: beinhaltet nur den CA Master

Die Auswahl des Backends erfolgt über eine ACL (Access Control List), welche die vom Agent angefragte URL auf das Vorkommen von “certificate” überprüft.

Wichtig ist auch die Option “verify optional”: Bei der ersten Kontaktaufnahme des Agents zu HAProxy, soll diese zur CA weitergeleitet werden um eine Signierung des Client Zertifikats zu ermöglichen. Hat man hier “verify” auf “required” gesetzt, ist dies natürlich nicht möglich – das Zertifikat ist ja noch nicht signiert. Setzt man “verify” auf “none” kann im Folgenden die Kommunikation mit den Puppet Mastern nicht erfolgen. “Optional” hingegen erlaubt beide Kommunikationsarten.

frontend puppet-frontend
 bind *:8140 ssl crt /etc/haproxy/ssl/puppetlb.pem ca-file /etc/haproxy/ssl/ca.pem verify optional
 mode http
 http-request set-header X-Client-Verify-Real  %[ssl_c_verify]
 http-request set-header X-Client-Verify NONE if !{ hdr_val(X-Client-Verify-Real) eq 0 }
 http-request set-header X-Client-Verify SUCCESS if { hdr_val(X-Client-Verify-Real) eq 0 }
 http-request set-header X-Client-DN CN=%{+Q}[ssl_c_s_dn(cn)]
 http-request set-header X-SSL-Subject CN=%{+Q}[ssl_c_s_dn(cn)]
 acl ca path -m sub certificate
 default_backend puppet-backend
 use_backend puppet-ca-backend if ca

backend puppet-backend
 balance roundrobin
 mode http
 option tcp-check
 stick on src
 stick-table type ip size 1m expire 1m
 server puppet00.nbg.evoila.com 10.1.20.144:8140 check port 8140 inter 5s
 server puppet01.nbg.evoila.com 10.1.20.145:8140 check port 8140 inter 5s

backend puppet-ca-backend
 mode http
 option tcp-check
 server puppet00.nbg.evoila.com 10.1.20.144:8140 check port 8140 inter 5s

Puppet Agent

Wenn in der Umgebung kein DNS Server vorhanden ist, muss in /etc/hosts ein Eintrag gemacht werden, damit ein Auflösen der DNS Namen möglich ist.

10.1.20.143 puppetlb puppetlb.nbg.evoila.com

Installation von Puppet Agent

 

$ wget https://apt.puppetlabs.com/puppetlabs-release-trusty.deb  
$ sudo dpkg -i puppetlabs-release-trusty.deb  
$ sudo apt-get update
$ sudo apt-get install puppet

Die /etc/puppet/puppet.conf muss nun so angepasst werden, dass Puppet Agent weiß wie der Puppet Master für ihn erreichbar ist. Hier tragen wir den Namen des Load Balancers ein.

[agent]
server = puppetlb.nbg.evoila.com

Der Puppet Agent ist standardmäßig deaktiviert. Um dies zu ändern, aktualisiert man die Konfigurationsdatei /etc/default/puppet und setzt den Wert für START von “no” auf “yes”:

START = yes

Generieren und signieren von Zertifikaten

puppetagent puppet00
Erstanmeldung des Agents am Puppet Master:

$ puppet agent -t

Es wird ein Fehler ausgegeben, die besagt, dass kein Zertifikat gefunden wurde. Dieser Fehler ist, weil das generierte Zertifikat von dem CA Server zu genehmigt werden muss.
Beispielausgabe:

Info: Creating a new SSL key for puppetagent.nbg.evoila.com
Info: Caching certificate for ca
Info: csr_attributes file loading from /etc/puppet/csr_attributes.yaml
Info: Creating a new SSL certificate request for puppetagent.nbg.evoila.com
Info: Certificate Request fingerprint (SHA256):79:4E:4A:9F:ED:E6:0C:70:87:AA:2A:49:7E:2F:DB:5F:0A:39:B1:F0:80:70:AD:0B:9A:01:7E:E8:87:12:0B:06
Info: Caching certificate for ca
Exiting; no certificate found and waitforcert is disabled
Nun meldet man sich an dem CA Server and und kann sich mit

$ puppet cert --list
"puppetagent.nbg.evoila.com" (SHA256) 79:4E:4A:9F:ED:E6:0C:70:87:AA:2A:49:7E:2F:DB:5F:0A:39:B1:F0:80:70:AD:0B:9A:01:7E:E8:87:12:0B:06

eine Liste noch zu signierender Zertifikate anzeigen lassen.
Um sicher zu sein den richten Server zu signieren, kann man den Fingerprint des Clients an dieser Stelle nochmal abgleichen.

$ puppet cert --sign "puppetagent.nbg.evoila.com"
Notice: Signed certificate request for puppetagent.nbg.evoila.com
Notice: Removing file Puppet::SSL::CertificateRequest puppetagent.nbg.
evoila.com at '/var/lib/puppet/ssl/ca/requests/puppetagent.nbg.evoila.com.pem'
Kehrt man zurück auf den puppetagent, führt man den folgenden Befehl erneut aus:

$ puppet agent -t
Info: Caching certificate for puppetagent.nbg.evoila.comInfo: Caching certificate_revocation_list for ca
Info: Caching certificate for puppetagent.nbg.evoila.comInfo: Retrieving pluginfacts
Info: Retrieving pluginInfo: Caching catalog for puppetagent.nbg.evoila.com
Info: Applying configuration version '1454659619'
Notice: Finished catalog run in 0.02 seconds

Am Output des Puppet Agent kann man erkennen, dass der Puppet Run erfolgreich durchgelaufen ist. Nachfolgende Anfragen werden nun über die zwei verfügbaren Load Balancer verteilt.