SSH Host Key Signing - ein unterschätztes Feature

Rudolph
19.12.2017 3 7:06 min

Da wir eine größere Menge an Linux Servern betreiben, ist SSH unser tägliches Brot. Sei es nun für den Login mit dem eigenen Benutzer oder für auf SSH aufsetzende Automatisierungen, wie zum Beispiel Ansible. Was nun jeder SSH Anwender aber kennt: der ewige “Kampf” mit der known_hosts Datei, in der alle dem Clients bereits bekannten Public SSH Host Keys abgelegt werden. Wenn sie noch nicht dort liegen, stolpert man über eine interaktive Nachfrage (der Feind jeglicher Automatisierung) und wenn das Ziel zum Beispiel neu aufgesetzt wurde, gibt es sogar einen Konflikt, der eher umständlich aufgelöst werden muss. Im Falle von Ansible Playbooks oder Git Operationen kann das bedeuten, dass Befehle unerwartet abbrechen, mit Rückfragen stehen bleiben oder aber einfach in einen Timeout laufen, weil die Rückfrage gar nicht bis zum Benutzer durchkommt. Dann ist da auch noch die Frage, in welcher Form ein “conflicting” Public Host Key in der known_hosts hinterlegt ist: mit einer IP Adresse, einem Hostnamen oder einem Hash davon als Identifier? Für einfache Aufräumarbeiten gibt die entsprechende Fehlermeldung des ssh Clients immerhin direkt das passende, copy/paste-bare Kommando (ssh-keygen -R […]) mit aus.

Für das Problem gibt es verschiedene Lösungen, die sich grob in “The Good” (zum Beispiel SSH Host Key Signing), “The Bad” (known_hosts Management) und “The Ugly” (Host Key Checking abschalten?!) einteilen lassen. Die letzte Variante ignorieren wir hier einmal, weil das für uns schlicht keine Option ist.

“managed” known_hosts

Bevor wir SSH Host Key Signing entdeckt haben, hat Ansible uns in Teilen geholfen. Beim initialen Setup eines Servers haben wir über delegate_to Tasks dafür gesorgt, dass auf bestimmten, für Configuration Management/Deployment relevanten Systemen, die known_hosts Dateien einiger Benutzer um die Public Host Keys des neuen Servers erweitert wurden. Das funktioniert allerdings immer nur so lange automatisch, bis ein Server mal neu aufgesetzt wird und dann am Ende zwei Keys für das gleiche Ziel in der known_hosts landen – schon musste wieder händisch eingegriffen wird. Bevor wir die vorhandene Lösung noch komplizierter machen mussten, sind wir zum Glück über das folgende Thema gestolpert:

SSH Host Key Signing

OpenSSH beherrscht seit ca. 2010 ein Verfahren, um SSH Host Keys mit einer CA zu signieren. Es handelt sich dabei aber nicht um eine x509 CA, sondern um eine eigene Implementierung – sämtliche Interaktionen erfolgen über das Tool ssh-keygen.

Insgesamt sind folgende Schritte nötig, um an das Ziel zu gelangen:

  1. SSH CA erzeugen
  2. Neuen Server aufsetzen, Public Host Key(s) zur CA transferieren und signieren
  3. Signierte Public Key(s) auf neues System legen, in SSHD Konfiguration aktivieren
  4. Public Key der SSH CA in allen known_host Dateien (z.B. systemweit) hinterlegen

Die Schritte 2. und 3. sind für jeden neuen Server zu wiederholen und lassen sich relativ leicht mit Ansible automatisieren.

SSH CA erzeugen

Die CA kann auf einem beliebigen aktuellen Linux System erzeugt/betrieben werden – spezielle Anforderungen gibt es nicht. Da auf diesem System allerdings der Private Key der CA liegt, sollte es natürlich nicht gerade der öffentlich erreichbare Webserver sein, sondern schon ein dedizierter und entsprechend abgeschotteter Server. Seit OpenSSH 5.5 kann eine CA allerdings auch über PKCS#11 abgerufen werden – und damit zum Beispiel in einem Hardware Security Module (HSM) liegen. Dieser Blogpost beleuchtet aber die einfache Variante mit einer CA im Dateisystem.

Hier erzeugen wir nun unsere CA:

mkdir /etc/ssh-ca && cd /etc/ssh-ca
ssh-keygen -f server_ca

Jetzt signen wir damit zuerst mal den Public Host Key unseres CA Servers, dazu benötigen wir den Fully Qualified Domain Name des Servers in unserer $FQDN Variable und den Hostnamen (ohne Domain) in der Variable $HOSTNAME:

ssh-keygen -s server_ca -I ${FQDN}-host-key -h -n ${FQDN},${HOSTNAME} -V +52w /etc/ssh/ssh_host_ecdsa_key.pub

Durch den Parameter -V +150w geben wir an, dass das Zertifikat für 52 Wochen gültig sein soll, über -n wird mitgegeben, für welche(n) Hostnamen das Zertifikat gelten soll (hier nehmen wir mal den Fully Qualified Domain Namen sowie den kurzen Hostnamen an).

