OpenSSH PKI

vorhergehende Artikel in: Linux Security
25.06.2025

Ich habe ja bereits eine kleine Präsentation zum Thema PKI und OpenSSH verfasst - hier folgt nun - mit einigen Links zu externen Ressourcen zu diesem Thema angereichert - eine strukturierte Zusammenfassung diverser Use Cases und deren Lösung mit einer OpenSSH PKI

Ich werde auch immer mal wieder zu der Konkurrenz - x509-Zertifikate - verweisen, um Unterschied, Gemeinsamkeiten und verwandte Konzepte herauszuarbeiten.

Wie auch bei x509-Zertifikaten kann es nützlich sein, verschiedene CAs für unterschiedliche Themengebiete - etwa Host- und User-CAs - zu betreiben oder die Verantwortlichkeit entlang anderer Kriterien zwischen mehreren CAs aufzuteilen.

So könnte es unter Umständen möglich sein, mehrere User-CAs zu betreiben, um auf diese Art und Weise Nutzern nur Rechte für den Zugriff auf bestimmte Gruppen von Hosts zu ermöglichen: Nutzer können sich in diesem Szenario nur mit Hosts verbinden, die der jeweiligen CA vertrauen, die das Nutzerzertifikat ausgestellt hat. Das ist mit OpenSSH problemlos möglich, da man beim Connect oder in der Konfiguration hostspezifische digitale Identitäten zur Benutzung spezifizieren kann.

Ein weiterer Weg für so etwas wäre die Benutzung nur einer User-CA aber die Kontrolle über den Zugang zu einzelnen Hosts gesteuert über die Principals zu nutzen: Wie die Subject Alternative Names von x509-Zertifikaten erlauben es SSH-Zertifikate, mehrere Principals anzugeben. Diese Principals können als Gruppennamen benutzt und die Hosts so konfiguriert werden, dass nur Nutzer, deren Zertifikate bestimmte Principals aufweisen sich verbinden dürfen.

Darüber hinaus sind auch weitere Restriktionen in den Zertifikaten möglich - etwa Einschränkungen, von welchem Gerät aus sie sich anmelden können source-address oder welches Kommando sie ausführen dürfen force-command.

Ein Tip noch zum Verwalten solcher PKIs: Nutzen Sie einen ssh-agent!

Beginnen wir also damit, uns zunächst einige Verzeichnisse zu kreieren:

mkdir -p openssh-pki/{user-ca/work,host-ca/work} && cd openssh-pki

Wir erzeugen zunächst die digitalen Identitäten für die CAs:

cd host-ca && ssh-keygen -t rsa -b 4096 -f host_ca -C host_ca && cd ..
cd user-ca && ssh-keygen -t rsa -b 4096 -f user_ca -C user_ca && cd ..

Zu Testzwecken richten wir nun zwei unprivilegierte LXC-Container ein - target wird als Host agieren, mit dem sich user von client aus verbinden:

lxc-create -n target -t download -- -d ubuntu -r focal -a amd64
lxc-create -n client -t download -- -d ubuntu -r focal -a amd64

Ich benutze hier eine etwas ältere Version weil LXC neuere Ubuntu-Versionen nicht als unprivilegierte Container starten mag - aber das ist ein Kampf für einen anderen Tag!

Beide Container müssen gestartet werden:

lxc-unpriv-start -n target
lxc-unpriv-start -n client

Für diese spezielle Geschmacksrichtung muss nun für den Standardnutzer ubuntu noch ein Passwort gesetzt werden. Zusätzlich wird auf target der openssh-server installiert.

Nun wird der public key aus target nach openssh-pki/host-ca/work kopiert und signiert:

cd host-ca/work && ssh-keygen -s ../host_ca -I target -h -n target  ssh_host_rsa_key.pub && cd ../../

Das Zertifikat wird auf den Host zurückkopiert und in /etc/ssh/sshd_config entsprechend seine Nutzung konfiguriert:

HostCertificate /etc/ssh/ssh_host_rsa_key-cert.pub

Nach einen Neustart des Service mittels

systemctl restart sshd

