Typische Meldungen
curl: (60) SSL certificate problem: unable to get local issuer certificate git: SSL certificate problem: unable to get local issuer certificate Python: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate Node: Error: unable to get local issuer certificate (UNABLE_TO_GET_ISSUER_CERT_LOCALLY) Java: PKIX path building failed: unable to find valid certification path to requested target
Alle bedeuten dasselbe: Der Client kann vom Server-Zertifikat aus keine Kette bis zu einer Root-CA bilden, der er vertraut.
Warum es im Browser trotzdem funktioniert
Browser sind nachsichtig. Fehlt ein Zwischenzertifikat, laden sie es über die AIA-Adresse im Zertifikat nach oder nehmen es aus ihrem Zwischenspeicher, weil sie es auf einer anderen Seite schon gesehen haben. curl, Python, Java, Git und die meisten Apps machen das nicht. Deshalb gilt: Funktioniert eine Seite im Browser, ist die Kette noch lange nicht vollständig.
Drei mögliche Ursachen
1. Der Server schickt die Kette nicht vollständig (häufigste Ursache)
Eingerichtet wurde nur das Server-Zertifikat, ohne Zwischenzertifikat. Prüfen lässt sich das mit dem SSL-Check oder auf der Kommandozeile:
openssl s_client -connect www.beispiel.de:443 -servername www.beispiel.de -showcerts </dev/null
Steht in der Ausgabe nur ein Zertifikat (0 s:CN=www.beispiel.de) und dazu verify error:num=20:unable to get local issuer certificate, fehlt das Zwischenzertifikat.
2. Dem Client fehlt die Root-CA
Alte Docker-Images ohne das Paket ca-certificates, eine veraltete Java-Installation oder ein altes certifi-Paket in Python kennen neuere Root-CAs nicht.
3. Eine Firewall bricht TLS auf oder es ist eine interne CA
Viele Firmen-Proxys und Firewalls ersetzen Zertifikate durch eigene, die von einer internen CA stammen. Browser auf Firmenrechnern kennen diese CA über die Gruppenrichtlinie, Docker-Container, Python und Java aber nicht. Dasselbe gilt für Server mit Zertifikaten einer eigenen Firmen-CA.
Lösung auf dem Server: vollständige Kette ausliefern
# nginx: Zertifikat + Zwischenzertifikat in einer Datei ssl_certificate /etc/ssl/beispiel/fullchain.pem; ssl_certificate_key /etc/ssl/beispiel/server.key; # Apache ab 2.4.8: die Kette gehört mit in SSLCertificateFile SSLCertificateFile /etc/ssl/beispiel/fullchain.pem SSLCertificateKeyFile /etc/ssl/beispiel/server.key # Let's Encrypt: fullchain.pem verwenden, nicht cert.pem
Unter Windows bzw. IIS muss das Zwischenzertifikat im Speicher „Zwischenzertifizierungsstellen“ des Computers liegen. Am einfachsten importierst du eine PFX, die die Kette enthält. Fehlt dir das Zwischenzertifikat, ergänzt der Zertifikat-Konverter die Kette automatisch über AIA. Der SSL-Check übergibt sie mit „Kette im Konverter ergänzen“ direkt dorthin.
Lösung auf dem Client
# Debian/Ubuntu: Root-CAs aktualisieren bzw. eigene CA hinzufügen apt install ca-certificates cp firmen-root.crt /usr/local/share/ca-certificates/ && update-ca-certificates # Python (requests) pip install --upgrade certifi export REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt # Java ab Version 9 keytool -importcert -cacerts -alias firmen-root -file firmen-root.crt
Finger weg von curl -k, verify=False oder NODE_TLS_REJECT_UNAUTHORIZED=0 als Dauerlösung. Damit ist die Verbindung zwar verschlüsselt, aber nicht mehr gegen Angreifer geschützt.
FAQ
Muss ich die Root-CA mit ausliefern?
Nein. Der Server schickt Server-Zertifikat und Zwischenzertifikate. Die Root-CA muss beim Client bereits vorhanden sein, eine mitgeschickte Root wird ignoriert.
Wie finde ich heraus, ob Server oder Client schuld ist?
Prüf den Server mit dem SSL-Check. Meldet er eine vollständige Kette, liegt es am Client (fehlende Root oder Firmen-Proxy). Meldet er ein fehlendes Zwischenzertifikat, muss der Server korrigiert werden.
Warum tritt der Fehler nur in Docker auf?
Schlanke Images wie alpine oder debian-slim enthalten oft keine Root-CAs. Installier im Dockerfile das Paket ca-certificates oder kopier die Firmen-CA hinein und führ update-ca-certificates aus.