Der Vorgang erzeugt ein Host Zertifikat (oder auch genannt: ein signierter Public Key) in /etc/ssh/ssh_host_ecdsa_key-cert.pub. Dieses Zertifikat müssen wir jetzt noch dem SSHD in der /etc/ssh/sshd_config beibringen und ihn danach neustarten:

HostCertificate /etc/ssh/ssh_host_ecdsa_key-cert.pub

Wer neben ECDSA auch noch andere Host Key Varianten aktiviert hat, muss den Vorgang für diese Keys auch wiederholen (oder sie deaktivieren).

Public Keys eines neuen Servers signieren

Um nun die Host Keys eines neuen Servers zu signieren, greifen wir auf einige Schritte von weiter oben zurück. Wir kopieren den Public ECDSA Host Key (/etc/ssh/ssh_host_ecdsa_key.pub) auf unser SSH CA System, zum Beispiel nach /etc/ssh-ca/ssh_host_ecsd_key.pub. Anschließend führen wir den Sign-Befehl aus (auch hier benötigen wir wieder die beiden Variablen $FQDN und $HOSTNAME, nur dieses Mal bezogen auf das System, von dem der Key stammt):

ssh-keygen -s server_ca -I ${FQDN}-host-key -h -n ${FQDN},${HOSTNAME} 
-V +52w /etc/ssh-ca/ssh_host_ecdsa_key.pub

Das Ergebnis wird in /etc/ssh-ca/ssh_host_ecdsa_key-cert.pub liegen und kann zum Server zurück transferiert werden. Dort müssen wir es noch in der /etc/ssh/sshd_config aktivieren und den Dienst neustarten:

 HostCertificate /etc/ssh/ssh_host_ecdsa_key-cert.pub

Auch hier gilt: wenn mehr als eine Art von SSH Host Key benutzt wird (z.B. RSA), sollte man die Schritte für alle Keys wiederholen oder sie deaktivieren.

Und die Clients?

Jedes System, welches nun als SSH Client agieren soll, benötigt Zugriff auf die SSH-CA – dies geschieht auch über die known_hosts. Um das Deployment zu vereinfachen, kann man einfach eine systemweite known_hosts in /etc/ssh/ssh_known_hosts pflegen. Der Inhalt setzt sich aus zwei Teilen zusammen:

  1. Dem Prefix @cert-authority und einem Matcher auf einen Hostnamen (Wildcards sind möglich, wie in der ssh_config) – ein einzelnes “*” tuts auch, um die CA für sämtliche Clients anzuwenden
  2. Der Public Key unserer CA, der im SSH-CA Ordner unter dem Namen server_ca.pub erzeugt wurde

Das fertige Ergebnis könnte dann so aussehen:

 @cert-authority * ssh-rsa AAAADje9fnekjsld[...]

Das wars schon?

Tatsächlich ist das schon im großen und ganzen alles, was für eine SSH CA/SSH Host Key Signing notwendig ist. Es gibt natürlich auch andere Wege (z.B. über ein zentrales LDAP System). Wenn man diese Komplexität allerdings scheut, kommt man über die SSH CA sicherlich schneller zum Ziel – und alles ist besser, als Host Key Checking einfach zu deaktivieren, weil es an der Automatisierung hindert.

Gültigkeit von Zertifikaten

Wie bei allen Dingen mit einer endlichen Gültigkeit: man möchte natürlich seine SSH Zertifikate regelmäßig erneuern und/oder auf ihre Gültigkeit überwachen. Wenn man das nicht tut, resultiert das zwar unseren Tests nach per Default nur in einer Warnung beim Login, sauber ist das allerdings nicht.

Kann ich ein Zertifikat zurückziehen?

Wer Keys signed bzw. Zertifikate ausstellt, möchte diese eventuell auch wieder zurückziehen. Die bei OpenSSH KRL genannte “Key Revocation List” muss auf der SSH-CA gepflegt (mehr Details dazu in der Manpage von ssh-keygen) und auf alle Clients verteilt werden. Auf den Clients kann man sie über die Direktive RevokedHostKeys in der /etc/ssh/ssh_config systemweit aktivieren.

Wird jetzt alles gut?

Insgesamt kann man mit diesem Schritt Deployments/Config Management via SSH (lies: Ansible) deutlich stabiler machen. Das gleicht allerdings nicht zwingend andere Schwächen aus, die Mika Prokop hier jüngst mal zusammengestellt hat.

3 Kommentare


Peter:

Und damit läuft jetzt LTE? Ich finde es gar nicht gut, dass die Sachd so tot geschwiegen wird. Ich würde mir mal eine konkrete Aussage ob Ja, nein und warum wünschen. Ich denke, dass das jeder eurer Kunden wissen will.

Das beiseite, aber es musste sein. Vielen Dank für den Artikel.

antworten

Dashia:

Ich finde diesen Artikel einfach mal als SSH-Anwender (ob ins NW von unterwegs nach Hause oder zur Webspace-Administration) sehr gut, denn er trifft meine Problem, mit dem ich mich als Autodidakt auch herumschlage. Der Stil ist m.E. eine glueckliche Mischung aus Tech-Sprech und Anwendbarkeit.

Werd ich gleich mal mit Freunden teilen. Nein, nicht ueber FB-Tochter WA. Ueber Telegram.

antworten

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert