Einführung
In diesem Tutorial lernst du, wie du SSL/TLS-Zertifikate von Let's Encrypt automatisch mit cert-manager in Kubernetes holst und erneuerst. Wir nutzen die DNS-01-Challenge-Methode mit dem offiziellen Hetzner Cloud DNS-Webhook.
Die DNS-01-Challenge ist nützlich, wenn du Zertifikate brauchst und deine Server zum Beispiel nicht öffentlich über HTTP erreichbar sind. Anstatt die Domain-Inhaberschaft über HTTP nachzuweisen, erstellt cert-manager temporäre DNS-TXT-Einträge, um zu überprüfen, ob du die Domain kontrollierst.
Am Ende dieses Tutorials hast du ein automatisiertes Zertifikatsverwaltungssystem, das die Ausstellung und Erneuerung ohne manuelles Eingreifen übernimmt.
Voraussetzungen
- Ein funktionierenden Kubernetes-Cluster
kubectl, konfiguriert für den Zugriff auf deinen Cluster- Helm v3.16 oder höher (wir brauchen speziell die Unterstützung des Attributs
toYamlPretty) - Ein Hetzner Console-Konto mit DNS-Zonen, die in der Hetzner Console verwaltet werden
- Ein Hetzner Cloud API-Token mit Lese- und Schreibrechten – ich empfehle, alle deine Zonen in verschiedenen Projekten zu trennen, da ein API-Schlüssel Lese- und Schreibrechte für das Projekt repräsentiert. Stichwort hier: Least Privilege.
Wichtig: Hetzner hat zwei DNS-APIs. Die alte DNS-Console-API (dns.hetzner.com) wird im Mai 2026 eingestellt. Dieses Tutorial nutzt die neue Cloud-API (api.hetzner.cloud). Stell sicher, dass deine DNS-Zonen in der Hetzner Console verwaltet werden, nicht in der alten DNS-Console.
Schritt 1 - Installiere cert-manager
cert-manager ist ein Kubernetes-Add-on, das die Verwaltung und Ausstellung von TLS-Zertifikaten automatisiert. Füge zuerst das Jetstack-Helm-Repository hinzu und installiere cert-manager:
helm repo add jetstack https://charts.jetstack.io
helm repo updateInstalliere jetzt cert-manager mit aktivierten Custom Resource Definitions (CRDs):
helm install cert-manager jetstack/cert-manager \
--namespace cert-manager \
--create-namespace \
--set crds.enabled=trueWarte, bis alle cert-manager-Pods bereit sind, bevor du fortfährst:
kubectl get pods -n cert-managerEs sollten drei Pods den Status "running" haben: cert-manager, cert-manager-cainjector und cert-manager-webhook.
NAME READY STATUS RESTARTS AGE
cert-manager-7ff7f97d55-p6scf 1/1 Running 0 13s
cert-manager-cainjector-59bb669f8d-zddqq 1/1 Running 0 13s
cert-manager-webhook-59bbd786df-qjq8t 1/1 Running 0 13sSchritt 2 - Installiere den Hetzner Cloud DNS Webhook
Der Webhook erweitert cert-manager, um DNS-01-Challenges mithilfe der Hetzner Cloud DNS-API zu lösen. Du kannst ihn aus dem offiziellen Helm-Repository oder direkt aus dem Git-Repository installieren.
Schritt 2.1 - Option A: Installation aus dem Helm-Repository (empfohlen)
helm repo add hcloud https://charts.hetzner.cloud
helm repo update
helm install cert-manager-webhook-hetzner hcloud/cert-manager-webhook-hetzner \
--namespace cert-managerSchritt 2.2 - Option B: Installation aus dem Git-Repository
Wenn du lieber aus dem Quellcode installieren möchtest oder das Chart ändern musst:
git clone https://github.com/hetzner/cert-manager-webhook-hetzner.git
cd cert-manager-webhook-hetzner
helm install cert-manager-webhook-hetzner ./chart \
--namespace cert-managerSchritt 3 - API-Token-Geheimnis erstellen
Der Webhook braucht dein Hetzner Cloud API-Token, um DNS-Einträge zu erstellen. Speichere es als Kubernetes-Geheimnis:
Erstelle eine Datei namens hetzner-secret.yaml:
apiVersion: v1
kind: Secret
metadata:
name: hetzner-secret
namespace: cert-manager
type: Opaque
stringData:
api-token: "<your-hetzner-cloud-api-token>"Ersetze <your-hetzner-cloud-api-token> durch deinen tatsächlichen Token und wende ihn dann an:
kubectl apply -f hetzner-secret.yamlSicherheitstipp: Lösche die YAML-Datei nach dem Anwenden, da sie sensible Anmeldedaten enthält.
Schritt 4 - Erstelle einen ClusterIssuer
Ein ClusterIssuer ist eine clusterweite Ressource, die festlegt, wie Zertifikate bezogen werden sollen. Erstelle eine Datei namens "clusterissuer-letsencrypt.yaml":
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: mail@example.com
privateKeySecretRef:
name: letsencrypt-account-key
solvers:
- dns01:
webhook:
groupName: acme.hetzner.com
solverName: hetzner
config:
tokenSecretKeyRef:
name: hetzner-secret
key: api-tokenDer cert-manager erwartet bei einem ACME Issuer/ClusterIssuer weiterhin spec.acme.email. Benachrichtigungen über den Ablauf hat Let's Encrypt seit 4. Juni 2025 eingestellt. Siehe auch https://letsencrypt.org/2025/01/22/ending-expiration-emails.
Wende den ClusterIssuer an:
kubectl apply -f clusterissuer-letsencrypt.yamlSchritt 4.1 - Erstelle einen Staging-ClusterIssuer (optional)
Verwende zum Testen die Staging-Umgebung von Let's Encrypt, um Rate-Limit Beschränkungen zu vermeiden. Bearbeite dazu in clusterissuer-letsencrypt.yaml einfach:
| Production-Wert | Staging-Wert | |
|---|---|---|
| metadata.name | letsencrypt | letsencrypt-staging |
| spec.acme.server | https://acme-v02.api.letsencrypt.org/directory | https://acme-staging-v02.api.letsencrypt.org/directory |
| spec.acme.privateKeySecretRef.name | letsencrypt-account-key | letsencrypt-staging-account-key |
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
spec:
acme:
server: https://acme-staging-v02.api.letsencrypt.org/directory
email: mail@example.com
privateKeySecretRef:
name: letsencrypt-staging-account-key
solvers:
- dns01:
webhook:
groupName: acme.hetzner.com
solverName: hetzner
config:
tokenSecretKeyRef:
name: hetzner-secret
key: api-tokenStaging-Zertifikate werden von Browsern nicht als vertrauenswürdig eingestuft, ermöglichen es dir aber, den gesamten Ablauf zu testen, ohne dass du auf dem Produktiv-System von LetsEncrypt "gesperrt bzw. ausgebremst" wirst.
Schritt 5 - Zertifikat anfordern
Jetzt kannst du Zertifikate anfordern. Erstelle eine Datei namens "certificate.yaml":
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: example-com-tls
namespace: default
spec:
secretName: example-com-tls
issuerRef:
name: letsencrypt # oder letsencrypt-staging
kind: ClusterIssuer
dnsNames:
- <example.com>
- "*.<example.com>"Ersetze <example.com> durch deine tatsächliche Domain. Der Platzhaltereintrag (*.<example.com>) ist optional, zeigt aber einen der wichtigsten Vorteile von DNS-01-Challenges.
Wende die Zertifikatsanforderung an:
kubectl apply -f certificate.yamlcert-manager erstellt jetzt einen DNS-TXT-Eintrag, wartet, bis Let's Encrypt ihn überprüft hat, holt das Zertifikat und speichert es im angegebenen Secret.
Üblich wäre auch die Nutzung einer "annotation" auf einem ingress object: cert-manager.io/cluster-issuer: letsencrypt
Schritt 6 - Überprüfen
Überprüfe den Status deiner Ressourcen:
# Status von ClusterIssuer überprüfen
kubectl get clusterissuer
# Status des Zertifikats überprüfen
kubectl get certificates -A
# Aktive Herausforderungen überprüfen (sollten nach Abschluss leer sein)
kubectl get challenges -AEin erfolgreich ausgestelltes Zertifikat zeigt "Ready: True" an (kubectl get certificates -A).
Ergebnis
Du hast die automatische SSL/TLS-Zertifikatsverwaltung mit cert-manager und dem Hetzner Cloud DNS-Webhook erfolgreich eingerichtet. Deine Zertifikate werden jetzt automatisch vor Ablauf erneuert.
Nächste Schritte:
- Konfiguriere deine Ingress-Ressourcen für die Verwendung der Zertifikate
- Richte Monitoring und Benachrichtigungen für den Ablauf von Zertifikaten ein
- Viel Spaß mit deinen sicheren TLS-Verbindungen
Hilfreiche Links:
- Offizielles Hetzner-Webhook-Repository
- Hetzner-DNS-Migrationsdokumentation
- cert-manager-Dokumentation
- Hetzner Cloud API-Referenz