TL;DR — Kurzzusammenfassung

step-ca verwandelt jeden Server in eine private CA für internes TLS, mTLS und SSH-Zertifikate. Vollständige Anleitung zu Installation, Provisioners und ACME.

step-ca ist eine quelloffene private Zertifizierungsstelle von Smallstep, mit der du deine eigene PKI für internes TLS, mTLS zwischen Microservices und SSH-Zertifikate betreiben kannst, ohne Datenverkehr an eine öffentliche CA zu senden. Wenn du jemals Probleme mit Let’s Encrypt auf privaten Domains, Warnungen bei selbstsignierten Zertifikaten oder der Vertrauensverteilung über Dutzende von Diensten hattest, löst step-ca all das mit einem modernen, automatisierungsorientierten Design. Dieser Leitfaden umfasst den vollständigen Lebenszyklus: Warum du eine private CA brauchst, Architektur, Installation, Provisioner, ACME zur automatischen Erneuerung, SSH-Zertifikate und ein produktives HA-Deployment.

Warum eine Private CA?

Öffentliche CAs wie Let’s Encrypt erfordern Domain-Validierung über das öffentliche Internet. Das schließt sofort aus:

  • Interne Hostnamenpostgres.internal, api.corp oder jede .local- / .corp-Domain
  • mTLS für Microservices — mTLS erfordert, dass jeder Dienst ein Client-Zertifikat vorlegt; Tausende kurzlebige Service-Zertifikate von einer öffentlichen CA auszustellen ist unpraktisch und teuer
  • Zero-Trust-Netzwerke — jede Verbindung per Zertifikat authentifiziert, nicht durch Netzwerkposition
  • Air-gapped-Umgebungen — kein öffentlicher Internetzugang
  • Service Mesh ohne Sidecars — natives TLS zwischen Diensten mit step-ca-Zertifikaten vermeidet den Overhead eines vollständigen Istio- oder Linkerd-Deployments

step-ca schließt diese Lücke mit einem ACME-kompatiblen Server, kurzen Zertifikatslaufzeiten (standardmäßig 24 Stunden), automatischen Erneuerungs-Daemons und erstklassiger Kubernetes-Integration via autocert-Webhook und cert-manager step-issuer.

Architektur

┌─────────────────────────────────────────────┐
│              step-ca-Server                 │
│  ┌──────────┐  ┌─────────────┐              │
│  │ Root-CA  │→ │Intermediate-│              │
│  │(offline) │  │     CA      │              │
│  └──────────┘  └──────┬──────┘              │
│                       │ signiert            │
│  ┌────────────────────▼──────────────────┐  │
│  │            Provisioner                │  │
│  │  JWK │ ACME │ OIDC │ AWS │ K8sSA │…  │  │
│  └───────────────────────────────────────┘  │
└─────────────────────────────────────────────┘
         ↑ HTTPS-API (Port 9000)
    ┌────┴────┐
    │step CLI │  certbot  Caddy  Traefik  cert-manager
    └─────────┘

Die Root-CA signiert nur das Intermediate-CA-Zertifikat. In der Produktion wird der Root-CA-Schlüssel offline aufbewahrt. Die Intermediate-CA ist das, womit step-ca täglich arbeitet. Provisioner sind die Authentifizierungsmechanismen, die die Zertifikatsausstellung steuern.

Installation

Binär (Linux/macOS)

# step CLI
wget https://github.com/smallstep/cli/releases/latest/download/step_linux_amd64.tar.gz
tar xzf step_linux_amd64.tar.gz && sudo mv step /usr/local/bin/

# step-ca-Server
wget https://github.com/smallstep/certificates/releases/latest/download/step-ca_linux_amd64.tar.gz
tar xzf step-ca_linux_amd64.tar.gz && sudo mv step-ca /usr/local/bin/

macOS (Homebrew)

brew install step
brew install step-ca

Docker

