Zertifikat in den Java-Truststore (cacerts) importieren

Spricht eine Java-Anwendung mit einem Server, dessen CA sie nicht kennt, kommt „PKIX path building failed“. Die Lösung ist, die CA in den Truststore aufzunehmen. Dabei gibt es einen kurzen und einen dauerhaften Weg.

Wo liegt cacerts?

Das Standardkennwort ist changeit. Welche Datei eine laufende Anwendung wirklich benutzt, zeigt -Djavax.net.debug=ssl:trustmanager.

Welches Zertifikat importieren?

Importiere die Root-CA (oder die ausstellende Zwischen-CA) deiner Firma, nicht das Serverzertifikat. Ein Serverzertifikat wird bei jedem Wechsel ungültig, die CA bleibt jahrelang. Die CA bekommst du von der IT oder aus der Kette des Servers. Der SSL-Check zeigt alle Zertifikate und lädt sie als PEM herunter.

Der keytool-Befehl

# Java 9 und neuer
keytool -importcert -cacerts -alias firmen-root -file firmen-root.crt -storepass changeit -noprompt

# Java 8
keytool -importcert -keystore "$JAVA_HOME/jre/lib/security/cacerts" \
  -alias firmen-root -file firmen-root.crt -storepass changeit -noprompt

# prüfen und wieder entfernen
keytool -list -cacerts -alias firmen-root -storepass changeit
keytool -delete -cacerts -alias firmen-root -storepass changeit

Die Datei darf PEM oder DER sein. Unter Linux und macOS brauchst du meist sudo, weil cacerts zum JDK gehört. Danach die Anwendung neu starten, Java liest den Truststore nur beim Start.

Der dauerhafte Weg unter Linux

Ein JDK-Update ersetzt cacerts, deine Änderung ist dann weg. Die Pakete von Debian, Ubuntu, RHEL und Fedora erzeugen cacerts deshalb aus dem Zertifikatsspeicher des Systems. Dort hinzufügen und es gilt für Java, curl, Python und alle anderen gleichzeitig:

# Debian, Ubuntu (Endung .crt, Format PEM)
sudo cp firmen-root.crt /usr/local/share/ca-certificates/
sudo update-ca-certificates

# RHEL, Rocky, Alma, Fedora
sudo cp firmen-root.crt /etc/pki/ca-trust/source/anchors/
sudo update-ca-trust

Das funktioniert für die Java-Pakete der Distribution. Ein von Hand entpacktes JDK (etwa unter /opt) bringt ein eigenes cacerts mit. Dann entweder dieses mit keytool ändern oder per -Djavax.net.ssl.trustStore=/etc/ssl/certs/java/cacerts (Debian) bzw. /etc/pki/ca-trust/extracted/java/cacerts (RHEL) auf den Systemspeicher zeigen.

In Docker-Images

Die offiziellen eclipse-temurin-Images können CAs beim Start übernehmen. Leg die Zertifikate nach /certificates und setz USE_SYSTEM_CA_CERTS=1:

docker run -e USE_SYSTEM_CA_CERTS=1 -v ./ca:/certificates:ro meine-app

# oder fest im Image
FROM eclipse-temurin:21-jre
COPY firmen-root.crt /usr/local/share/ca-certificates/
RUN update-ca-certificates

Bei anderen Basis-Images geht der keytool-Befehl von oben im Dockerfile.

Eigener Truststore statt cacerts

Willst du das JDK nicht anfassen, gib der Anwendung einen eigenen Truststore. Wichtig: Er ersetzt cacerts, enthält also nur, was du hineinlegst. Am einfachsten kopierst du cacerts und ergänzt die CA:

cp "$JAVA_HOME/lib/security/cacerts" truststore.p12
keytool -importcert -keystore truststore.p12 -storepass changeit -alias firmen-root -file firmen-root.crt -noprompt
java -Djavax.net.ssl.trustStore=truststore.p12 -Djavax.net.ssl.trustStorePassword=changeit -jar app.jar

Einen Truststore nur aus bestimmten CAs baust du im Java-Keystore-Helfer unter „PEM & CA-Antwort“: CA-Zertifikate einfügen, als Truststore speichern, fertig.

FAQ

Muss ich das Kennwort changeit ändern?

Für cacerts nicht unbedingt. Es schützt nur vor Änderungen, nicht vor dem Lesen, und die Inhalte sind öffentliche Zertifikate. Wichtig ist, dass nur Administratoren die Datei schreiben dürfen.

Was bedeutet „Certificate was added to keystore“ ohne Wirkung?

Meist wurde ein anderes cacerts geändert als das, das die Anwendung nutzt, etwa bei mehreren installierten JDKs. Prüf die Datei mit -Djavax.net.debug=ssl:trustmanager.

Gilt das auch für Tomcat, Jenkins oder Maven?

Ja, sie alle nutzen den Truststore der Java-Laufzeit, mit der sie gestartet werden. Bei Maven ist das die JVM aus JAVA_HOME bzw. MAVEN_OPTS.

Kann ich die Firmen-CA unter Windows aus dem System übernehmen?

Ja, mit -Djavax.net.ssl.trustStoreType=Windows-ROOT liest Java den Windows-Zertifikatsspeicher. Dann ist kein Import nötig.