Zum Inhalt springen
Europe/Berlin
--:--:--

Vault SSH-Zertifikate: 4 Schritte zum sicheren Backend

October 17, 2026

In fast jeder gewachsenen Linux-Infrastruktur findet sich dasselbe Sicherheitsrisiko: der Wildwuchs von ~/.ssh/authorized_keys. Entwickler hinterlassen ihre Public Keys auf Entwicklungs-, Staging- oder gar Produktivsystemen. Verlässt ein Mitarbeiter das Team, gerät das Bereinigen dieser Schlüssel schnell in Vergessenheit. Was bleibt, sind verwaiste Hintertüren und mangelnde Nachvollziehbarkeit bei Audits.

OpenSSH bietet bereits seit Version 5.4 eine native, kryptografisch saubere Lösung: SSH-Zertifikate. Kombiniert man dieses Feature mit der SSH Secrets Engine von HashiCorp Vault, lässt sich der Zugriff auf Linux-Instanzen vollständig zustandslos, zeitlich befristet und zentral auditiert gestalten.

Klassische Public-Key-Authentifizierung vergleicht den privaten Schlüssel des Clients mit dem auf dem Server hinterlegten öffentlichen Schlüssel. Das bedeutet State auf dem Zielsystem: Jede Maschine muss wissen, wer autorisiert ist.

Eine SSH-Zertifizierungsstelle (Certificate Authority, CA) dreht dieses Modell um:

  1. Der Zielserver kennt ausschließlich den öffentlichen Schlüssel der Vault-CA (TrustedUserCAKeys).
  2. Ein Entwickler generiert lokal ein Schlüsselpaar und schickt den Public Key an Vault.
  3. Vault validiert die Identität (z. B. via OIDC, Okta oder GitHub) und signiert den Schlüssel mit einer kurzen Time-To-Live (TTL), typischerweise zwischen 5 und 60 Minuten.
  4. Der SSH-Daemon (sshd) auf dem Server verifiziert beim Login lediglich die Signatur gegen den hinterlegten CA-Schlüssel und prüft, ob die Zertifikatsattribute (Principals, Gültigkeitsdauer) mit der Anfrage übereinstimmen.

Der Zielserver muss weder Vault kontaktieren noch lokale Schlüsseldateien verwalten. Das System ist vollkommen zustandslos. Ein Certificate Revocation List (CRL) Management entfällt in der Praxis komplett: Läuft ein Zertifikat nach 15 Minuten ab, schließt sich das Zugriffsfenster automatisch.

Ein immenser Vorteil gegenüber statischen Schlüsseln ist die Compliance-Transparenz. Im Audit-Log von Vault ist exakt protokolliert, welcher Identity Provider User (z. B. j.doe@company.internal) zu welchem Zeitpunkt ein Zertifikat für welche Linux-Accounts (principals) signieren ließ. Selbst wenn auf dem Server ein geteilter Account wie ubuntu oder deploy genutzt wird, bleibt die auslösende reale Person im Vault-Log eindeutig identifizierbar.

Oft stellt sich bei der Evaluierung die Frage, welches Werkzeug das richtige ist:

  • HashiCorp Vault: Agiert rein als signierende CA. Es gibt keinen Proxy-Zwang. Der SSH-Traffic fließt direkt vom Client zum Zielhost. Das bedeutet null Netzwerklatenz-Overhead und minimale Infrastrukturkomplexität, sofern Vault ohnehin für Secrets-Management genutzt wird.
  • Teleport: Bietet ein ganzheitliches Access-Management inklusive Bastion-Hosts, Session-Recording auf Video-Ebene und Web-UI. Dafür bringt Teleport signifikanten operativen Overhead, proprietäre Proxy-Komponenten und höhere Lizenzen mit sich.
  • HashiCorp Boundary: Fungiert primär als identitätsbasierter TCP-Proxy. Boundary übernimmt die Authentifizierung am Proxy und tunnelt Verbindungen, signiert im Standardfall jedoch keine OpenSSH-Zertifikate, sondern leitet reine TCP-Sessions weiter.

Für Backend- und Plattform-Teams, die native SSH-Workflows bevorzugen und keine Bastion-Proxies verwalten wollen, ist Vault die leichtgewichtigste und performanteste Wahl.

Zuerst aktivieren wir die SSH-Engine unter einem separaten Pfad, generieren einen modernen Ed25519-Signaturschlüssel und hinterlegen eine Rolle für Entwickler-Zugriffe:

Bash
vault secrets enable -path=ssh-client-signer ssh

vault write ssh-client-signer/config/ca generate_signing_key=true key_type=ed25519

vault write ssh-client-signer/roles/dev-access \
    allowed_users="ubuntu,ec2-user" \
    default_user="ubuntu" \
    ttl="30m" \
    max_ttl="60m" \
    allow_user_certificates=true \
    allowed_critical_options="source-address"

