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 Hostnamen —
postgres.internal,api.corpoder 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-Zertifikatsecrets/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
| Backend | Standard | HA | Anwendungsfall |
|---|---|---|---|
| Badger | Ja | Nein | Einzelinstanz, Dev/kleine Teams |
| PostgreSQL | Nein | Ja | Produktion Multi-Replikat |
| MySQL | Nein | Ja | Produktion Multi-Replikat |
"db": {
"type": "postgresql",
"dataSource": "postgresql://stepca:password@pg.internal:5432/stepca?sslmode=require"
}
Vergleich: Private-CA-Optionen
| Tool | ACME-Server | SSH-Zerts | Provisioner | HA | Einfachheit | Lizenz |
|---|---|---|---|---|---|---|
| step-ca | Ja (integriert) | Ja | 8 Typen | Ja (ext. DB) | Hoch | Apache 2 |
| CFSSL | Nein | Nein | Keine | Ja | Mittel | BSD |
| Vault PKI | Via Plugin | Via Vault SSH | Via Vault Auth | Ja (Raft) | Niedrig | BSL |
| EJBCA | Ja | Nein | Viele | Ja | Sehr niedrig | LGPL / EE |
| Let’s Encrypt | Ja (öffentlich) | Nein | Nur ACME | N/A | Sehr hoch | N/A |
| mkcert | Nein | Nein | Keine | Nein | Sehr hoch | MIT |
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