docker run -v step:/home/step \
  -p 9000:9000 \
  -e "DOCKER_STEPCA_INIT_NAME=Interne CA" \
  -e "DOCKER_STEPCA_INIT_DNS_NAMES=ca.internal,localhost" \
  -e "DOCKER_STEPCA_INIT_REMOTE_MANAGEMENT=true" \
  smallstep/step-ca

Kubernetes (Helm + autocert)

helm repo add smallstep https://smallstep.github.io/helm-charts
helm install step-certificates smallstep/step-certificates \
  --set ca.name="Interne CA" \
  --set ca.dns="step-certificates.default.svc.cluster.local"

Ersteinrichtung: step ca init

step ca init \
  --name "Unternehmens-CA" \
  --dns ca.corp.internal \
  --address :9000 \
  --provisioner admin@corp.internal

Folgendes wird unter $(step path)/ erstellt:

  • certs/root_ca.crt — Root-CA-Zertifikat (an alle Clients verteilen)
  • certs/intermediate_ca.crt — Intermediate-Zertifikat
  • secrets/root_ca_key — privater Root-CA-Schlüssel (offline aufbewahren)
  • secrets/intermediate_ca_key — Intermediate-Schlüssel (vom Server genutzt)
  • config/ca.json — Serverkonfiguration

Server starten:

step-ca $(step path)/config/ca.json

Für die Produktion eine systemd-Unit erstellen:

[Unit]
Description=Smallstep CA
After=network.target

[Service]
User=step
ExecStart=/usr/local/bin/step-ca /etc/step-ca/config/ca.json
Restart=always
RestartSec=5
Environment=STEPPATH=/etc/step-ca

[Install]
WantedBy=multi-user.target

Provisioner

Provisioner sind Authentifizierungs-Plugins. Weitere hinzufügen mit:

step ca provisioner add <name> --type <TYP>

JWK — Interaktiv / Skriptbasiert

Der Standard-Provisioner. Clients authentifizieren sich mit einem JSON Web Token:

step ca certificate api.internal api.crt api.key

ACME — Automatisiert (Caddy, Nginx, certbot)

step ca provisioner add acme --type ACME

Beispiel mit certbot:

certbot certonly \
  --server https://ca.internal:9000/acme/acme/directory \
  --standalone \
  -d api.internal \
  --agree-tos -m admin@corp.internal

Caddy in der Caddyfile:

api.internal {
  tls {
    ca https://ca.internal:9000/acme/acme/directory
  }
  reverse_proxy localhost:8080
}

OIDC — SSO-basiert

step ca provisioner add google --type OIDC \
  --client-id <GOOGLE_CLIENT_ID> \
  --client-secret <SECRET> \
  --configuration-endpoint https://accounts.google.com/.well-known/openid-configuration

Cloud-Instanz-Identität (AWS / GCP / Azure)

step ca provisioner add aws --type AWS --aws-account 123456789012
step ca provisioner add gcp --type GCP --gcp-project mein-projekt
step ca provisioner add azure --type Azure --azure-tenant <TENANT_ID>

Kubernetes-Dienstkonten (K8sSA)

step ca provisioner add k8s --type K8sSA \
  --public-key /var/run/secrets/kubernetes.io/serviceaccount/public-key.pub

Zertifikate Ausstellen

# ECDSA P-256 (Standard) mit SANs
step ca certificate api.internal api.crt api.key \
  --san api.corp --san 10.0.1.50

# Ed25519
step ca certificate api.internal api.crt api.key --kty OKP --crv Ed25519

# RSA 4096 (Legacy-Kompatibilität)
step ca certificate api.internal api.crt api.key --kty RSA --size 4096

# Kurzlebiges Zertifikat (1 Stunde)
step ca certificate api.internal api.crt api.key --not-after 1h

SSH-Zertifikate

# SSH-Benutzerzertifikat
step ssh certificate benutzer@corp.internal id_ecdsa --provisioner google

# SSH-Host-Zertifikat
step ssh certificate --host api.internal ssh_host_ecdsa_key --provisioner aws

sshd konfigurieren:

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

Erneuerung und Widerruf

Automatische Erneuerung (—daemon)

step ca renew --daemon api.crt api.key

In einem systemd-Dienst:

ExecStartPost=/usr/local/bin/step ca renew --daemon \
  /etc/tls/dienst.crt /etc/tls/dienst.key \
  --exec "systemctl reload mein-dienst"

Widerruf

Passiver Widerruf — kurze Zertifikatslaufzeiten machen den Widerruf implizit.

Aktiver Widerruf:

step ca revoke --serial 1234567890abcdef

Datenbank-Backends und Hochverfügbarkeit

BackendStandardHAAnwendungsfall
BadgerJaNeinEinzelinstanz, Dev/kleine Teams
PostgreSQLNeinJaProduktion Multi-Replikat
MySQLNeinJaProduktion Multi-Replikat
"db": {
  "type": "postgresql",
  "dataSource": "postgresql://stepca:password@pg.internal:5432/stepca?sslmode=require"
}

Vergleich: Private-CA-Optionen

ToolACME-ServerSSH-ZertsProvisionerHAEinfachheitLizenz
step-caJa (integriert)Ja8 TypenJa (ext. DB)HochApache 2
CFSSLNeinNeinKeineJaMittelBSD
Vault PKIVia PluginVia Vault SSHVia Vault AuthJa (Raft)NiedrigBSL
EJBCAJaNeinVieleJaSehr niedrigLGPL / EE
Let’s EncryptJa (öffentlich)NeinNur ACMEN/ASehr hochN/A
mkcertNeinNeinKeineNeinSehr hochMIT

Fallstricke und Sonderfälle

Zeitversatz — step-ca lehnt CSRs ab, wenn die Client-Uhr mehr als wenige Minuten abweicht. Stelle sicher, dass NTP auf allen Knoten läuft.

Schutz des Root-CA-Schlüssels — nach step ca init den root_ca_key offline bewegen. Der Intermediate-Schlüssel ist alles, was step-ca zum Betrieb braucht.

ACME und IP-SANs — ACME HTTP-01- und DNS-01-Challenges funktionieren für Domainnamen. Für IP-Adressen-SANs das step CLI direkt verwenden.

Zertifikatstransparenz — anders als öffentliche CAs sendet step-ca keine Zertifikate an CT-Protokolle. Das ist für interne Infrastruktur erwünscht.

Verwaltung von Provisioner-Passwörtern — Passwörter in einem Secrets-Manager speichern (HashiCorp Vault, AWS Secrets Manager, Azure Key Vault). Niemals im Klartext in Skripten speichern.

Zusammenfassung

  • step-ca betreibt eine vollständige private PKI: Root-CA, Intermediate-CA und REST-API zur Zertifikatsausstellung
  • Kurzlebige Zertifikate (Standard 24h) und --daemon-Erneuerung statt CRL/OCSP verwenden
  • Der ACME-Provisioner macht step-ca zu einer internen CA, kompatibel mit Caddy, Nginx, Traefik und certbot
  • Cloud-Provisioner (AWS, GCP, Azure) ermöglichen Workload-Identity-Bootstrapping ohne geteilte Geheimnisse
  • K8sSA und cert-manager-Integration automatisieren TLS pro Pod in Kubernetes ohne Sidecars
  • SSH-Zertifikate von step-ca eliminieren die individuelle known_hosts-Verwaltung pro Server
  • Für HA das Datenbank-Backend auf PostgreSQL umstellen und mehrere Replikate hinter einem Load Balancer betreiben
  • Root-CA-Schlüssel offline halten; den Intermediate-CA-Schlüssel unabhängig rotieren, wenn er kompromittiert wurde

Verwandte Artikel