Skip to content
scalewerk.io:~#
  • Blog
ssh · 06 September 2024

Zer­tifi­kats­basier­te SSH-Authen­ti­fi­zie­rung

Der letzte Blogpost Interne Certificate Authority mit Step-Ca behandelte den Aufbau einer Zertifikatsverwaltung mittels Step-CA. Nachdem die Step-CA nun erfolgreich aufgesetzt wurde und wir mit dieser Zertifikate ausstellen können, können wir auch gleich ein weiteres Problem angehen: Die Authentifizierung von Usern und Hosts im Kontext von SSH-Verbindungen.

Obwohl eine Step-CA hierfür nicht zwingend erforderlich ist, da eine zertifikatsbasierte Authentifizierung für SSH auch problemlos mit den Standardwerkzeugen von OpenSSH umgesetzt werden kann, vereinfacht die Step-CA die Verwaltung und Einrichtung in einigen Punkten.

Das folgende docker-compose Setup baut auf der bestehenden Step-CA-Umgebung auf, erweitert das bestehende Setup jedoch um zwei zusätzliche Secrets und einen weiteren Initialisierungs-Container. Die Aufgabe dieses Containers besteht darin, sicherzustellen, dass die Step-CA (im Container) dieselben Host- und Benutzerzertifikate verwendet wie der Host selbst.


version: "3.7"

name: step-ca

volumes:
  step-ca-data:

networks:
  step-ca-net:

secrets:
  init_secret:
    file: ./init_secret.txt
  ca_private_host_key:                   # privater Key des Hosts
    file: /etc/ssh/ssh_host_ecdsa_key
  ca_private_user_key:
    file: /etc/ssh/ssh_user_ecdsa_key

services:
  step-ca:
    container_name: step-ca
    image: smallstep/step-ca:0.27.2
    volumes:
      - step-ca-data:/home/step
    command:
    secrets:
      - init_secret
    environment:
      DOCKER_STEPCA_INIT_PASSWORD_FILE: /run/secrets/init_secret
      DOCKER_STEPCA_INIT_NAME: ca.example.com
      DOCKER_STEPCA_INIT_DNS_NAMES: localhost,192.168.xxx.xxx,ca.example.com
      DOCKER_STEPCA_INIT_REMOTE_MANAGEMENT: true
      DOCKER_STEPCA_INIT_PROVISIONER_NAME: admin
      DOCKER_STEPCA_INIT_SSH: true
      DOCKER_STEPCA_INIT_ACME: true
    ports:
      - 9000:9000
    networks:
      - step-ca-net

  step-ca-ssh-setup:
    container_name: step-ca-ssh-setup
    image: docker:latest
    volumes:
      - step-ca-data:/home/step
      - /var/run/docker.sock:/var/run/docker.sock
      - ./docker-compose.yaml:/docker-compose.yaml
    secrets:
      - ca_private_host_key
      - ca_private_user_key
    depends_on:
      - step-ca
    restart: no
    entrypoint: ["sh", "-c", "sleep 1 \
                  && cat /run/secrets/ca_private_host_key > /home/step/secrets/ssh_host_ca_key \
                  && cat /run/secrets/ca_private_user_key > /home/step/secrets/ssh_user_ca_key \
                  && docker compose restart step-ca" ]

Standardmäßig verwendet Step-CA für die Signatur den internen privaten Host-Schlüssel des Containers.
Um sicherzustellen, dass die Signatur mit Step durchgeführt wird und die anschließende Zertifikatsvalidierung gegen den Host erfolgreich ist, nutzen wir den Host-Schlüssel für die Signierung:

step ssh certificate --host --sign foo.example.com /etc/ssh/ssh_host_ecdsa_key.pub

Dabei wird das signierte Zertifikat unter

/etc/ssh/ssh_host_ecdsa_key-cert.pub

auf dem Host gespeichert.

Zusätzlich müssen wir SSHD so konfigurieren, dass das signierte Host-Zertifikat vom Host zur Verifizierung herangezogen wird:

In /etc/ssh/sshd_config ergänzen:

HostCertificate /etc/ssh/step-ca/ssh_host_ca_key-cert.pub

Restart von SSHD:

systemctl restart sshd

Nun können wir dem Client mitteilen, dass er dem Host-Zertifikat vertrauen soll:

PUB_CERT=$(step ssh config --host --roots)

Für den Benutzer:

echo "@cert-authority * ${PUB_CERT}" >> ~/.ssh/known_hosts

Oder Systemweit:

echo "@cert-authority * ${PUB_CERT}" | sudo tee -a /etc/ssh/ssh_known_hosts

Anschließend ist es möglich, sich per SSH zu verbinden, wobei standardmäßig allen von der Host-CA ausgestellten Host-Zertifikaten vertraut wird. Dadurch entfallen die Warnmeldungen über unbekannte Hosts:

ssh test.foobar.com
Authentifikation über signierte User Zertifikate

Um die Authentifizierung mittels Benutzerzertifikaten zu ermöglichen, sind noch folgende Anpassungen erforderlich:

1. Den SSH-Daemon über die /etc/ssh/sshd_config so konfigurieren, dass Benutzerzertifikate gegen die Benutzer-CA validiert werden:


HostKey /etc/ssh/ssh_host_ecdsa_key
HostCertificate /etc/ssh/ssh_host_ecdsa_key-cert.pub

Restart von SSHD:

systemctl restart sshd

2. Ein SSH-Keypair erzeugen und mit der CA signieren:

step ssh certificate --ca-url https://foo.example.com:9000 john@foo.example.com id_ecdsa --principal john

Um existierende Keys neu zu signieren:

step ssh certificate --ca-url=https://foo.example.com:9000 john@foo.example.com id_ecdsa.pub --sign --private-key=id_ecdsa --principal john

3. Das generierte Zertifikat validieren:

ssh-keygen -Lf id_ecdsa-cert.pub

4. Optional: einen passenden Eintrag in der ~/.ssh/config anlegen:

Host foobar
     HostName foo.example.com
     User john
     IdentityFile ~/.ssh/id_ecdsa
     CertificateFile ~/.ssh/id_ecdsa-cert.pub

Impressum - Datenschutz - © 2025 scalewerk.io GmbH