Kann man sich nun an die Konfiguration des client machen: Dort einfach die Datei _~/.ssh/known_hosts komplett leeren und @cert-authority target ` einfügen - gefolgt vom Inhalt von host_ca.pub.

Nun kann man sich von client aus zu target verbinden und wird nicht mehr mit lästigen Nachfragen nach Fingerprints belästigt - sein Passwort muss man aber schon noch eingeben. Das wird im nächsten Schritt behoben - zunächst wird eine digitale Identität auf client erzeugt:

ssh-keygen -f user-key -b 4096 -t rsa

Anschließend wird der public key an die User-CA übergeben und dort erfolgt die Erstellung des Zertifikats:

cd user-ca/work && ssh-keygen -s ../user_ca -I ubuntu@client -n ubuntu -V +1d user-key.pub && cd ../../

Das erzeugte Zertifikat wird wieder zurück auf client übertragen.

Den Inhalt eines solchen Zertifikats kann man sich übrigens mittels ssh-keygen -L -f user-key-cert.pub ansehen - als Ergebnis kommt dann in etwa so etwas heraus:

user-key-cert.pub:
        Type: ssh-rsa-cert-v01@openssh.com user certificate
        Public key: RSA-CERT SHA256:t+7TgKrt2qgy8vmPbfc2rL1VeHtH+uUJxZ7AEdwgWpE
        Signing CA: RSA SHA256:tqyYd6Rfvx7vI+L0+L/qzM5NyYh/J7fy13lJHB4N6P0 (using rsa-sha2-512)
        Key ID: "ubuntu@client"
        Serial: 0
        Valid: from 2025-04-23T12:55:00 to 2025-04-24T12:56:28
        Principals: 
                ubuntu
        Critical Options: (none)
        Extensions: 
                permit-X11-forwarding
                permit-agent-forwarding
                permit-port-forwarding
                permit-pty
                permit-user-rc

Nachdem das Zertifikat auf den client zurückkopiert wurde, muss dem target nun noch mitgeteilt werden, dass er von dieser CA ausgestellten Zertifikaten vertrauen darf - dazu muss der public key der CA auf target kopiert werden - zum Beispiel nach /etc/ssh/ und eine entsprechende Zeile zu /etc/ssh/sshd_config hinzugefügt werden:

TrustedUserCAKeys /etc/ssh/user_ca.pub

Startet man sshd auf target danach neu, kann man beim Aufbau der Verbindung mittels -i die Digitale Identität angeben, die man zum Verbindungsaufbau nutzen möchte. Setzt man nun noch auf dem target die Option PasswordAuthentication no, so können sich nur noch Nutzer an target anmelden, die ein gültiges Zertifikat unserer User-CA vorweisen können.

Oh - und ich hatte ja vorhin erwähnt, dass noch die eine oder andere Konfiguration für SSH vorgenommen werden kann, indem Optionen ähnlich den Extensions bei x509-Zertifikaten konfiguriert werden - so würde etwa ein Zertifikat, das mittels dieses Kommandos erzeugt würde:

ssh-keygen -s ../user_ca -I ubuntu@client -n ubuntu -O force-command="top" -V +1d user-key.pub

Die Auswirkung, dass der Nutzer sich zwar authentifizieren könnte, aber danach keine interaktive Shell für ihn gestartet würde, sondern die applikation top.

Bliebe noch das Szenario zu adressieren, mehrere Principals in einem Zertifikat zu vereinen. Dazu legen wir auf target zunächst einen weiteren Nutzer an:

useradd -m ubuntu2
<pre>#[[

Versucht man sich von <span class="mdcode">client</span> aus als dieser neue Nutzer zu verbinden, wird dieser Versuch abgewiesen. Stellen wir also nun ein neues Zertifikat aus: <pre>#[[.sh ssh-keygen -s ../user_ca -I ubuntu@client -n ubuntu,allowed_group -V +1d user-key.pub

Nachdem dieses wieder an Nutzer ubuntu auf client übergeben wurde erhält er zwar beim Anmelden als ubuntu auf target wieder eine interaktive Shell, kann sich aber nicht als ubuntu2 dort anmelden. Das ändert sich erst, wenn ein solches Mapping durch

mkdir /etc/ssh/auth_principals/
echo "allowed_group" > /etc/ssh/auth_principals/ubuntu2

und Hinzufügen von

AuthorizedPrincipalsFile /etc/ssh/auth_principals/%u

in /etc/ssh/sshd_config auf target und Neustart des Service aktiviert wird.

Wichtig ist dabei, dass für jeden Nutzer, der sich fürderhin verbinden soll eine solche Datei in /etc/ssh/auth_principals/ vorhanden sein muss - um sich also weiterhin auch mit dem Konto ubuntu verbinden zu können beaucht es noch ein

echo "allowed_group" > /etc/ssh/auth_principals/ubuntu2

Weiterhin ist zu beachten, dass SSH sehr pingelig ist, was die Rechte dieses Verzeichnises und der darin enthaltenen Dateien angeht. Also sicherheitshalber noch

chmod 755 /etc/ssh/auth_principals
chmod 644 /etc/ssh/auth_principals/*

vor Neustart des sshd ausführen!

Alle Artikel rss Wochenübersicht Monatsübersicht Codeberg Repositories Mastodon Über mich home xmpp


Neueste Artikel

  • Compartmentalization and Privilege Drop

    Eine Präsentation zum besseren Verständnis einiger Konzepte sicherer Softwareentwicklung

    Weiterlesen
  • Der Gumowski-Mira Attractor

    Und wieder habe ich mich mit einem System beschäftigt, das sich in die Themen Chaos und Fraktale oder Strange Attractors einordnen lässt.

    Weiterlesen
  • OpenGrok neu im Docker-Zoo

    Ich habe meinen Docker-Zoo wieder um ein Exemplar bereichert: Nachdem ich neulich über LXR bzw. seine Inkarnation zum Stöbern im Linux-Quelltext gestlpert bin habe ich mich daran erinnert, dass ich so etwas schon immer mal für meine diversen Quelltextprojekte haben wollte.

    Weiterlesen

Manche nennen es Blog, manche Web-Seite - ich schreibe hier hin und wieder über meine Erlebnisse, Rückschläge und Erleuchtungen bei meinen Hobbies.

Wer daran teilhaben und eventuell sogar davon profitieren möchte, muss damit leben, daß ich hin und wieder kleine Ausflüge in Bereiche mache, die nichts mit IT, Administration oder Softwareentwicklung zu tun haben.

Ich wünsche allen Lesern viel Spaß und hin und wieder einen kleinen AHA!-Effekt...

PS: Meine öffentlichen Codeberg-Repositories findet man hier.