Skip to content

Sophos UTM & Let’s Encrypt: Automatische Zertifikatsupdates

Ein Firewall- bzw. Sicherheitsprodukt, das wir bei vielen Kunden und auch bei uns selber einsetzen, ist die Sophos UTM. Sie besetzt einen äußerst attraktiven Mittelpunkt aus umfangreicher Funktionalität, benutzerfreundlicher Bedienung und günstigem Preis.

le-logo-standardEin anderes Produkt, das eine ähnlich verführerische Mischung bietet, ist das Let’s Encrypt-Projekt. Seine Prämisse ist einfach: kostenlose SSL-Zertifikate für alle, von allen Browsern und Produkten akzeptiert.

Eine Sophos UTM benötigt SSL-Zertifikate an verschiedenen Stellen: für das Benutzerportal, aber auch und vor allem beim SMTP-Proxy, der als ein- und ausgehende Schnittstelle für alle E-Mails einer Firma dienen kann. Warum also nicht Let’s Encrypt-Zertifikate in einer UTM einsetzen?

Das einzige, was der Verwendung ernsthaft entgegensteht, ist der Bedarf an Automatisierung. Let’s Encrypt-Zertifikate sind maximal 90 Tage gültig, und praktisch alle für Let’s Encrypt verfügbaren Clients erneuern schon deutlich früher, z.B. alle 30 Tage. Die Idee dahinter ist, dass Administratoren den kompletten Prozess der Zertifikatserneuerung automatisieren sollen, um das typische Problem zu vermeiden, das man mit langlebigen Zertifikaten sonst gerne hat: alle paar Jahre grübeln zu müssen, was man alles wie wo machen müssen, um ein langlebiges Zertifikat auszutauschen.

Wie soll man aber das Webinterface der Sophos UTM automatisieren? Gar nicht! Statt dessen werden wir via ssh direkt Konfigurationsobjekte verändern.

Voraussetzungen

Achtung: es kann sein, dass durch dieses Prozedere streng genommen der Support erlischt. Wir betrachten den Prozess trotzdem als ausgesprochen sicher und harmlos.

Voraussetzung für das Folgende ist, dass der ssh-Zugang der UTM freigeschaltet ist. Das Login als loginuser genügt für die automatischen Updates; root-Zugriff brauchen Sie nur einmalig während der Einrichtung. Auch ein wenig Wissen über die Scriptsprache Perl schadet nicht. Getestet haben wir das Ganze mit der UTM-Firmware-Version 9.407-3.

Weiterhin gehe ich davon aus, dass Sie Ihren gewünschten Let’s Encrypt-Client schon konfiguriert und ausprobiert haben. Anschließend müssen Sie einmalig ein Let’s Encrypt-Zertifikat via Webinterface in die UTM hochladen. Dazu muss man es erst einmal in ein .p12 konvertieren. Das geht auf verschiedene Arten; hier kurz und knapp eine davon:

openssl pkcs12 -export -out lets-encrypt.p12 \
  -in fullchain.pem -inkey privkey.pem -CAfile chain.pem

UTM-Konfiguration

Eine Sophos UTM verwaltet intern alles als Konfigurationsobjekte — sei es ein Host-Eintrag, eine Firewallregel oder auch ein hochgeladenes SSL-Zertifikat. Diese Objekte werden von einem zentralen Konfigurations-Dämonen verwaltet. Wird ein Objekt verändert (z.B. die IP-Adresse eines Host-Objektes), so triggert der Dämon automatisch alle dafür notwendigen Aktionen (z.B. die nötigen Anpassungen an den Firewallregeln, in denen das Host-Objekt benutzt wird).

Um mit diesem Dämon zu kommunizieren, gibt es zum einen ein Kommandozeileninterface namens cc, zum anderen aber auch Perl-Module. Die Benutzung des Perl-Interfaces ist denkbar einfach und sieht so aus (ohne jegliche Fehlerbehandlung):

# Modul laden:
use Astaro::ConfdPlRPC;

# Interface-Objekt erstellen und gegen zeitgleiche Änderungen sperren:
my $sys = Astaro::ConfdPlRPC->new;
$sys->lock;

# Ein Objekt auslesen:
my $reference = "REF_LookBelowToSeeHowToDetermineThisName";
my $object    = $sys->get_object($reference);

# Das Objekt ist ein einfaches Hash. Direkt modifizieren:
$object->{data}->{comment} = "Astaro ASG is now Sophos UTM!";

# Speichern und alle vorgenommenen Änderungen auch wirklich anwenden:
$sys->set_object($object);
$sys->commit;

# Abmelden:
$sys->disconnect;

Zertifikatsobjekte