Auf den Zielservern laden wir einmalig den öffentlichen Schlüssel der Vault-CA herunter, tragen ihn in /etc/ssh/sshd_config ein und laden den Daemon neu:

Bash
curl -s https://vault.internal:8200/v1/ssh-client-signer/public_key > /etc/ssh/trusted-user-ca-keys.pem
chmod 644 /etc/ssh/trusted-user-ca-keys.pem

echo -e "TrustedUserCAKeys /etc/ssh/trusted-user-ca-keys.pem\nAuthorizedPrincipalsFile /etc/ssh/auth_principals/%u" >> /etc/ssh/sshd_config
systemctl reload sshd

Liegt unter /etc/ssh/auth_principals/ubuntu eine Liste erlaubter Rollen (oder man konfiguriert Vault so, dass der Zielbenutzer direkt als Principal im Zertifikat landet), akzeptiert der Server ab sofort gültige Signaturen.

Ein Entwickler kann seinen bestehenden SSH-Schlüssel nun signieren lassen und sich sofort verbinden:

Bash
vault write -field=signed_key ssh-client-signer/sign/dev-access \
    public_key=@$HOME/.ssh/id_ed25519.pub > $HOME/.ssh/id_ed25519-cert.pub

ssh -i $HOME/.ssh/id_ed25519-cert.pub -i $HOME/.ssh/id_ed25519 ubuntu@target.host.internal

Kein Entwickler möchte vor jedem SSH-Aufruf manuell Vault-Befehle tippen. Mittels OpenSSH Match exec in der lokalen ~/.ssh/config lässt sich das Signieren völlig transparent automatisieren:

Ssh-config
Host *.internal !vault.internal
    Match exec "vault token lookup >/dev/null 2>&1 && vault write -field=signed_key ssh-client-signer/sign/dev-access public_key=@%d/.ssh/id_ed25519.pub > %d/.ssh/id_ed25519-cert.pub"
    CertificateFile ~/.ssh/id_ed25519-cert.pub
    IdentityFile ~/.ssh/id_ed25519

Sobald ein Entwickler ssh ubuntu@app-01.internal eingibt, prüft SSH, ob ein aktiver Vault-Token existiert, signiert den lokalen Public Key in Millisekunden und baut die Verbindung mit dem frischen Zertifikat auf.

Vault-Rollen können Restriktionen direkt in das Zertifikat einbacken, die der Server kryptografisch validiert und erzwingt:

  • Source-Address (CIDR): Begrenzt die Gültigkeit des Zertifikats auf IP-Bereiche (z. B. VPN-Netze).
  • Force-Command: Erzwingt ein bestimmtes Skript oder Kommando beim Verbindungsaufbau.
  • Port-Forwarding & PTY: Forwarding oder interaktive Terminals lassen sich für automatische Deployment-Rollen explizit unterbinden.

Ein häufiger Produktionsfehler: Teams setzen sehr aggressive TTLs ein (z. B. 2 Minuten), um das Angriffsfenster zu minimieren. Weichen die Systemuhren von Client, Vault-Instanz und Zielserver nur um 90 Sekunden voneinander ab, schlägt die Verbindung mit Certificate not yet valid oder Certificate has expired fehl. Eine saubere NTP-Synchronisation (via chrony oder systemd-timesyncd) ist auf allen Knoten zwingend erforderlich.

Das Prinzip funktioniert auch umgekehrt: Neben Client-Zertifikaten kann Vault auch die Host-Keys deiner Server signieren (Host CA). Indem Entwickler und Bastion-Hosts einmalig den Host-CA-Public-Key in ihrer globalen known_hosts hinterlegen (@cert-authority *.internal ssh-ed25519 AAAAC3...), gehören Host Key Verification Failed-Warnungen in dynamischen Auto-Scaling-Groups endgültig der Vergangenheit an. Neu provisionierte Instanzen erhalten bei der Initialisierung ihr Host-Zertifikat und werden von Clients ohne Fingerprint-Prompt sofort verifiziert.

  1. CA etablieren: Vault SSH Secrets Engine aufsetzen und Rollen definieren.
  2. Zielsysteme bestücken: TrustedUserCAKeys via Ansible, Puppet oder Cloud-Init auf allen Maschinen ausrollen.
  3. Dual-Betrieb fahren: Sowohl alte SSH-Keys als auch neue Vault-Zertifikate erlauben, während Entwickler ihre Workflows auf die Vault-CLI bzw. SSH-Config umstellen.
  4. Altlasten eliminieren: authorized_keys global abschalten, indem in der sshd_config AuthorizedKeysFile /dev/null gesetzt wird.

Damit ist dein Backend vollständig gegen kompromittierte statische Keys geschützt und erfüllt mühelos strikte Compliance-Vorgaben.

Wenn du deine Server-Infrastruktur auf kurzlebige Zertifikate umstellen oder deine Backend-Sicherheit auditieren möchtest, unterstützt dich Büngener Software gerne bei Konzeption und Umsetzung.