Damit haben wir eine Basis. Was man nun wissen muss:

  • Jedes Objekt hat eine eindeutige Referenz, die immer mit REF_… beginnt.
  • Jedes Zertifikat ist ein Objekt. Dabei enthält das Zertifikatsobjekt auch gleich schon den dazugehörigen Schlüssel. Zertifikat und Schlüssel werden beide im PEM-Format abgelegt.
  • Wird ein Intermediate-Zertifikat genutzt, so ist natürlich auch das Intermediate-Zertifikat ein eigenes Objekt. Bei Let’s Encrypt, dessen Wurzelzertifikat noch nicht überall vorhanden ist aber dafür von einer anderen bekannten Zertifikatsstelle unterschrieben wurde, wird das Wurzelzertifikat de facto wie ein Intermediate-Zertifikat behandelt und mitgeschickt.
  • Zu jedem Zertifikatsobjekt gibt es ein Meta-Objekt, das menschenlesbare Informationen zu dem Zertifikat enthält. Diese werden z.B. im Webinterface in den Zertifikatslisten angezeigt: Ablaufdatum, DN etc.

Wir benötigen also die Referenzen von vier Objekten: für das Zertifikat, für das Intermediate-Zertifikat sowie für die jeweils dazugehörigen Meta-Informationen. Glücklicherweise sind die Referenzen der Meta-Objekte in den Zertifikatsobjekten bereits aufgeführt, sodass wir doch nur zwei Referenzen heraussuchen müssen.

Das geht mit dem Kommandozeilentool cc. Um sich alle Zertifikatsobjekte für Endpunkte (also keine Intermediates, keine CAs) anzeigen zu lassen, geben Sie auf der UTM folgendes ein (Achtung: dieses Auslesen muss als root erfolgen):

cc get_objects ca host_key_cert

Suchen Sie aus der Liste dasjenige heraus, das Sie vorher hochgeladen haben. Aus der Datenstruktur benötigen Sie das Feld ref. Wenn Ihre Ausgabe also grob so aussieht …

          {
            'autoname' => 0,
            'class' => 'ca',
            'data' => {
                        'ca' => 'REF_CaVerBunkuVerifCa',
                        'certificate' => '-----BEGIN CERTIFICATE-----
…
-----END CERTIFICATE-----
',
                        'comment' => '',
                        'encrypted' => 0,
                        'key' => '-----BEGIN PRIVATE KEY-----
…
-----END PRIVATE KEY-----
',
                        'meta' => 'REF_CaMetCnbunkuste',
                        'name' => 'Let\'s Encrypt'
                      },
            'hidden' => 0,
            'lock' => '',
            'nodel' => '',
            'ref' => 'REF_CaHosLetsEncryp',
            'type' => 'host_key_cert'
          }

… so lautet die Objektreferenz REF_CaHosLetsEncryp.

Das gleiche machen wir noch einmal für das Intermediate-Zertifikat. Diese lassen sich mit cc get_objects ca verification_ca auflisten. Suchen Sie nach einem Objekt mit Namensfeld Let's Encrypt Verification CA 1. Bei mir hat es die Referenz REF_CaVerLetsEncryVerif.

Eigentliche Zertifikatsaktualisierung

Die eigentliche Aktualisierung ist nun nichts weiter als Fleißarbeit bei Nutzung der angesprochenen Perl-Schnittstelle. Zuerst liest man die Zertifikatsdateien aus, lässt sich vom Konfigurations-Dämonen die Objekte zu den oben herausgesuchten Referenzen geben, aktualisiert die ganzen Felder und schreibt sie wieder zurück. Gerade für die Meta-Objekte ist das relativ viel Gefummele. Daher habe ich das ganze in einem Perl-Script zusammengefasst, das Sie unten herunterladen können.

Der Aufruf des Scripts erfordert nun keine Root-Rechte mehr; hierfür genügt der loginuser. Sie müssen fünf Parameter angeben:

  1. Objektreferenz des Zertifikatsobjekts
  2. Dateiname des neues Zertifikats
  3. Dateiname des dazugehörigen Schlüssels
  4. Objektreferenz des Intermediate-Objekts
  5. Dateiname des Intermediate-Zertifikats

In Summe sieht das so aus:

./utm_update_certificate.pl \
  REF_CaHosLetsEncryp cert.pem privkey.pem \
  REF_CaVerLetsEncryVerif chain.pem

Die Ausgabe zeigt, ob etwas getan wurde. Wurden Zertifikate aktualisiert, so beginnt die Ausgabe mit UPDATE:. War hingegen nichts zu tun, weil die existierenden Zertifikate bereits mit den neuen übereinstimmten, so beginnt die Ausgabe mit OK:.

Einbinden in den Let’s Encrypt-Prozess

Wie man das nun in den Let’s Encrypt-Prozess einbindet, hängt von vielen Faktoren ab: welcher Client wird eingesetzt, welche Authentifizierungsmethode wird genutzt etc. Daher zeige ich das hier nicht konkret.

Entscheidend ist, dass nach dem Ausstellen eines neuen Zertifikats die folgenden Schritte ausgeführt werden:

  • Neue Zertifikatsdateien mittels scp auf UTM kopieren
  • Script mittels scp auf UTM kopieren
  • Via ssh an UTM anmelden und Script ausführen

All das kann man problemlos scripten. Nutzt man z.B. den Client dehydrated mit einem Shell-Hook-Script, so würde man die Befehle in der Funktion deploy_cert unterbringen.

Download

Das Script utm_update_certificate.pl ist auf Github verfügbar und unter den Bedingungen der MIT License lizensiert.